代码批量prettier格式化
parent
38db7196c7
commit
6995e5e280
|
@ -30,12 +30,7 @@ export function getThemeColors(color?: string) {
|
|||
return [...lightColors, ...modeColors];
|
||||
}
|
||||
|
||||
export function generateColors({
|
||||
color = primaryColor,
|
||||
mixLighten,
|
||||
mixDarken,
|
||||
tinycolor,
|
||||
}: GenerateColorsParams) {
|
||||
export function generateColors({ color = primaryColor, mixLighten, mixDarken, tinycolor }: GenerateColorsParams) {
|
||||
const arr = new Array(19).fill(0);
|
||||
const lightens = arr.map((_t, i) => {
|
||||
return mixLighten(color, i / 5);
|
||||
|
@ -68,12 +63,5 @@ export function generateColors({
|
|||
.toHexString();
|
||||
})
|
||||
.filter((item) => item !== '#000000');
|
||||
return [
|
||||
...lightens,
|
||||
...darkens,
|
||||
...alphaColors,
|
||||
...shortAlphaColors,
|
||||
...tinycolorDarkens,
|
||||
...tinycolorLightens,
|
||||
].filter((item) => !item.includes('-'));
|
||||
return [...lightens, ...darkens, ...alphaColors, ...shortAlphaColors, ...tinycolorDarkens, ...tinycolorLightens].filter((item) => !item.includes('-'));
|
||||
}
|
||||
|
|
|
@ -51,21 +51,14 @@ async function generateIcon() {
|
|||
if (data) {
|
||||
const { prefix } = data;
|
||||
const isLocal = useType === 'local';
|
||||
const icons = Object.keys(data.icons).map(
|
||||
(item) => `${isLocal ? prefix + ':' : ''}${item}`
|
||||
);
|
||||
const icons = Object.keys(data.icons).map((item) => `${isLocal ? prefix + ':' : ''}${item}`);
|
||||
|
||||
await fs.writeFileSync(
|
||||
path.join(output, `icons.data.ts`),
|
||||
`export default ${isLocal ? JSON.stringify(icons) : JSON.stringify({ prefix, icons })}`
|
||||
);
|
||||
await fs.writeFileSync(path.join(output, `icons.data.ts`), `export default ${isLocal ? JSON.stringify(icons) : JSON.stringify({ prefix, icons })}`);
|
||||
prefixSet.push(prefix);
|
||||
}
|
||||
}
|
||||
fs.emptyDir(path.join(process.cwd(), 'node_modules/.vite'));
|
||||
console.log(
|
||||
`✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`
|
||||
);
|
||||
console.log(`✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,5 @@
|
|||
* @param env
|
||||
*/
|
||||
export const getConfigFileName = (env: Record<string, any>) => {
|
||||
return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || '__APP'}__CONF__`
|
||||
.toUpperCase()
|
||||
.replace(/\s/g, '');
|
||||
return `__PRODUCTION__${env.VITE_GLOB_APP_SHORT_NAME || '__APP'}__CONF__`.toUpperCase().replace(/\s/g, '');
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ export const runBuild = async () => {
|
|||
|
||||
// Generate configuration file
|
||||
if (!argvList.includes('disabled-config')) {
|
||||
runBuildConfig();
|
||||
runBuildConfig();
|
||||
}
|
||||
|
||||
console.log(`✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - build successfully!');
|
||||
|
|
|
@ -3,60 +3,60 @@ import path from 'path';
|
|||
import dotenv from 'dotenv';
|
||||
|
||||
export function isDevFn(mode: string): boolean {
|
||||
return mode === 'development';
|
||||
return mode === 'development';
|
||||
}
|
||||
|
||||
export function isProdFn(mode: string): boolean {
|
||||
return mode === 'production';
|
||||
return mode === 'production';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to generate package preview
|
||||
*/
|
||||
export function isReportMode(): boolean {
|
||||
return process.env.REPORT === 'true';
|
||||
return process.env.REPORT === 'true';
|
||||
}
|
||||
|
||||
// Read all environment variable configuration files to process.env
|
||||
export function wrapperEnv(envConf: Recordable): ViteEnv {
|
||||
const ret: any = {};
|
||||
const ret: any = {};
|
||||
|
||||
for (const envName of Object.keys(envConf)) {
|
||||
let realName = envConf[envName].replace(/\\n/g, '\n');
|
||||
realName = realName === 'true' ? true : realName === 'false' ? false : realName;
|
||||
for (const envName of Object.keys(envConf)) {
|
||||
let realName = envConf[envName].replace(/\\n/g, '\n');
|
||||
realName = realName === 'true' ? true : realName === 'false' ? false : realName;
|
||||
|
||||
if (envName === 'VITE_PORT') {
|
||||
realName = Number(realName);
|
||||
}
|
||||
if (envName === 'VITE_PROXY' && realName) {
|
||||
try {
|
||||
realName = JSON.parse(realName.replace(/'/g, '"'));
|
||||
} catch (error) {
|
||||
realName = '';
|
||||
}
|
||||
}
|
||||
ret[envName] = realName;
|
||||
if (typeof realName === 'string') {
|
||||
process.env[envName] = realName;
|
||||
} else if (typeof realName === 'object') {
|
||||
process.env[envName] = JSON.stringify(realName);
|
||||
}
|
||||
if (envName === 'VITE_PORT') {
|
||||
realName = Number(realName);
|
||||
}
|
||||
return ret;
|
||||
if (envName === 'VITE_PROXY' && realName) {
|
||||
try {
|
||||
realName = JSON.parse(realName.replace(/'/g, '"'));
|
||||
} catch (error) {
|
||||
realName = '';
|
||||
}
|
||||
}
|
||||
ret[envName] = realName;
|
||||
if (typeof realName === 'string') {
|
||||
process.env[envName] = realName;
|
||||
} else if (typeof realName === 'object') {
|
||||
process.env[envName] = JSON.stringify(realName);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前环境下生效的配置文件名
|
||||
*/
|
||||
function getConfFiles() {
|
||||
const script = process.env.npm_lifecycle_script;
|
||||
const reg = new RegExp('--mode ([a-z_\\d]+)');
|
||||
const result = reg.exec(script as string) as any;
|
||||
if (result) {
|
||||
const mode = result[1] as string;
|
||||
return ['.env', `.env.${mode}`];
|
||||
}
|
||||
return ['.env', '.env.production'];
|
||||
const script = process.env.npm_lifecycle_script;
|
||||
const reg = new RegExp('--mode ([a-z_\\d]+)');
|
||||
const result = reg.exec(script as string) as any;
|
||||
if (result) {
|
||||
const mode = result[1] as string;
|
||||
return ['.env', `.env.${mode}`];
|
||||
}
|
||||
return ['.env', '.env.production'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,22 +65,22 @@ function getConfFiles() {
|
|||
* @param confFiles ext
|
||||
*/
|
||||
export function getEnvConfig(match = 'VITE_GLOB_', confFiles = getConfFiles()) {
|
||||
let envConfig = {};
|
||||
confFiles.forEach((item) => {
|
||||
try {
|
||||
const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item)));
|
||||
envConfig = {...envConfig, ...env};
|
||||
} catch (e) {
|
||||
console.error(`Error in parsing ${item}`, e);
|
||||
}
|
||||
});
|
||||
const reg = new RegExp(`^(${match})`);
|
||||
Object.keys(envConfig).forEach((key) => {
|
||||
if (!reg.test(key)) {
|
||||
Reflect.deleteProperty(envConfig, key);
|
||||
}
|
||||
});
|
||||
return envConfig;
|
||||
let envConfig = {};
|
||||
confFiles.forEach((item) => {
|
||||
try {
|
||||
const env = dotenv.parse(fs.readFileSync(path.resolve(process.cwd(), item)));
|
||||
envConfig = { ...envConfig, ...env };
|
||||
} catch (e) {
|
||||
console.error(`Error in parsing ${item}`, e);
|
||||
}
|
||||
});
|
||||
const reg = new RegExp(`^(${match})`);
|
||||
Object.keys(envConfig).forEach((key) => {
|
||||
if (!reg.test(key)) {
|
||||
Reflect.deleteProperty(envConfig, key);
|
||||
}
|
||||
});
|
||||
return envConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,5 +88,5 @@ export function getEnvConfig(match = 'VITE_GLOB_', confFiles = getConfFiles()) {
|
|||
* @param dir file path
|
||||
*/
|
||||
export function getRootPath(...dir: string[]) {
|
||||
return path.resolve(process.cwd(), ...dir);
|
||||
return path.resolve(process.cwd(), ...dir);
|
||||
}
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
import type { Plugin } from 'vite';
|
||||
import compressPlugin from 'vite-plugin-compression';
|
||||
|
||||
export function configCompressPlugin(
|
||||
compress: 'gzip' | 'brotli' | 'none',
|
||||
deleteOriginFile = false
|
||||
): Plugin | Plugin[] {
|
||||
export function configCompressPlugin(compress: 'gzip' | 'brotli' | 'none', deleteOriginFile = false): Plugin | Plugin[] {
|
||||
const compressList = compress.split(',');
|
||||
|
||||
const plugins: Plugin[] = [];
|
||||
|
|
|
@ -25,7 +25,7 @@ export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
|
|||
},
|
||||
// Embed the generated app.config.js file
|
||||
tags: isBuild
|
||||
? [
|
||||
? [
|
||||
{
|
||||
tag: 'script',
|
||||
attrs: {
|
||||
|
@ -33,7 +33,7 @@ export function configHtmlPlugin(env: ViteEnv, isBuild: boolean) {
|
|||
},
|
||||
},
|
||||
]
|
||||
: [],
|
||||
: [],
|
||||
},
|
||||
});
|
||||
return htmlPlugin;
|
||||
|
|
|
@ -15,74 +15,66 @@ import { configThemePlugin } from './theme';
|
|||
import { configImageminPlugin } from './imagemin';
|
||||
import { configSvgIconsPlugin } from './svgSprite';
|
||||
import { configHmrPlugin } from './hmr';
|
||||
import OptimizationPersist from 'vite-plugin-optimize-persist'
|
||||
import PkgConfig from 'vite-plugin-package-config'
|
||||
import OptimizationPersist from 'vite-plugin-optimize-persist';
|
||||
import PkgConfig from 'vite-plugin-package-config';
|
||||
|
||||
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
|
||||
const {
|
||||
VITE_USE_IMAGEMIN,
|
||||
VITE_USE_MOCK,
|
||||
VITE_LEGACY,
|
||||
VITE_BUILD_COMPRESS,
|
||||
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE,
|
||||
} = viteEnv;
|
||||
const { VITE_USE_IMAGEMIN, VITE_USE_MOCK, VITE_LEGACY, VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE } = viteEnv;
|
||||
|
||||
const vitePlugins: (Plugin | Plugin[])[] = [
|
||||
// have to
|
||||
vue(),
|
||||
// have to
|
||||
vueJsx(),
|
||||
// support name
|
||||
vueSetupExtend(),
|
||||
];
|
||||
const vitePlugins: (Plugin | Plugin[])[] = [
|
||||
// have to
|
||||
vue(),
|
||||
// have to
|
||||
vueJsx(),
|
||||
// support name
|
||||
vueSetupExtend(),
|
||||
];
|
||||
|
||||
// vite-plugin-windicss
|
||||
vitePlugins.push(windiCSS());
|
||||
// vite-plugin-windicss
|
||||
vitePlugins.push(windiCSS());
|
||||
|
||||
// TODO
|
||||
!isBuild && vitePlugins.push(configHmrPlugin());
|
||||
// TODO
|
||||
!isBuild && vitePlugins.push(configHmrPlugin());
|
||||
|
||||
// @vitejs/plugin-legacy
|
||||
VITE_LEGACY && isBuild && vitePlugins.push(legacy());
|
||||
// @vitejs/plugin-legacy
|
||||
VITE_LEGACY && isBuild && vitePlugins.push(legacy());
|
||||
|
||||
// vite-plugin-html
|
||||
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
|
||||
// vite-plugin-html
|
||||
vitePlugins.push(configHtmlPlugin(viteEnv, isBuild));
|
||||
|
||||
// vite-plugin-svg-icons
|
||||
vitePlugins.push(configSvgIconsPlugin(isBuild));
|
||||
// vite-plugin-svg-icons
|
||||
vitePlugins.push(configSvgIconsPlugin(isBuild));
|
||||
|
||||
// vite-plugin-mock
|
||||
VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild));
|
||||
// vite-plugin-mock
|
||||
VITE_USE_MOCK && vitePlugins.push(configMockPlugin(isBuild));
|
||||
|
||||
// vite-plugin-purge-icons
|
||||
vitePlugins.push(purgeIcons());
|
||||
// vite-plugin-purge-icons
|
||||
vitePlugins.push(purgeIcons());
|
||||
|
||||
// vite-plugin-style-import
|
||||
vitePlugins.push(configStyleImportPlugin(isBuild));
|
||||
// vite-plugin-style-import
|
||||
vitePlugins.push(configStyleImportPlugin(isBuild));
|
||||
|
||||
// rollup-plugin-visualizer
|
||||
vitePlugins.push(configVisualizerConfig());
|
||||
// rollup-plugin-visualizer
|
||||
vitePlugins.push(configVisualizerConfig());
|
||||
|
||||
//vite-plugin-theme
|
||||
vitePlugins.push(configThemePlugin(isBuild));
|
||||
//vite-plugin-theme
|
||||
vitePlugins.push(configThemePlugin(isBuild));
|
||||
|
||||
// The following plugins only work in the production environment
|
||||
if (isBuild) {
|
||||
//vite-plugin-imagemin
|
||||
VITE_USE_IMAGEMIN && vitePlugins.push(configImageminPlugin());
|
||||
// The following plugins only work in the production environment
|
||||
if (isBuild) {
|
||||
//vite-plugin-imagemin
|
||||
VITE_USE_IMAGEMIN && vitePlugins.push(configImageminPlugin());
|
||||
|
||||
// rollup-plugin-gzip
|
||||
vitePlugins.push(
|
||||
configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE),
|
||||
);
|
||||
// rollup-plugin-gzip
|
||||
vitePlugins.push(configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE));
|
||||
|
||||
// vite-plugin-pwa
|
||||
vitePlugins.push(configPwaConfig(viteEnv));
|
||||
}
|
||||
// vite-plugin-pwa
|
||||
vitePlugins.push(configPwaConfig(viteEnv));
|
||||
}
|
||||
|
||||
//vite-plugin-theme【解决vite首次打开界面加载慢问题】
|
||||
vitePlugins.push(PkgConfig());
|
||||
vitePlugins.push(OptimizationPersist());
|
||||
//vite-plugin-theme【解决vite首次打开界面加载慢问题】
|
||||
vitePlugins.push(PkgConfig());
|
||||
vitePlugins.push(OptimizationPersist());
|
||||
|
||||
return vitePlugins;
|
||||
return vitePlugins;
|
||||
}
|
||||
|
|
|
@ -4,86 +4,80 @@
|
|||
*/
|
||||
import type { Plugin } from 'vite';
|
||||
import path from 'path';
|
||||
import {
|
||||
viteThemePlugin,
|
||||
antdDarkThemePlugin,
|
||||
mixLighten,
|
||||
mixDarken,
|
||||
tinycolor,
|
||||
} from 'vite-plugin-theme';
|
||||
import { viteThemePlugin, antdDarkThemePlugin, mixLighten, mixDarken, tinycolor } from 'vite-plugin-theme';
|
||||
import { getThemeColors, generateColors } from '../../config/themeConfig';
|
||||
import { generateModifyVars } from '../../generate/generateModifyVars';
|
||||
|
||||
export function configThemePlugin(isBuild: boolean): Plugin[] {
|
||||
const colors = generateColors({
|
||||
mixDarken,
|
||||
mixLighten,
|
||||
tinycolor,
|
||||
});
|
||||
const plugin = [
|
||||
viteThemePlugin({
|
||||
resolveSelector: (s) => {
|
||||
s = s.trim();
|
||||
switch (s) {
|
||||
case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon':
|
||||
return '.ant-steps-item-icon > .ant-steps-icon';
|
||||
case '.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)':
|
||||
case '.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover':
|
||||
case '.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active':
|
||||
return s;
|
||||
case '.ant-steps-item-icon > .ant-steps-icon':
|
||||
return s;
|
||||
case '.ant-select-item-option-selected:not(.ant-select-item-option-disabled)':
|
||||
return s;
|
||||
default:
|
||||
if (s.indexOf('.ant-btn') >= -1) {
|
||||
// 按钮被重新定制过,需要过滤掉class防止覆盖
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return s.startsWith('[data-theme') ? s : `[data-theme] ${s}`;
|
||||
},
|
||||
colorVariables: [...getThemeColors(), ...colors],
|
||||
}),
|
||||
antdDarkThemePlugin({
|
||||
preloadFiles: [
|
||||
path.resolve(process.cwd(), 'node_modules/ant-design-vue/dist/antd.less'),
|
||||
//path.resolve(process.cwd(), 'node_modules/ant-design-vue/dist/antd.dark.less'),
|
||||
path.resolve(process.cwd(), 'src/design/index.less'),
|
||||
],
|
||||
filter: (id) => (isBuild ? !id.endsWith('antd.less') : true),
|
||||
// extractCss: false,
|
||||
darkModifyVars: {
|
||||
...generateModifyVars(true),
|
||||
'text-color': '#c9d1d9',
|
||||
'primary-1': 'rgb(255 255 255 / 8%)',
|
||||
'text-color-base': '#c9d1d9',
|
||||
'component-background': '#151515',
|
||||
'heading-color': 'rgb(255 255 255 / 65%)',
|
||||
// black: '#0e1117',
|
||||
// #8b949e
|
||||
'text-color-secondary': '#8b949e',
|
||||
'border-color-base': '#303030',
|
||||
// 'border-color-split': '#30363d',
|
||||
'item-active-bg': '#111b26',
|
||||
'app-content-background': '#1e1e1e',
|
||||
'tree-node-selected-bg': '#11263c',
|
||||
const colors = generateColors({
|
||||
mixDarken,
|
||||
mixLighten,
|
||||
tinycolor,
|
||||
});
|
||||
const plugin = [
|
||||
viteThemePlugin({
|
||||
resolveSelector: (s) => {
|
||||
s = s.trim();
|
||||
switch (s) {
|
||||
case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon':
|
||||
return '.ant-steps-item-icon > .ant-steps-icon';
|
||||
case '.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)':
|
||||
case '.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover':
|
||||
case '.ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active':
|
||||
return s;
|
||||
case '.ant-steps-item-icon > .ant-steps-icon':
|
||||
return s;
|
||||
case '.ant-select-item-option-selected:not(.ant-select-item-option-disabled)':
|
||||
return s;
|
||||
default:
|
||||
if (s.indexOf('.ant-btn') >= -1) {
|
||||
// 按钮被重新定制过,需要过滤掉class防止覆盖
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return s.startsWith('[data-theme') ? s : `[data-theme] ${s}`;
|
||||
},
|
||||
colorVariables: [...getThemeColors(), ...colors],
|
||||
}),
|
||||
antdDarkThemePlugin({
|
||||
preloadFiles: [
|
||||
path.resolve(process.cwd(), 'node_modules/ant-design-vue/dist/antd.less'),
|
||||
//path.resolve(process.cwd(), 'node_modules/ant-design-vue/dist/antd.dark.less'),
|
||||
path.resolve(process.cwd(), 'src/design/index.less'),
|
||||
],
|
||||
filter: (id) => (isBuild ? !id.endsWith('antd.less') : true),
|
||||
// extractCss: false,
|
||||
darkModifyVars: {
|
||||
...generateModifyVars(true),
|
||||
'text-color': '#c9d1d9',
|
||||
'primary-1': 'rgb(255 255 255 / 8%)',
|
||||
'text-color-base': '#c9d1d9',
|
||||
'component-background': '#151515',
|
||||
'heading-color': 'rgb(255 255 255 / 65%)',
|
||||
// black: '#0e1117',
|
||||
// #8b949e
|
||||
'text-color-secondary': '#8b949e',
|
||||
'border-color-base': '#303030',
|
||||
// 'border-color-split': '#30363d',
|
||||
'item-active-bg': '#111b26',
|
||||
'app-content-background': '#1e1e1e',
|
||||
'tree-node-selected-bg': '#11263c',
|
||||
|
||||
'alert-success-border-color': '#274916',
|
||||
'alert-success-bg-color': '#162312',
|
||||
'alert-success-icon-color': '#49aa19',
|
||||
'alert-info-border-color': '#153450',
|
||||
'alert-info-bg-color': '#111b26',
|
||||
'alert-info-icon-color': '#177ddc',
|
||||
'alert-warning-border-color': '#594214',
|
||||
'alert-warning-bg-color': '#2b2111',
|
||||
'alert-warning-icon-color': '#d89614',
|
||||
'alert-error-border-color': '#58181c',
|
||||
'alert-error-bg-color': '#2a1215',
|
||||
'alert-error-icon-color': '#a61d24',
|
||||
},
|
||||
}),
|
||||
];
|
||||
'alert-success-border-color': '#274916',
|
||||
'alert-success-bg-color': '#162312',
|
||||
'alert-success-icon-color': '#49aa19',
|
||||
'alert-info-border-color': '#153450',
|
||||
'alert-info-bg-color': '#111b26',
|
||||
'alert-info-icon-color': '#177ddc',
|
||||
'alert-warning-border-color': '#594214',
|
||||
'alert-warning-bg-color': '#2b2111',
|
||||
'alert-warning-icon-color': '#d89614',
|
||||
'alert-error-border-color': '#58181c',
|
||||
'alert-error-bg-color': '#2a1215',
|
||||
'alert-error-icon-color': '#a61d24',
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
return plugin as unknown as Plugin[];
|
||||
return plugin as unknown as Plugin[];
|
||||
}
|
||||
|
|
|
@ -9,12 +9,7 @@ export function resultSuccess<T = Recordable>(result: T, { message = 'ok' } = {}
|
|||
};
|
||||
}
|
||||
|
||||
export function resultPageSuccess<T = any>(
|
||||
pageNo: number,
|
||||
pageSize: number,
|
||||
list: T[],
|
||||
{ message = 'ok' } = {}
|
||||
) {
|
||||
export function resultPageSuccess<T = any>(pageNo: number, pageSize: number, list: T[], { message = 'ok' } = {}) {
|
||||
const pageData = pagination(pageNo, pageSize, list);
|
||||
|
||||
return {
|
||||
|
@ -37,10 +32,7 @@ export function resultError(message = 'Request failed', { code = -1, result = nu
|
|||
|
||||
export function pagination<T = any>(pageNo: number, pageSize: number, array: T[]): T[] {
|
||||
const offset = (pageNo - 1) * Number(pageSize);
|
||||
const ret =
|
||||
offset + Number(pageSize) >= array.length
|
||||
? array.slice(offset, array.length)
|
||||
: array.slice(offset, offset + Number(pageSize));
|
||||
const ret = offset + Number(pageSize) >= array.length ? array.slice(offset, array.length) : array.slice(offset, offset + Number(pageSize));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ export default [
|
|||
timeout: 1000,
|
||||
method: 'get',
|
||||
response: ({ query }) => {
|
||||
const { keyword,count} = query;
|
||||
const { keyword, count } = query;
|
||||
console.log(keyword);
|
||||
return resultSuccess(demoList(keyword,count));
|
||||
return resultSuccess(demoList(keyword, count));
|
||||
},
|
||||
},
|
||||
] as MockMethod[];
|
||||
|
|
|
@ -2,196 +2,183 @@ import { MockMethod } from 'vite-plugin-mock';
|
|||
import { resultError, resultPageSuccess, resultSuccess, baseUrl } from '../_util';
|
||||
|
||||
const accountList = (() => {
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 20; index++) {
|
||||
result.push({
|
||||
id: `${index}`,
|
||||
account: '@first',
|
||||
email: '@email',
|
||||
nickname: '@cname()',
|
||||
role: '@first',
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)',
|
||||
'status|1': ['0', '1'],
|
||||
});
|
||||
}
|
||||
return result;
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 20; index++) {
|
||||
result.push({
|
||||
id: `${index}`,
|
||||
account: '@first',
|
||||
email: '@email',
|
||||
nickname: '@cname()',
|
||||
role: '@first',
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)',
|
||||
'status|1': ['0', '1'],
|
||||
});
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
|
||||
const userList = (() => {
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 20; index++) {
|
||||
result.push({
|
||||
id: `${index}`,
|
||||
username: '@first',
|
||||
email: '@email',
|
||||
realname: '@cname()',
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)',
|
||||
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=190848757&s=640'
|
||||
});
|
||||
}
|
||||
return result;
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 20; index++) {
|
||||
result.push({
|
||||
id: `${index}`,
|
||||
username: '@first',
|
||||
email: '@email',
|
||||
realname: '@cname()',
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)',
|
||||
avatar: 'https://q1.qlogo.cn/g?b=qq&nk=190848757&s=640',
|
||||
});
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
|
||||
const roleList = (() => {
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 4; index++) {
|
||||
result.push({
|
||||
id: index + 1,
|
||||
orderNo: `${index + 1}`,
|
||||
roleName: ['超级管理员', '管理员', '文章管理员', '普通用户'][index],
|
||||
roleValue: '@first',
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)',
|
||||
menu: [['0', '1', '2'], ['0', '1'], ['0', '2'], ['2']][index],
|
||||
'status|1': ['0', '1'],
|
||||
});
|
||||
}
|
||||
return result;
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 4; index++) {
|
||||
result.push({
|
||||
id: index + 1,
|
||||
orderNo: `${index + 1}`,
|
||||
roleName: ['超级管理员', '管理员', '文章管理员', '普通用户'][index],
|
||||
roleValue: '@first',
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)',
|
||||
menu: [['0', '1', '2'], ['0', '1'], ['0', '2'], ['2']][index],
|
||||
'status|1': ['0', '1'],
|
||||
});
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
|
||||
const newRoleList = (() => {
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 4; index++) {
|
||||
result.push({
|
||||
id: index + 1,
|
||||
orderNo: `${index + 1}`,
|
||||
roleName: ['超级管理员', '管理员', '文章管理员', '普通用户'][index],
|
||||
roleCode: '@first',
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)'
|
||||
});
|
||||
}
|
||||
return result;
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 4; index++) {
|
||||
result.push({
|
||||
id: index + 1,
|
||||
orderNo: `${index + 1}`,
|
||||
roleName: ['超级管理员', '管理员', '文章管理员', '普通用户'][index],
|
||||
roleCode: '@first',
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)',
|
||||
});
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
|
||||
const testList = (() => {
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 4; index++) {
|
||||
result.push({
|
||||
id: index + 1,
|
||||
orderNo: `${index + 1}`,
|
||||
testName: ['数据1', '数据2', '数据3', '数据4'][index],
|
||||
testValue: '@first',
|
||||
createTime: '@datetime'
|
||||
});
|
||||
}
|
||||
return result;
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 4; index++) {
|
||||
result.push({
|
||||
id: index + 1,
|
||||
orderNo: `${index + 1}`,
|
||||
testName: ['数据1', '数据2', '数据3', '数据4'][index],
|
||||
testValue: '@first',
|
||||
createTime: '@datetime',
|
||||
});
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
|
||||
const tableDemoList = (() => {
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 4; index++) {
|
||||
result.push({
|
||||
id: index + 1,
|
||||
orderCode: '2008200' + `${index + 1}`,
|
||||
orderMoney: '@natural(1000,3000)',
|
||||
ctype: '@natural(1,2)',
|
||||
content: '@cword(10,20)',
|
||||
orderDate: '@datetime'
|
||||
});
|
||||
}
|
||||
return result;
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 4; index++) {
|
||||
result.push({
|
||||
id: index + 1,
|
||||
orderCode: '2008200' + `${index + 1}`,
|
||||
orderMoney: '@natural(1000,3000)',
|
||||
ctype: '@natural(1,2)',
|
||||
content: '@cword(10,20)',
|
||||
orderDate: '@datetime',
|
||||
});
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
|
||||
const deptList = (() => {
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 3; index++) {
|
||||
result.push({
|
||||
id: `${index}`,
|
||||
deptName: ['华东分部', '华南分部', '西北分部'][index],
|
||||
orderNo: index + 1,
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 3; index++) {
|
||||
result.push({
|
||||
id: `${index}`,
|
||||
deptName: ['华东分部', '华南分部', '西北分部'][index],
|
||||
orderNo: index + 1,
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)',
|
||||
'status|1': ['0', '0', '1'],
|
||||
children: (() => {
|
||||
const children: any[] = [];
|
||||
for (let j = 0; j < 4; j++) {
|
||||
children.push({
|
||||
id: `${index}-${j}`,
|
||||
deptName: ['研发部', '市场部', '商务部', '财务部'][j],
|
||||
orderNo: j + 1,
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)',
|
||||
'status|1': ['0', '0', '1'],
|
||||
children: (() => {
|
||||
const children: any[] = [];
|
||||
for (let j = 0; j < 4; j++) {
|
||||
children.push({
|
||||
id: `${index}-${j}`,
|
||||
deptName: ['研发部', '市场部', '商务部', '财务部'][j],
|
||||
orderNo: j + 1,
|
||||
createTime: '@datetime',
|
||||
remark: '@cword(10,20)',
|
||||
'status|1': ['0', '1'],
|
||||
parentDept: `${index}`,
|
||||
children: undefined,
|
||||
});
|
||||
}
|
||||
return children;
|
||||
})(),
|
||||
});
|
||||
}
|
||||
return result;
|
||||
'status|1': ['0', '1'],
|
||||
parentDept: `${index}`,
|
||||
children: undefined,
|
||||
});
|
||||
}
|
||||
return children;
|
||||
})(),
|
||||
});
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
|
||||
const menuList = (() => {
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 3; index++) {
|
||||
result.push({
|
||||
id: `${index}`,
|
||||
icon: ['ion:layers-outline', 'ion:git-compare-outline', 'ion:tv-outline'][index],
|
||||
component: 'LAYOUT',
|
||||
type: '0',
|
||||
menuName: ['Dashboard', '权限管理', '功能'][index],
|
||||
permission: '',
|
||||
orderNo: index + 1,
|
||||
const result: any[] = [];
|
||||
for (let index = 0; index < 3; index++) {
|
||||
result.push({
|
||||
id: `${index}`,
|
||||
icon: ['ion:layers-outline', 'ion:git-compare-outline', 'ion:tv-outline'][index],
|
||||
component: 'LAYOUT',
|
||||
type: '0',
|
||||
menuName: ['Dashboard', '权限管理', '功能'][index],
|
||||
permission: '',
|
||||
orderNo: index + 1,
|
||||
createTime: '@datetime',
|
||||
'status|1': ['0', '0', '1'],
|
||||
children: (() => {
|
||||
const children: any[] = [];
|
||||
for (let j = 0; j < 4; j++) {
|
||||
children.push({
|
||||
id: `${index}-${j}`,
|
||||
type: '1',
|
||||
menuName: ['菜单1', '菜单2', '菜单3', '菜单4'][j],
|
||||
icon: 'ion:document',
|
||||
permission: ['menu1:view', 'menu2:add', 'menu3:update', 'menu4:del'][index],
|
||||
component: ['/dashboard/welcome/index', '/dashboard/Analysis/index', '/dashboard/workbench/index', '/dashboard/test/index'][j],
|
||||
orderNo: j + 1,
|
||||
createTime: '@datetime',
|
||||
'status|1': ['0', '0', '1'],
|
||||
'status|1': ['0', '1'],
|
||||
parentMenu: `${index}`,
|
||||
children: (() => {
|
||||
const children: any[] = [];
|
||||
for (let j = 0; j < 4; j++) {
|
||||
children.push({
|
||||
id: `${index}-${j}`,
|
||||
type: '1',
|
||||
menuName: ['菜单1', '菜单2', '菜单3', '菜单4'][j],
|
||||
icon: 'ion:document',
|
||||
permission: ['menu1:view', 'menu2:add', 'menu3:update', 'menu4:del'][index],
|
||||
component: [
|
||||
'/dashboard/welcome/index',
|
||||
'/dashboard/Analysis/index',
|
||||
'/dashboard/workbench/index',
|
||||
'/dashboard/test/index',
|
||||
][j],
|
||||
orderNo: j + 1,
|
||||
createTime: '@datetime',
|
||||
'status|1': ['0', '1'],
|
||||
parentMenu: `${index}`,
|
||||
children: (() => {
|
||||
const children: any[] = [];
|
||||
for (let k = 0; k < 4; k++) {
|
||||
children.push({
|
||||
id: `${index}-${j}-${k}`,
|
||||
type: '2',
|
||||
menuName: '按钮' + (j + 1) + '-' + (k + 1),
|
||||
icon: '',
|
||||
permission:
|
||||
['menu1:view', 'menu2:add', 'menu3:update', 'menu4:del'][index] +
|
||||
':btn' +
|
||||
(k + 1),
|
||||
component: [
|
||||
'/dashboard/welcome/index',
|
||||
'/dashboard/Analysis/index',
|
||||
'/dashboard/workbench/index',
|
||||
'/dashboard/test/index',
|
||||
][j],
|
||||
orderNo: j + 1,
|
||||
createTime: '@datetime',
|
||||
'status|1': ['0', '1'],
|
||||
parentMenu: `${index}-${j}`,
|
||||
children: undefined,
|
||||
});
|
||||
}
|
||||
return children;
|
||||
})(),
|
||||
});
|
||||
}
|
||||
return children;
|
||||
const children: any[] = [];
|
||||
for (let k = 0; k < 4; k++) {
|
||||
children.push({
|
||||
id: `${index}-${j}-${k}`,
|
||||
type: '2',
|
||||
menuName: '按钮' + (j + 1) + '-' + (k + 1),
|
||||
icon: '',
|
||||
permission: ['menu1:view', 'menu2:add', 'menu3:update', 'menu4:del'][index] + ':btn' + (k + 1),
|
||||
component: ['/dashboard/welcome/index', '/dashboard/Analysis/index', '/dashboard/workbench/index', '/dashboard/test/index'][j],
|
||||
orderNo: j + 1,
|
||||
createTime: '@datetime',
|
||||
'status|1': ['0', '1'],
|
||||
parentMenu: `${index}-${j}`,
|
||||
children: undefined,
|
||||
});
|
||||
}
|
||||
return children;
|
||||
})(),
|
||||
});
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
return children;
|
||||
})(),
|
||||
});
|
||||
}
|
||||
return result;
|
||||
})();
|
||||
|
||||
export default [
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { resultSuccess, resultError, getRequestToken, requestParams,baseUrl} from '../_util';
|
||||
import { resultSuccess, resultError, getRequestToken, requestParams, baseUrl } from '../_util';
|
||||
import { MockMethod } from 'vite-plugin-mock';
|
||||
import { createFakeUserList } from './user';
|
||||
|
||||
|
|
|
@ -51,9 +51,7 @@ export default [
|
|||
method: 'post',
|
||||
response: ({ body }) => {
|
||||
const { username, password } = body;
|
||||
const checkUser = createFakeUserList().find(
|
||||
(item) => item.username === username && password === item.password
|
||||
);
|
||||
const checkUser = createFakeUserList().find((item) => item.username === username && password === item.password);
|
||||
if (!checkUser) {
|
||||
return resultError('Incorrect account or password!');
|
||||
}
|
||||
|
|
|
@ -291,7 +291,6 @@
|
|||
"vue-print-nb-jeecg/src/printarea",
|
||||
"vue-router",
|
||||
"vue-types",
|
||||
"vuedraggable",
|
||||
"vxe-table",
|
||||
"vxe-table-plugin-antd",
|
||||
"xe-utils",
|
||||
|
|
|
@ -18,7 +18,7 @@ enum Api {
|
|||
/**
|
||||
* 上传父路径
|
||||
*/
|
||||
export const uploadUrl=`${baseUploadUrl}/sys/common/upload`;
|
||||
export const uploadUrl = `${baseUploadUrl}/sys/common/upload`;
|
||||
|
||||
/**
|
||||
* 职务列表
|
||||
|
@ -47,52 +47,51 @@ export const getRoleList = (params) => {
|
|||
/**
|
||||
* 异步获取部门树列表
|
||||
*/
|
||||
export const queryDepartTreeSync = (params?) =>{
|
||||
export const queryDepartTreeSync = (params?) => {
|
||||
return defHttp.get({ url: Api.queryDepartTreeSync, params });
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 获取部门树列表
|
||||
*/
|
||||
export const queryTreeList = (params?) =>{
|
||||
export const queryTreeList = (params?) => {
|
||||
return defHttp.get({ url: Api.queryTreeList, params });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 分类字典树控件 加载节点
|
||||
*/
|
||||
export const loadTreeData = (params?) =>{
|
||||
export const loadTreeData = (params?) => {
|
||||
return defHttp.get({ url: Api.loadTreeData, params });
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据字典code加载字典text
|
||||
*/
|
||||
export const loadDictItem = (params?) =>{
|
||||
export const loadDictItem = (params?) => {
|
||||
return defHttp.get({ url: Api.loadDictItem, params });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据字典code加载字典text
|
||||
*/
|
||||
export const getDictItems = (dictCode) =>{
|
||||
return defHttp.get({ url: Api.getDictItems+dictCode},{joinTime:false});
|
||||
}
|
||||
export const getDictItems = (dictCode) => {
|
||||
return defHttp.get({ url: Api.getDictItems + dictCode }, { joinTime: false });
|
||||
};
|
||||
/**
|
||||
* 部门用户modal选择列表加载list
|
||||
*/
|
||||
export const getTableList = (params)=>{
|
||||
return defHttp.get({url:Api.getTableList,params})
|
||||
}
|
||||
export const getTableList = (params) => {
|
||||
return defHttp.get({ url: Api.getTableList, params });
|
||||
};
|
||||
/**
|
||||
* 加载全部分类字典数据
|
||||
*/
|
||||
export const loadCategoryData = (params)=>{
|
||||
return defHttp.get({url:Api.getCategoryData,params})
|
||||
}
|
||||
export const loadCategoryData = (params) => {
|
||||
return defHttp.get({ url: Api.getCategoryData, params });
|
||||
};
|
||||
/**
|
||||
* 文件上传
|
||||
*/
|
||||
export const uploadFile = (params,success)=>{
|
||||
return defHttp.uploadFile({url:uploadUrl}, params,{success})
|
||||
}
|
||||
export const uploadFile = (params, success) => {
|
||||
return defHttp.uploadFile({ url: uploadUrl }, params, { success });
|
||||
};
|
||||
|
|
|
@ -7,5 +7,4 @@ enum Api {
|
|||
/**
|
||||
* @description: Get sample options value
|
||||
*/
|
||||
export const optionsListApi = (params?: selectParams) =>
|
||||
defHttp.get<DemoOptionsItem[]>({ url: Api.OPTIONS_LIST, params });
|
||||
export const optionsListApi = (params?: selectParams) => defHttp.get<DemoOptionsItem[]>({ url: Api.OPTIONS_LIST, params });
|
||||
|
|
|
@ -1,54 +1,45 @@
|
|||
import {
|
||||
AccountParams,
|
||||
DeptListItem,
|
||||
MenuParams,
|
||||
RoleParams,
|
||||
TestPageParams,
|
||||
RolePageParams,
|
||||
MenuListGetResultModel,
|
||||
DeptListGetResultModel,
|
||||
AccountListGetResultModel,
|
||||
RolePageListGetResultModel,
|
||||
RoleListGetResultModel,
|
||||
TestListGetResultModel
|
||||
AccountParams,
|
||||
DeptListItem,
|
||||
MenuParams,
|
||||
RoleParams,
|
||||
TestPageParams,
|
||||
RolePageParams,
|
||||
MenuListGetResultModel,
|
||||
DeptListGetResultModel,
|
||||
AccountListGetResultModel,
|
||||
RolePageListGetResultModel,
|
||||
RoleListGetResultModel,
|
||||
TestListGetResultModel,
|
||||
} from './model/systemModel';
|
||||
import {defHttp} from '/@/utils/http/axios';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
AccountList = '/mock/system/getAccountList',
|
||||
IsAccountExist = '/mock/system/accountExist',
|
||||
DeptList = '/mock/system/getDeptList',
|
||||
setRoleStatus = '/mock/system/setRoleStatus',
|
||||
MenuList = '/mock/system/getMenuList',
|
||||
RolePageList = '/mock/system/getRoleListByPage',
|
||||
DemoTableList = '/mock/system/getDemoTableListByPage',
|
||||
TestPageList = '/mock/system/getTestListByPage',
|
||||
GetAllRoleList = '/mock/system/getAllRoleList',
|
||||
AccountList = '/mock/system/getAccountList',
|
||||
IsAccountExist = '/mock/system/accountExist',
|
||||
DeptList = '/mock/system/getDeptList',
|
||||
setRoleStatus = '/mock/system/setRoleStatus',
|
||||
MenuList = '/mock/system/getMenuList',
|
||||
RolePageList = '/mock/system/getRoleListByPage',
|
||||
DemoTableList = '/mock/system/getDemoTableListByPage',
|
||||
TestPageList = '/mock/system/getTestListByPage',
|
||||
GetAllRoleList = '/mock/system/getAllRoleList',
|
||||
}
|
||||
|
||||
export const getAccountList = (params: AccountParams) =>
|
||||
defHttp.get<AccountListGetResultModel>({url: Api.AccountList, params});
|
||||
export const getAccountList = (params: AccountParams) => defHttp.get<AccountListGetResultModel>({ url: Api.AccountList, params });
|
||||
|
||||
export const getDeptList = (params?: DeptListItem) =>
|
||||
defHttp.get<DeptListGetResultModel>({url: Api.DeptList, params});
|
||||
export const getDeptList = (params?: DeptListItem) => defHttp.get<DeptListGetResultModel>({ url: Api.DeptList, params });
|
||||
|
||||
export const getMenuList = (params?: MenuParams) =>
|
||||
defHttp.get<MenuListGetResultModel>({url: Api.MenuList, params});
|
||||
export const getMenuList = (params?: MenuParams) => defHttp.get<MenuListGetResultModel>({ url: Api.MenuList, params });
|
||||
|
||||
export const getRoleListByPage = (params?: RolePageParams) =>
|
||||
defHttp.get<RolePageListGetResultModel>({url: Api.RolePageList, params});
|
||||
export const getRoleListByPage = (params?: RolePageParams) => defHttp.get<RolePageListGetResultModel>({ url: Api.RolePageList, params });
|
||||
|
||||
export const getAllRoleList = (params?: RoleParams) =>
|
||||
defHttp.get<RoleListGetResultModel>({url: Api.GetAllRoleList, params});
|
||||
export const getAllRoleList = (params?: RoleParams) => defHttp.get<RoleListGetResultModel>({ url: Api.GetAllRoleList, params });
|
||||
|
||||
export const setRoleStatus = (id: number, status: string) =>
|
||||
defHttp.post({url: Api.setRoleStatus, params: {id, status}});
|
||||
export const setRoleStatus = (id: number, status: string) => defHttp.post({ url: Api.setRoleStatus, params: { id, status } });
|
||||
|
||||
export const getTestListByPage = (params?: TestPageParams) =>
|
||||
defHttp.get<TestListGetResultModel>({url: Api.TestPageList, params});
|
||||
export const getTestListByPage = (params?: TestPageParams) => defHttp.get<TestListGetResultModel>({ url: Api.TestPageList, params });
|
||||
|
||||
export const getDemoTableListByPage = (params) =>
|
||||
defHttp.get({url: Api.DemoTableList, params});
|
||||
export const getDemoTableListByPage = (params) => defHttp.get({ url: Api.DemoTableList, params });
|
||||
|
||||
export const isAccountExist = (account: string) =>
|
||||
defHttp.post({url: Api.IsAccountExist, params: {account}}, {errorMessageMode: 'none'});
|
||||
export const isAccountExist = (account: string) => defHttp.post({ url: Api.IsAccountExist, params: { account } }, { errorMessageMode: 'none' });
|
||||
|
|
|
@ -7,5 +7,4 @@ enum Api {
|
|||
/**
|
||||
* @description: Get sample options value
|
||||
*/
|
||||
export const treeOptionsListApi = (params?: Recordable) =>
|
||||
defHttp.get<Recordable[]>({ url: Api.TREE_OPTIONS_LIST, params });
|
||||
export const treeOptionsListApi = (params?: Recordable) => defHttp.get<Recordable[]>({ url: Api.TREE_OPTIONS_LIST, params });
|
||||
|
|
|
@ -12,12 +12,12 @@ enum Api {
|
|||
export const getMenuList = () => {
|
||||
return new Promise((resolve) => {
|
||||
//为了兼容mock和接口数据
|
||||
defHttp.get<getMenuListResultModel>({ url: Api.GetMenuList }).then(res=>{
|
||||
if(Array.isArray(res)){
|
||||
resolve(res)
|
||||
}else{
|
||||
resolve(res['menu'])
|
||||
defHttp.get<getMenuListResultModel>({ url: Api.GetMenuList }).then((res) => {
|
||||
if (Array.isArray(res)) {
|
||||
resolve(res);
|
||||
} else {
|
||||
resolve(res['menu']);
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
};
|
||||
|
|
|
@ -52,6 +52,6 @@ export interface GetUserInfoModel {
|
|||
export interface GetResultModel {
|
||||
code: number;
|
||||
message: string;
|
||||
result:object;
|
||||
result: object;
|
||||
success: Boolean;
|
||||
}
|
||||
|
|
|
@ -8,10 +8,7 @@ const { uploadUrl = '' } = useGlobSetting();
|
|||
/**
|
||||
* @description: Upload interface
|
||||
*/
|
||||
export function uploadApi(
|
||||
params: UploadFileParams,
|
||||
onUploadProgress: (progressEvent: ProgressEvent) => void
|
||||
) {
|
||||
export function uploadApi(params: UploadFileParams, onUploadProgress: (progressEvent: ProgressEvent) => void) {
|
||||
return defHttp.uploadFile<UploadApiResult>(
|
||||
{
|
||||
url: uploadUrl,
|
||||
|
@ -23,15 +20,13 @@ export function uploadApi(
|
|||
/**
|
||||
* @description: Upload interface
|
||||
*/
|
||||
export function uploadImg(
|
||||
params: UploadFileParams,
|
||||
onUploadProgress: (progressEvent: ProgressEvent) => void
|
||||
) {
|
||||
export function uploadImg(params: UploadFileParams, onUploadProgress: (progressEvent: ProgressEvent) => void) {
|
||||
return defHttp.uploadFile<UploadApiResult>(
|
||||
{
|
||||
url: `${uploadUrl}/sys/common/upload`,
|
||||
onUploadProgress,
|
||||
},
|
||||
params, {isReturnResponse:true}
|
||||
params,
|
||||
{ isReturnResponse: true }
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,16 +2,15 @@ import { defHttp } from '/@/utils/http/axios';
|
|||
import { LoginParams, LoginResultModel, GetUserInfoModel } from './model/userModel';
|
||||
|
||||
import { ErrorMessageMode } from '/#/axios';
|
||||
import {useMessage} from "/@/hooks/web/useMessage";
|
||||
import {useUserStoreWithOut} from "/@/store/modules/user";
|
||||
import {setAuthCache} from "/@/utils/auth";
|
||||
import {TOKEN_KEY} from "/@/enums/cacheEnum";
|
||||
import {router} from "/@/router";
|
||||
import {PageEnum} from "/@/enums/pageEnum";
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useUserStoreWithOut } from '/@/store/modules/user';
|
||||
import { setAuthCache } from '/@/utils/auth';
|
||||
import { TOKEN_KEY } from '/@/enums/cacheEnum';
|
||||
import { router } from '/@/router';
|
||||
import { PageEnum } from '/@/enums/pageEnum';
|
||||
|
||||
const { createErrorModal } = useMessage();
|
||||
enum Api {
|
||||
|
||||
Login = '/sys/login',
|
||||
phoneLogin = '/sys/phoneLogin',
|
||||
Logout = '/sys/logout',
|
||||
|
@ -23,7 +22,7 @@ enum Api {
|
|||
GetPermCode = '/sys/permission/getPermCode',
|
||||
//新加的获取图形验证码的接口
|
||||
getInputCode = '/sys/randomImage',
|
||||
//获取短信验证码的接口
|
||||
//获取短信验证码的接口
|
||||
getCaptcha = '/sys/sms',
|
||||
//注册接口
|
||||
registerApi = '/sys/user/register',
|
||||
|
@ -78,17 +77,17 @@ export function phoneLoginApi(params: LoginParams, mode: ErrorMessageMode = 'mod
|
|||
/**
|
||||
* @description: getUserInfo
|
||||
*/
|
||||
export function getUserInfo() {
|
||||
return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo }, { errorMessageMode: 'none' }).catch((e)=>{
|
||||
// update-begin--author:zyf---date:20220425---for:【VUEN-76】捕获接口超时异常,跳转到登录界面
|
||||
if (e && e.message.includes('timeout')) {
|
||||
//接口不通时跳转到登录界面
|
||||
const userStore = useUserStoreWithOut();
|
||||
userStore.setToken('');
|
||||
setAuthCache(TOKEN_KEY, null);
|
||||
router.push(PageEnum.BASE_LOGIN);
|
||||
}
|
||||
// update-end--author:zyf---date:20220425---for:【VUEN-76】捕获接口超时异常,跳转到登录界面
|
||||
export function getUserInfo() {
|
||||
return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo }, { errorMessageMode: 'none' }).catch((e) => {
|
||||
// update-begin--author:zyf---date:20220425---for:【VUEN-76】捕获接口超时异常,跳转到登录界面
|
||||
if (e && e.message.includes('timeout')) {
|
||||
//接口不通时跳转到登录界面
|
||||
const userStore = useUserStoreWithOut();
|
||||
userStore.setToken('');
|
||||
setAuthCache(TOKEN_KEY, null);
|
||||
router.push(PageEnum.BASE_LOGIN);
|
||||
}
|
||||
// update-end--author:zyf---date:20220425---for:【VUEN-76】捕获接口超时异常,跳转到登录界面
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -101,7 +100,7 @@ export function doLogout() {
|
|||
}
|
||||
|
||||
export function getCodeInfo(currdatetime) {
|
||||
let url = Api.getInputCode+`/${currdatetime}`
|
||||
let url = Api.getInputCode + `/${currdatetime}`;
|
||||
return defHttp.get({ url: url });
|
||||
}
|
||||
/**
|
||||
|
@ -109,78 +108,75 @@ export function getCodeInfo(currdatetime) {
|
|||
*/
|
||||
export function getCaptcha(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
defHttp.post({url:Api.getCaptcha,params},{isTransformResponse: false}).then(res=>{
|
||||
console.log(res)
|
||||
if(res.success){
|
||||
resolve(true)
|
||||
}else{
|
||||
createErrorModal({ title: '错误提示', content: res.message||'未知问题' });
|
||||
reject()
|
||||
defHttp.post({ url: Api.getCaptcha, params }, { isTransformResponse: false }).then((res) => {
|
||||
console.log(res);
|
||||
if (res.success) {
|
||||
resolve(true);
|
||||
} else {
|
||||
createErrorModal({ title: '错误提示', content: res.message || '未知问题' });
|
||||
reject();
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: 注册接口
|
||||
*/
|
||||
export function register(params) {
|
||||
return defHttp.post({url: Api.registerApi,params},{isReturnNativeResponse: true})
|
||||
return defHttp.post({ url: Api.registerApi, params }, { isReturnNativeResponse: true });
|
||||
}
|
||||
|
||||
/**
|
||||
*校验用户是否存在
|
||||
* @param params
|
||||
*/
|
||||
export const checkOnlyUser = (params) =>
|
||||
defHttp.get({url: Api.checkOnlyUser, params},{isTransformResponse:false});
|
||||
export const checkOnlyUser = (params) => defHttp.get({ url: Api.checkOnlyUser, params }, { isTransformResponse: false });
|
||||
/**
|
||||
*校验手机号码
|
||||
* @param params
|
||||
*/
|
||||
export const phoneVerify = (params) =>
|
||||
defHttp.post({url: Api.phoneVerify, params},{isTransformResponse:false});
|
||||
export const phoneVerify = (params) => defHttp.post({ url: Api.phoneVerify, params }, { isTransformResponse: false });
|
||||
/**
|
||||
*密码修改
|
||||
* @param params
|
||||
*/
|
||||
export const passwordChange = (params) =>
|
||||
defHttp.get({url: Api.passwordChange, params},{isTransformResponse:false});
|
||||
export const passwordChange = (params) => defHttp.get({ url: Api.passwordChange, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* @description: 第三方登录
|
||||
*/
|
||||
export function thirdLogin(params, mode: ErrorMessageMode = 'modal') {
|
||||
return defHttp.get<LoginResultModel>(
|
||||
{
|
||||
url: `${Api.thirdLogin}/${params.token}/${params.thirdType}`,
|
||||
},
|
||||
{
|
||||
errorMessageMode: mode,
|
||||
}
|
||||
);
|
||||
return defHttp.get<LoginResultModel>(
|
||||
{
|
||||
url: `${Api.thirdLogin}/${params.token}/${params.thirdType}`,
|
||||
},
|
||||
{
|
||||
errorMessageMode: mode,
|
||||
}
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @description: 获取第三方短信验证码
|
||||
*/
|
||||
export function setThirdCaptcha(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
defHttp.post({url:Api.getThirdCaptcha,params},{isTransformResponse: false}).then(res=>{
|
||||
console.log(res)
|
||||
if(res.success){
|
||||
resolve(true)
|
||||
}else{
|
||||
createErrorModal({ title: '错误提示', content: res.message||'未知问题' });
|
||||
reject()
|
||||
}
|
||||
});
|
||||
})
|
||||
return new Promise((resolve, reject) => {
|
||||
defHttp.post({ url: Api.getThirdCaptcha, params }, { isTransformResponse: false }).then((res) => {
|
||||
console.log(res);
|
||||
if (res.success) {
|
||||
resolve(true);
|
||||
} else {
|
||||
createErrorModal({ title: '错误提示', content: res.message || '未知问题' });
|
||||
reject();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取登录二维码信息
|
||||
*/
|
||||
export function getLoginQrcode() {
|
||||
let url = Api.getLoginQrcode
|
||||
let url = Api.getLoginQrcode;
|
||||
return defHttp.get({ url: url });
|
||||
}
|
||||
|
||||
|
@ -188,14 +184,14 @@ export function getLoginQrcode() {
|
|||
* 监控扫码状态
|
||||
*/
|
||||
export function getQrcodeToken(params) {
|
||||
let url = Api.getQrcodeToken
|
||||
return defHttp.get({ url: url,params});
|
||||
let url = Api.getQrcodeToken;
|
||||
return defHttp.get({ url: url, params });
|
||||
}
|
||||
|
||||
/**
|
||||
* SSO登录校验
|
||||
*/
|
||||
export async function validateCasLogin(params) {
|
||||
let url = Api.validateCasLogin
|
||||
return defHttp.get({ url: url,params});
|
||||
let url = Api.validateCasLogin;
|
||||
return defHttp.get({ url: url, params });
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
outline: 0;
|
||||
}
|
||||
|
||||
|
||||
.area-select:active {
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
|
@ -96,12 +95,12 @@
|
|||
top: 50%;
|
||||
margin-top: -2px;
|
||||
right: 6px;
|
||||
content: "";
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 6px solid transparent;
|
||||
border-top-color: rgba(0, 0, 0, 0.25);
|
||||
transition: all .3s linear;
|
||||
transition: all 0.3s linear;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
|
@ -223,7 +222,7 @@
|
|||
top: 50%;
|
||||
margin-top: -4px;
|
||||
right: 5px;
|
||||
content: "";
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 4px solid transparent;
|
||||
|
@ -256,4 +255,4 @@
|
|||
.cascader-menu-list::-webkit-scrollbar-thumb:vertical:hover,
|
||||
.area-selectable-list-wrap::-webkit-scrollbar-thumb:vertical:hover {
|
||||
background-color: #777;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,7 @@
|
|||
* @Description: Multi-language switching component
|
||||
-->
|
||||
<template>
|
||||
<Dropdown
|
||||
placement="bottomCenter"
|
||||
:trigger="['click']"
|
||||
:dropMenuList="localeList"
|
||||
:selectedKeys="selectedKeys"
|
||||
@menuEvent="handleMenuEvent"
|
||||
overlayClassName="app-locale-picker-overlay"
|
||||
>
|
||||
<Dropdown placement="bottomCenter" :trigger="['click']" :dropMenuList="localeList" :selectedKeys="selectedKeys" @menuEvent="handleMenuEvent" overlayClassName="app-locale-picker-overlay">
|
||||
<span class="cursor-pointer flex items-center">
|
||||
<Icon icon="ion:language" />
|
||||
<span v-if="showText" class="ml-1">{{ getLocaleText }}</span>
|
||||
|
|
|
@ -40,11 +40,7 @@
|
|||
const { title } = useGlobSetting();
|
||||
const go = useGo();
|
||||
|
||||
const getAppLogoClass = computed(() => [
|
||||
prefixCls,
|
||||
props.theme,
|
||||
{ 'collapsed-show-title': unref(getCollapsedShowTitle) },
|
||||
]);
|
||||
const getAppLogoClass = computed(() => [prefixCls, props.theme, { 'collapsed-show-title': unref(getCollapsedShowTitle) }]);
|
||||
|
||||
const getTitleClass = computed(() => [
|
||||
`${prefixCls}__title`,
|
||||
|
|
|
@ -45,12 +45,7 @@
|
|||
if (!unref(isSetState)) {
|
||||
isSetState.value = true;
|
||||
const {
|
||||
menuSetting: {
|
||||
type: menuType,
|
||||
mode: menuMode,
|
||||
collapsed: menuCollapsed,
|
||||
split: menuSplit,
|
||||
},
|
||||
menuSetting: { type: menuType, mode: menuMode, collapsed: menuCollapsed, split: menuSplit },
|
||||
} = appStore.getProjectConfig;
|
||||
appStore.setProjectConfig({
|
||||
menuSetting: {
|
||||
|
|
|
@ -41,8 +41,7 @@
|
|||
margin-right: 0.4em;
|
||||
background-color: linear-gradient(-225deg, #d5dbe4, #f8f8f8);
|
||||
border-radius: 2px;
|
||||
box-shadow: inset 0 -2px 0 0 #cdcde6, inset 0 0 1px 1px #fff,
|
||||
0 1px 2px 1px rgba(30, 35, 90, 0.4);
|
||||
box-shadow: inset 0 -2px 0 0 #cdcde6, inset 0 0 1px 1px #fff, 0 1px 2px 1px rgba(30, 35, 90, 0.4);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
|
|
|
@ -4,13 +4,7 @@
|
|||
<div :class="getClass" @click.stop v-if="visible">
|
||||
<div :class="`${prefixCls}-content`" v-click-outside="handleClose">
|
||||
<div :class="`${prefixCls}-input__wrapper`">
|
||||
<a-input
|
||||
:class="`${prefixCls}-input`"
|
||||
:placeholder="t('common.searchText')"
|
||||
ref="inputRef"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<a-input :class="`${prefixCls}-input`" :placeholder="t('common.searchText')" ref="inputRef" allow-clear @change="handleSearch">
|
||||
<template #prefix>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
|
@ -26,13 +20,13 @@
|
|||
|
||||
<ul :class="`${prefixCls}-list`" v-show="!getIsNotData" ref="scrollWrap">
|
||||
<li
|
||||
:ref="setRefs(index)"
|
||||
v-for="(item, index) in searchResult"
|
||||
:key="item.path"
|
||||
:data-index="index"
|
||||
@mouseenter="handleMouseenter"
|
||||
@click="handleEnter"
|
||||
:class="[
|
||||
:ref="setRefs(index)"
|
||||
v-for="(item, index) in searchResult"
|
||||
:key="item.path"
|
||||
:data-index="index"
|
||||
@mouseenter="handleMouseenter"
|
||||
@click="handleEnter"
|
||||
:class="[
|
||||
`${prefixCls}-list__item`,
|
||||
{
|
||||
[`${prefixCls}-list__item--active`]: activeIndex === index,
|
||||
|
@ -84,8 +78,7 @@
|
|||
const [refs, setRefs] = useRefs();
|
||||
const { getIsMobile } = useAppInject();
|
||||
|
||||
const { handleSearch, searchResult, keyword, activeIndex, handleEnter, handleMouseenter } =
|
||||
useMenuSearch(refs, scrollWrap, emit);
|
||||
const { handleSearch, searchResult, keyword, activeIndex, handleEnter, handleMouseenter } = useMenuSearch(refs, scrollWrap, emit);
|
||||
|
||||
const getIsNotData = computed(() => !keyword || unref(searchResult).length === 0);
|
||||
|
||||
|
@ -99,13 +92,13 @@
|
|||
});
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible: boolean) => {
|
||||
visible &&
|
||||
nextTick(() => {
|
||||
unref(inputRef)?.focus();
|
||||
});
|
||||
}
|
||||
() => props.visible,
|
||||
(visible: boolean) => {
|
||||
visible &&
|
||||
nextTick(() => {
|
||||
unref(inputRef)?.focus();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
function handleClose() {
|
||||
|
|
|
@ -57,7 +57,7 @@ export function useMenuSearch(refs: Ref<HTMLElement[]>, scrollWrap: Ref<ElRef>,
|
|||
const filterMenu = filter(menuList, (item) => {
|
||||
// 【issues/33】包含子菜单时,不添加到搜索队列
|
||||
if (Array.isArray(item.children)) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
return reg.test(item.name) && !item.hideMenu;
|
||||
});
|
||||
|
|
|
@ -46,9 +46,7 @@
|
|||
setup(props, { slots }) {
|
||||
const { prefixCls } = useDesign('basic-help');
|
||||
|
||||
const getTooltipStyle = computed(
|
||||
(): CSSProperties => ({ color: props.color, fontSize: props.fontSize })
|
||||
);
|
||||
const getTooltipStyle = computed((): CSSProperties => ({ color: props.color, fontSize: props.fontSize }));
|
||||
|
||||
const getOverlayStyle = computed((): CSSProperties => ({ maxWidth: props.maxWidth }));
|
||||
|
||||
|
|
|
@ -33,11 +33,7 @@
|
|||
|
||||
const { prefixCls } = useDesign('basic-title');
|
||||
const slots = useSlots();
|
||||
const getClass = computed(() => [
|
||||
prefixCls,
|
||||
{ [`${prefixCls}-show-span`]: props.span && slots.default },
|
||||
{ [`${prefixCls}-normal`]: props.normal },
|
||||
]);
|
||||
const getClass = computed(() => [prefixCls, { [`${prefixCls}-show-span`]: props.span && slots.default }, { [`${prefixCls}-normal`]: props.normal }]);
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-basic-title';
|
||||
|
|
|
@ -1,39 +1,39 @@
|
|||
<template>
|
||||
<Button v-bind="getBindValue" :class="getButtonClass" @click="onClick">
|
||||
<template #default="data">
|
||||
<Icon :icon="preIcon" v-if="preIcon" :size="iconSize" />
|
||||
<slot v-bind="data || {}"></slot>
|
||||
<Icon :icon="postIcon" v-if="postIcon" :size="iconSize" />
|
||||
</template>
|
||||
</Button>
|
||||
<Button v-bind="getBindValue" :class="getButtonClass" @click="onClick">
|
||||
<template #default="data">
|
||||
<Icon :icon="preIcon" v-if="preIcon" :size="iconSize" />
|
||||
<slot v-bind="data || {}"></slot>
|
||||
<Icon :icon="postIcon" v-if="postIcon" :size="iconSize" />
|
||||
</template>
|
||||
</Button>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'AButton',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'AButton',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import { computed, unref } from 'vue';
|
||||
import { Button } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon/src/Icon.vue';
|
||||
import { buttonProps } from './props';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
const props = defineProps(buttonProps);
|
||||
// get component class
|
||||
const attrs = useAttrs({ excludeDefaultKeys: false });
|
||||
const getButtonClass = computed(() => {
|
||||
const { color, disabled } = props;
|
||||
return [
|
||||
{
|
||||
[`ant-btn-${color}`]: !!color,
|
||||
[`is-disabled`]: disabled,
|
||||
},
|
||||
];
|
||||
});
|
||||
import { computed, unref } from 'vue';
|
||||
import { Button } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon/src/Icon.vue';
|
||||
import { buttonProps } from './props';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
const props = defineProps(buttonProps);
|
||||
// get component class
|
||||
const attrs = useAttrs({ excludeDefaultKeys: false });
|
||||
const getButtonClass = computed(() => {
|
||||
const { color, disabled } = props;
|
||||
return [
|
||||
{
|
||||
[`ant-btn-${color}`]: !!color,
|
||||
[`is-disabled`]: disabled,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
// get inherit binding value
|
||||
const getBindValue = computed(() => ({ ...unref(attrs), ...props }));
|
||||
// get inherit binding value
|
||||
const getBindValue = computed(() => ({ ...unref(attrs), ...props }));
|
||||
</script>
|
||||
|
|
|
@ -1,54 +1,54 @@
|
|||
<script lang="ts">
|
||||
import { computed, defineComponent, h, unref } from 'vue';
|
||||
import BasicButton from './BasicButton.vue';
|
||||
import { Popconfirm } from 'ant-design-vue';
|
||||
import { extendSlots } from '/@/utils/helper/tsxHelper';
|
||||
import { omit } from 'lodash-es';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { computed, defineComponent, h, unref } from 'vue';
|
||||
import BasicButton from './BasicButton.vue';
|
||||
import { Popconfirm } from 'ant-design-vue';
|
||||
import { extendSlots } from '/@/utils/helper/tsxHelper';
|
||||
import { omit } from 'lodash-es';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
const props = {
|
||||
/**
|
||||
* Whether to enable the drop-down menu
|
||||
* @default: true
|
||||
*/
|
||||
enable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
};
|
||||
const props = {
|
||||
/**
|
||||
* Whether to enable the drop-down menu
|
||||
* @default: true
|
||||
*/
|
||||
enable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PopButton',
|
||||
inheritAttrs: false,
|
||||
props,
|
||||
setup(props, { slots }) {
|
||||
const { t } = useI18n();
|
||||
const attrs = useAttrs();
|
||||
export default defineComponent({
|
||||
name: 'PopButton',
|
||||
inheritAttrs: false,
|
||||
props,
|
||||
setup(props, { slots }) {
|
||||
const { t } = useI18n();
|
||||
const attrs = useAttrs();
|
||||
|
||||
// get inherit binding value
|
||||
const getBindValues = computed(() => {
|
||||
return Object.assign(
|
||||
{
|
||||
okText: t('common.okText'),
|
||||
cancelText: t('common.cancelText'),
|
||||
},
|
||||
{ ...props, ...unref(attrs) }
|
||||
);
|
||||
});
|
||||
// get inherit binding value
|
||||
const getBindValues = computed(() => {
|
||||
return Object.assign(
|
||||
{
|
||||
okText: t('common.okText'),
|
||||
cancelText: t('common.cancelText'),
|
||||
},
|
||||
{ ...props, ...unref(attrs) }
|
||||
);
|
||||
});
|
||||
|
||||
return () => {
|
||||
const bindValues = omit(unref(getBindValues), 'icon');
|
||||
const btnBind = omit(bindValues, 'title') as Recordable;
|
||||
if (btnBind.disabled) btnBind.color = '';
|
||||
const Button = h(BasicButton, btnBind, extendSlots(slots));
|
||||
return () => {
|
||||
const bindValues = omit(unref(getBindValues), 'icon');
|
||||
const btnBind = omit(bindValues, 'title') as Recordable;
|
||||
if (btnBind.disabled) btnBind.color = '';
|
||||
const Button = h(BasicButton, btnBind, extendSlots(slots));
|
||||
|
||||
// If it is not enabled, it is a normal button
|
||||
if (!props.enable) {
|
||||
return Button;
|
||||
}
|
||||
return h(Popconfirm, bindValues, { default: () => Button });
|
||||
};
|
||||
},
|
||||
});
|
||||
// If it is not enabled, it is a normal button
|
||||
if (!props.enable) {
|
||||
return Button;
|
||||
}
|
||||
return h(Popconfirm, bindValues, { default: () => Button });
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,41 +1,41 @@
|
|||
<template>
|
||||
<a-upload name="file" :showUploadList="false" :customRequest="(file)=>onClick(file)">
|
||||
<Button :type="type" :class="getButtonClass" >
|
||||
<template #default="data">
|
||||
<Icon :icon="preIcon" v-if="preIcon" :size="iconSize" />
|
||||
<slot v-bind="data || {}"></slot>
|
||||
<Icon :icon="postIcon" v-if="postIcon" :size="iconSize" />
|
||||
</template>
|
||||
</Button>
|
||||
</a-upload>
|
||||
<a-upload name="file" :showUploadList="false" :customRequest="(file) => onClick(file)">
|
||||
<Button :type="type" :class="getButtonClass">
|
||||
<template #default="data">
|
||||
<Icon :icon="preIcon" v-if="preIcon" :size="iconSize" />
|
||||
<slot v-bind="data || {}"></slot>
|
||||
<Icon :icon="postIcon" v-if="postIcon" :size="iconSize" />
|
||||
</template>
|
||||
</Button>
|
||||
</a-upload>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'JUploadButton',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'JUploadButton',
|
||||
inheritAttrs: false,
|
||||
});
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import { computed, unref } from 'vue';
|
||||
import { Button } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon/src/Icon.vue';
|
||||
import { buttonProps } from './props';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
const props = defineProps(buttonProps);
|
||||
// get component class
|
||||
const attrs = useAttrs({ excludeDefaultKeys: false });
|
||||
const getButtonClass = computed(() => {
|
||||
const { color, disabled } = props;
|
||||
return [
|
||||
{
|
||||
[`ant-btn-${color}`]: !!color,
|
||||
[`is-disabled`]: disabled,
|
||||
},
|
||||
];
|
||||
});
|
||||
import { computed, unref } from 'vue';
|
||||
import { Button } from 'ant-design-vue';
|
||||
import Icon from '/@/components/Icon/src/Icon.vue';
|
||||
import { buttonProps } from './props';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
const props = defineProps(buttonProps);
|
||||
// get component class
|
||||
const attrs = useAttrs({ excludeDefaultKeys: false });
|
||||
const getButtonClass = computed(() => {
|
||||
const { color, disabled } = props;
|
||||
return [
|
||||
{
|
||||
[`ant-btn-${color}`]: !!color,
|
||||
[`is-disabled`]: disabled,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
// get inherit binding value
|
||||
const getBindValue = computed(() => ({ ...unref(attrs), ...props }));
|
||||
// get inherit binding value
|
||||
const getBindValue = computed(() => ({ ...unref(attrs), ...props }));
|
||||
</script>
|
||||
|
|
|
@ -16,6 +16,6 @@ export const buttonProps = {
|
|||
* @default: 14
|
||||
*/
|
||||
iconSize: { type: Number, default: 14 },
|
||||
isUpload:{type:Boolean,default:false},
|
||||
isUpload: { type: Boolean, default: false },
|
||||
onClick: { type: Function as PropType<(...args) => any>, default: null },
|
||||
};
|
||||
|
|
|
@ -1,50 +1,39 @@
|
|||
<template>
|
||||
<div class="p-2">
|
||||
<div class="bg-white mb-2 p-4">
|
||||
<BasicForm @register="registerForm" />
|
||||
</div>
|
||||
{{ sliderProp.width }}
|
||||
<div class="bg-white p-2">
|
||||
<List
|
||||
:grid="{ gutter: 5, xs: 1, sm: 2, md: 4, lg: 4, xl: 6, xxl: grid }"
|
||||
:data-source="data"
|
||||
:pagination="paginationProp"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex justify-end space-x-2"
|
||||
><slot name="header"></slot>
|
||||
<Tooltip>
|
||||
<template #title>
|
||||
<div class="w-50">每行显示数量</div
|
||||
><Slider
|
||||
id="slider"
|
||||
v-bind="sliderProp"
|
||||
v-model:value="grid"
|
||||
@change="sliderChange"
|
||||
/></template>
|
||||
<Button><TableOutlined /></Button>
|
||||
</Tooltip>
|
||||
<Tooltip @click="fetch">
|
||||
<template #title>刷新</template>
|
||||
<Button><RedoOutlined /></Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<template #renderItem="{ item }">
|
||||
<ListItem>
|
||||
<Card>
|
||||
<template #title></template>
|
||||
<template #cover>
|
||||
<div :class="height">
|
||||
<Image :src="item.imgs[0]" />
|
||||
</div>
|
||||
</template>
|
||||
<template class="ant-card-actions" #actions>
|
||||
<!-- <SettingOutlined key="setting" />-->
|
||||
<EditOutlined key="edit" />
|
||||
<Dropdown
|
||||
:trigger="['hover']"
|
||||
:dropMenuList="[
|
||||
<div class="p-2">
|
||||
<div class="bg-white mb-2 p-4">
|
||||
<BasicForm @register="registerForm" />
|
||||
</div>
|
||||
{{ sliderProp.width }}
|
||||
<div class="bg-white p-2">
|
||||
<List :grid="{ gutter: 5, xs: 1, sm: 2, md: 4, lg: 4, xl: 6, xxl: grid }" :data-source="data" :pagination="paginationProp">
|
||||
<template #header>
|
||||
<div class="flex justify-end space-x-2"
|
||||
><slot name="header"></slot>
|
||||
<Tooltip>
|
||||
<template #title> <div class="w-50">每行显示数量</div><Slider id="slider" v-bind="sliderProp" v-model:value="grid" @change="sliderChange" /></template>
|
||||
<Button><TableOutlined /></Button>
|
||||
</Tooltip>
|
||||
<Tooltip @click="fetch">
|
||||
<template #title>刷新</template>
|
||||
<Button><RedoOutlined /></Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<template #renderItem="{ item }">
|
||||
<ListItem>
|
||||
<Card>
|
||||
<template #title></template>
|
||||
<template #cover>
|
||||
<div :class="height">
|
||||
<Image :src="item.imgs[0]" />
|
||||
</div>
|
||||
</template>
|
||||
<template class="ant-card-actions" #actions>
|
||||
<!-- <SettingOutlined key="setting" />-->
|
||||
<EditOutlined key="edit" />
|
||||
<Dropdown
|
||||
:trigger="['hover']"
|
||||
:dropMenuList="[
|
||||
{
|
||||
text: '删除',
|
||||
event: '1',
|
||||
|
@ -54,125 +43,120 @@
|
|||
},
|
||||
},
|
||||
]"
|
||||
popconfirm
|
||||
>
|
||||
<EllipsisOutlined key="ellipsis" />
|
||||
</Dropdown>
|
||||
</template>
|
||||
popconfirm
|
||||
>
|
||||
<EllipsisOutlined key="ellipsis" />
|
||||
</Dropdown>
|
||||
</template>
|
||||
|
||||
<CardMeta>
|
||||
<template #title>
|
||||
<TypographyText :content="item.name" :ellipsis="{ tooltip: item.address }" />
|
||||
</template>
|
||||
<template #avatar>
|
||||
<Avatar :src="item.avatar" />
|
||||
</template>
|
||||
<template #description>{{ item.time }}</template>
|
||||
</CardMeta>
|
||||
</Card>
|
||||
</ListItem>
|
||||
<CardMeta>
|
||||
<template #title>
|
||||
<TypographyText :content="item.name" :ellipsis="{ tooltip: item.address }" />
|
||||
</template>
|
||||
</List>
|
||||
</div>
|
||||
<template #avatar>
|
||||
<Avatar :src="item.avatar" />
|
||||
</template>
|
||||
<template #description>{{ item.time }}</template>
|
||||
</CardMeta>
|
||||
</Card>
|
||||
</ListItem>
|
||||
</template>
|
||||
</List>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import {
|
||||
EditOutlined,
|
||||
EllipsisOutlined,
|
||||
RedoOutlined,
|
||||
TableOutlined,
|
||||
} from '@ant-design/icons-vue';
|
||||
import { List, Card, Image, Typography, Tooltip, Slider, Avatar } from 'ant-design-vue';
|
||||
import { Dropdown } from '/@/components/Dropdown';
|
||||
import { BasicForm, useForm } from '/@/components/Form';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { Button } from '/@/components/Button';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { useSlider, grid } from './data';
|
||||
const ListItem = List.Item;
|
||||
const CardMeta = Card.Meta;
|
||||
const TypographyText = Typography.Text;
|
||||
// 获取slider属性
|
||||
const sliderProp = computed(() => useSlider(4));
|
||||
// 组件接收参数
|
||||
const props = defineProps({
|
||||
// 请求API的参数
|
||||
params: propTypes.object.def({}),
|
||||
//api
|
||||
api: propTypes.func,
|
||||
});
|
||||
//暴露内部方法
|
||||
const emit = defineEmits(['getMethod', 'delete']);
|
||||
//数据
|
||||
const data = ref([]);
|
||||
// 切换每行个数
|
||||
// cover图片自适应高度
|
||||
//修改pageSize并重新请求数据
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { EditOutlined, EllipsisOutlined, RedoOutlined, TableOutlined } from '@ant-design/icons-vue';
|
||||
import { List, Card, Image, Typography, Tooltip, Slider, Avatar } from 'ant-design-vue';
|
||||
import { Dropdown } from '/@/components/Dropdown';
|
||||
import { BasicForm, useForm } from '/@/components/Form';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { Button } from '/@/components/Button';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { useSlider, grid } from './data';
|
||||
const ListItem = List.Item;
|
||||
const CardMeta = Card.Meta;
|
||||
const TypographyText = Typography.Text;
|
||||
// 获取slider属性
|
||||
const sliderProp = computed(() => useSlider(4));
|
||||
// 组件接收参数
|
||||
const props = defineProps({
|
||||
// 请求API的参数
|
||||
params: propTypes.object.def({}),
|
||||
//api
|
||||
api: propTypes.func,
|
||||
});
|
||||
//暴露内部方法
|
||||
const emit = defineEmits(['getMethod', 'delete']);
|
||||
//数据
|
||||
const data = ref([]);
|
||||
// 切换每行个数
|
||||
// cover图片自适应高度
|
||||
//修改pageSize并重新请求数据
|
||||
|
||||
const height = computed(() => {
|
||||
return `h-${120 - grid.value * 6}`;
|
||||
});
|
||||
//表单
|
||||
const [registerForm, { validate }] = useForm({
|
||||
schemas: [{ field: 'type', component: 'Input', label: '类型' }],
|
||||
labelWidth: 80,
|
||||
baseColProps: { span: 6 },
|
||||
actionColOptions: { span: 24 },
|
||||
autoSubmitOnEnter: true,
|
||||
submitFunc: handleSubmit,
|
||||
});
|
||||
//表单提交
|
||||
async function handleSubmit() {
|
||||
const data = await validate();
|
||||
await fetch(data);
|
||||
}
|
||||
function sliderChange(n) {
|
||||
pageSize.value = n * 4;
|
||||
fetch();
|
||||
}
|
||||
const height = computed(() => {
|
||||
return `h-${120 - grid.value * 6}`;
|
||||
});
|
||||
//表单
|
||||
const [registerForm, { validate }] = useForm({
|
||||
schemas: [{ field: 'type', component: 'Input', label: '类型' }],
|
||||
labelWidth: 80,
|
||||
baseColProps: { span: 6 },
|
||||
actionColOptions: { span: 24 },
|
||||
autoSubmitOnEnter: true,
|
||||
submitFunc: handleSubmit,
|
||||
});
|
||||
//表单提交
|
||||
async function handleSubmit() {
|
||||
const data = await validate();
|
||||
await fetch(data);
|
||||
}
|
||||
function sliderChange(n) {
|
||||
pageSize.value = n * 4;
|
||||
fetch();
|
||||
}
|
||||
|
||||
// 自动请求并暴露内部方法
|
||||
onMounted(() => {
|
||||
fetch();
|
||||
emit('getMethod', fetch);
|
||||
});
|
||||
// 自动请求并暴露内部方法
|
||||
onMounted(() => {
|
||||
fetch();
|
||||
emit('getMethod', fetch);
|
||||
});
|
||||
|
||||
async function fetch(p = {}) {
|
||||
const { api, params } = props;
|
||||
if (api && isFunction(api)) {
|
||||
const res = await api({ ...params, page: page.value, pageSize: pageSize.value, ...p });
|
||||
data.value = res.items;
|
||||
total.value = res.total;
|
||||
}
|
||||
async function fetch(p = {}) {
|
||||
const { api, params } = props;
|
||||
if (api && isFunction(api)) {
|
||||
const res = await api({ ...params, page: page.value, pageSize: pageSize.value, ...p });
|
||||
data.value = res.items;
|
||||
total.value = res.total;
|
||||
}
|
||||
//分页相关
|
||||
const page = ref(1);
|
||||
const pageSize = ref(36);
|
||||
const total = ref(0);
|
||||
const paginationProp = ref({
|
||||
showSizeChanger: false,
|
||||
showQuickJumper: true,
|
||||
pageSize,
|
||||
current: page,
|
||||
total,
|
||||
showTotal: (total) => `总 ${total} 条`,
|
||||
onChange: pageChange,
|
||||
onShowSizeChange: pageSizeChange,
|
||||
});
|
||||
}
|
||||
//分页相关
|
||||
const page = ref(1);
|
||||
const pageSize = ref(36);
|
||||
const total = ref(0);
|
||||
const paginationProp = ref({
|
||||
showSizeChanger: false,
|
||||
showQuickJumper: true,
|
||||
pageSize,
|
||||
current: page,
|
||||
total,
|
||||
showTotal: (total) => `总 ${total} 条`,
|
||||
onChange: pageChange,
|
||||
onShowSizeChange: pageSizeChange,
|
||||
});
|
||||
|
||||
function pageChange(p, pz) {
|
||||
page.value = p;
|
||||
pageSize.value = pz;
|
||||
fetch();
|
||||
}
|
||||
function pageSizeChange(current, size) {
|
||||
pageSize.value = size;
|
||||
fetch();
|
||||
}
|
||||
function pageChange(p, pz) {
|
||||
page.value = p;
|
||||
pageSize.value = pz;
|
||||
fetch();
|
||||
}
|
||||
function pageSizeChange(current, size) {
|
||||
pageSize.value = size;
|
||||
fetch();
|
||||
}
|
||||
|
||||
async function handleDelete(id) {
|
||||
emit('delete', id);
|
||||
}
|
||||
async function handleDelete(id) {
|
||||
emit('delete', id);
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
<template>
|
||||
<div class="h-full">
|
||||
<CodeMirrorEditor
|
||||
:value="getValue"
|
||||
@change="handleValueChange"
|
||||
:mode="mode"
|
||||
:readonly="readonly"
|
||||
/>
|
||||
<CodeMirrorEditor :value="getValue" @change="handleValueChange" :mode="mode" :readonly="readonly" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -32,15 +32,15 @@
|
|||
const appStore = useAppStore();
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
async (value) => {
|
||||
await nextTick();
|
||||
const oldValue = editor?.getValue();
|
||||
if (value !== oldValue) {
|
||||
editor?.setValue(value ? value : '');
|
||||
}
|
||||
},
|
||||
{ flush: 'post' }
|
||||
() => props.value,
|
||||
async (value) => {
|
||||
await nextTick();
|
||||
const oldValue = editor?.getValue();
|
||||
if (value !== oldValue) {
|
||||
editor?.setValue(value ? value : '');
|
||||
}
|
||||
},
|
||||
{ flush: 'post' }
|
||||
);
|
||||
|
||||
watchEffect(() => {
|
||||
|
@ -48,20 +48,17 @@
|
|||
});
|
||||
|
||||
watch(
|
||||
() => appStore.getDarkMode,
|
||||
async () => {
|
||||
setTheme();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
() => appStore.getDarkMode,
|
||||
async () => {
|
||||
setTheme();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
function setTheme() {
|
||||
unref(editor)?.setOption(
|
||||
'theme',
|
||||
appStore.getDarkMode === 'light' ? 'idea' : 'material-palenight'
|
||||
);
|
||||
unref(editor)?.setOption('theme', appStore.getDarkMode === 'light' ? 'idea' : 'material-palenight');
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
<template>
|
||||
<transition-group
|
||||
class="h-full w-full"
|
||||
v-bind="$attrs"
|
||||
ref="elRef"
|
||||
:name="transitionName"
|
||||
:tag="tag"
|
||||
mode="out-in"
|
||||
>
|
||||
<transition-group class="h-full w-full" v-bind="$attrs" ref="elRef" :name="transitionName" :tag="tag" mode="out-in">
|
||||
<div key="component" v-if="isInit">
|
||||
<slot :loading="loading"></slot>
|
||||
</div>
|
||||
|
|
|
@ -1,207 +1,196 @@
|
|||
<script lang="tsx">
|
||||
import type { ContextMenuItem, ItemContentProps, Axis } from './typing';
|
||||
import type { FunctionalComponent, CSSProperties } from 'vue';
|
||||
import { defineComponent, nextTick, onMounted, computed, ref, unref, onUnmounted } from 'vue';
|
||||
import Icon from '/@/components/Icon';
|
||||
import { Menu, Divider } from 'ant-design-vue';
|
||||
import type { ContextMenuItem, ItemContentProps, Axis } from './typing';
|
||||
import type { FunctionalComponent, CSSProperties } from 'vue';
|
||||
import { defineComponent, nextTick, onMounted, computed, ref, unref, onUnmounted } from 'vue';
|
||||
import Icon from '/@/components/Icon';
|
||||
import { Menu, Divider } from 'ant-design-vue';
|
||||
|
||||
const prefixCls = 'context-menu';
|
||||
const prefixCls = 'context-menu';
|
||||
|
||||
const props = {
|
||||
width: { type: Number, default: 156 },
|
||||
customEvent: { type: Object as PropType<Event>, default: null },
|
||||
styles: { type: Object as PropType<CSSProperties> },
|
||||
showIcon: { type: Boolean, default: true },
|
||||
axis: {
|
||||
// The position of the right mouse button click
|
||||
type: Object as PropType<Axis>,
|
||||
default() {
|
||||
return { x: 0, y: 0 };
|
||||
},
|
||||
},
|
||||
items: {
|
||||
// The most important list, if not, will not be displayed
|
||||
type: Array as PropType<ContextMenuItem[]>,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
};
|
||||
const props = {
|
||||
width: { type: Number, default: 156 },
|
||||
customEvent: { type: Object as PropType<Event>, default: null },
|
||||
styles: { type: Object as PropType<CSSProperties> },
|
||||
showIcon: { type: Boolean, default: true },
|
||||
axis: {
|
||||
// The position of the right mouse button click
|
||||
type: Object as PropType<Axis>,
|
||||
default() {
|
||||
return { x: 0, y: 0 };
|
||||
},
|
||||
},
|
||||
items: {
|
||||
// The most important list, if not, will not be displayed
|
||||
type: Array as PropType<ContextMenuItem[]>,
|
||||
default() {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const ItemContent: FunctionalComponent<ItemContentProps> = (props) => {
|
||||
const { item } = props;
|
||||
return (
|
||||
<span
|
||||
style="display: inline-block; width: 100%; "
|
||||
class="px-4"
|
||||
onClick={props.handler.bind(null, item)}
|
||||
>
|
||||
const ItemContent: FunctionalComponent<ItemContentProps> = (props) => {
|
||||
const { item } = props;
|
||||
return (
|
||||
<span style="display: inline-block; width: 100%; " class="px-4" onClick={props.handler.bind(null, item)}>
|
||||
{props.showIcon && item.icon && <Icon class="mr-2" icon={item.icon} />}
|
||||
<span>{item.label}</span>
|
||||
<span>{item.label}</span>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ContextMenu',
|
||||
props,
|
||||
setup(props) {
|
||||
const wrapRef = ref(null);
|
||||
const showRef = ref(false);
|
||||
|
||||
const getStyle = computed((): CSSProperties => {
|
||||
const { axis, items, styles, width } = props;
|
||||
const { x, y } = axis || { x: 0, y: 0 };
|
||||
const menuHeight = (items || []).length * 40;
|
||||
const menuWidth = width;
|
||||
const body = document.body;
|
||||
|
||||
const left = body.clientWidth < x + menuWidth ? x - menuWidth : x;
|
||||
const top = body.clientHeight < y + menuHeight ? y - menuHeight : y;
|
||||
return {
|
||||
...styles,
|
||||
width: `${width}px`,
|
||||
left: `${left + 1}px`,
|
||||
top: `${top + 1}px`,
|
||||
};
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => (showRef.value = true));
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
const el = unref(wrapRef);
|
||||
el && document.body.removeChild(el);
|
||||
});
|
||||
|
||||
function handleAction(item: ContextMenuItem, e: MouseEvent) {
|
||||
const { handler, disabled } = item;
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
showRef.value = false;
|
||||
e?.stopPropagation();
|
||||
e?.preventDefault();
|
||||
handler?.();
|
||||
}
|
||||
|
||||
function renderMenuItem(items: ContextMenuItem[]) {
|
||||
return items.map((item) => {
|
||||
const { disabled, label, children, divider = false } = item;
|
||||
|
||||
const contentProps = {
|
||||
item,
|
||||
handler: handleAction,
|
||||
showIcon: props.showIcon,
|
||||
};
|
||||
|
||||
if (!children || children.length === 0) {
|
||||
return (
|
||||
<>
|
||||
<Menu.Item disabled={disabled} class={`${prefixCls}__item`} key={label}>
|
||||
<ItemContent {...contentProps} />
|
||||
</Menu.Item>
|
||||
{divider ? <Divider key={`d-${label}`} /> : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (!unref(showRef)) return null;
|
||||
|
||||
return (
|
||||
<Menu.SubMenu key={label} disabled={disabled} popupClassName={`${prefixCls}__popup`}>
|
||||
{{
|
||||
title: () => <ItemContent {...contentProps} />,
|
||||
default: () => renderMenuItem(children),
|
||||
}}
|
||||
</Menu.SubMenu>
|
||||
);
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
if (!unref(showRef)) {
|
||||
return null;
|
||||
}
|
||||
const { items } = props;
|
||||
return (
|
||||
<Menu inlineIndent={12} mode="vertical" class={prefixCls} ref={wrapRef} style={unref(getStyle)}>
|
||||
{renderMenuItem(items)}
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ContextMenu',
|
||||
props,
|
||||
setup(props) {
|
||||
const wrapRef = ref(null);
|
||||
const showRef = ref(false);
|
||||
|
||||
const getStyle = computed((): CSSProperties => {
|
||||
const { axis, items, styles, width } = props;
|
||||
const { x, y } = axis || { x: 0, y: 0 };
|
||||
const menuHeight = (items || []).length * 40;
|
||||
const menuWidth = width;
|
||||
const body = document.body;
|
||||
|
||||
const left = body.clientWidth < x + menuWidth ? x - menuWidth : x;
|
||||
const top = body.clientHeight < y + menuHeight ? y - menuHeight : y;
|
||||
return {
|
||||
...styles,
|
||||
width: `${width}px`,
|
||||
left: `${left + 1}px`,
|
||||
top: `${top + 1}px`,
|
||||
};
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => (showRef.value = true));
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
const el = unref(wrapRef);
|
||||
el && document.body.removeChild(el);
|
||||
});
|
||||
|
||||
function handleAction(item: ContextMenuItem, e: MouseEvent) {
|
||||
const { handler, disabled } = item;
|
||||
if (disabled) {
|
||||
return;
|
||||
}
|
||||
showRef.value = false;
|
||||
e?.stopPropagation();
|
||||
e?.preventDefault();
|
||||
handler?.();
|
||||
}
|
||||
|
||||
function renderMenuItem(items: ContextMenuItem[]) {
|
||||
return items.map((item) => {
|
||||
const { disabled, label, children, divider = false } = item;
|
||||
|
||||
const contentProps = {
|
||||
item,
|
||||
handler: handleAction,
|
||||
showIcon: props.showIcon,
|
||||
};
|
||||
|
||||
if (!children || children.length === 0) {
|
||||
return (
|
||||
<>
|
||||
<Menu.Item disabled={disabled} class={`${prefixCls}__item`} key={label}>
|
||||
<ItemContent {...contentProps} />
|
||||
</Menu.Item>
|
||||
{divider ? <Divider key={`d-${label}`} /> : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (!unref(showRef)) return null;
|
||||
|
||||
return (
|
||||
<Menu.SubMenu key={label} disabled={disabled} popupClassName={`${prefixCls}__popup`}>
|
||||
{{
|
||||
title: () => <ItemContent {...contentProps} />,
|
||||
default: () => renderMenuItem(children),
|
||||
}}
|
||||
</Menu.SubMenu>
|
||||
);
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
if (!unref(showRef)) {
|
||||
return null;
|
||||
}
|
||||
const { items } = props;
|
||||
return (
|
||||
<Menu
|
||||
inlineIndent={12}
|
||||
mode="vertical"
|
||||
class={prefixCls}
|
||||
ref={wrapRef}
|
||||
style={unref(getStyle)}
|
||||
>
|
||||
{renderMenuItem(items)}
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@default-height: 42px !important;
|
||||
@default-height: 42px !important;
|
||||
|
||||
@small-height: 36px !important;
|
||||
@small-height: 36px !important;
|
||||
|
||||
@large-height: 36px !important;
|
||||
@large-height: 36px !important;
|
||||
|
||||
.item-style() {
|
||||
li {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: @default-height;
|
||||
margin: 0 !important;
|
||||
line-height: @default-height;
|
||||
.item-style() {
|
||||
li {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: @default-height;
|
||||
margin: 0 !important;
|
||||
line-height: @default-height;
|
||||
|
||||
span {
|
||||
line-height: @default-height;
|
||||
}
|
||||
span {
|
||||
line-height: @default-height;
|
||||
}
|
||||
|
||||
> div {
|
||||
margin: 0 !important;
|
||||
}
|
||||
> div {
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
&:not(.ant-menu-item-disabled):hover {
|
||||
color: @text-color-base;
|
||||
background-color: @item-hover-bg;
|
||||
}
|
||||
}
|
||||
&:not(.ant-menu-item-disabled):hover {
|
||||
color: @text-color-base;
|
||||
background-color: @item-hover-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 200;
|
||||
display: block;
|
||||
width: 156px;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
background-color: @component-background;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-radius: 0.25rem;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.1), 0 1px 5px 0 rgba(0, 0, 0, 0.06);
|
||||
background-clip: padding-box;
|
||||
user-select: none;
|
||||
|
||||
.item-style();
|
||||
|
||||
.ant-divider {
|
||||
margin: 0 0;
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 200;
|
||||
display: block;
|
||||
width: 156px;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
background-color: @component-background;
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-radius: 0.25rem;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.1),
|
||||
0 1px 5px 0 rgba(0, 0, 0, 0.06);
|
||||
background-clip: padding-box;
|
||||
user-select: none;
|
||||
&__popup {
|
||||
.ant-divider {
|
||||
margin: 0 0;
|
||||
}
|
||||
|
||||
.item-style();
|
||||
|
||||
.ant-divider {
|
||||
margin: 0 0;
|
||||
}
|
||||
|
||||
&__popup {
|
||||
.ant-divider {
|
||||
margin: 0 0;
|
||||
}
|
||||
|
||||
.item-style();
|
||||
}
|
||||
|
||||
.ant-menu-submenu-title,
|
||||
.ant-menu-item {
|
||||
padding: 0 !important;
|
||||
}
|
||||
.item-style();
|
||||
}
|
||||
|
||||
.ant-menu-submenu-title,
|
||||
.ant-menu-item {
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -30,9 +30,7 @@
|
|||
const { t } = useI18n();
|
||||
|
||||
const getButtonText = computed(() => {
|
||||
return !unref(isStart)
|
||||
? t('component.countdown.normalText')
|
||||
: t('component.countdown.sendText', [unref(currentCount)]);
|
||||
return !unref(isStart) ? t('component.countdown.normalText') : t('component.countdown.sendText', [unref(currentCount)]);
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
|
|
|
@ -1,283 +1,214 @@
|
|||
<template>
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
@register="register"
|
||||
:title="t('component.cropper.modalTitle')"
|
||||
width="800px"
|
||||
:canFullscreen="false"
|
||||
@ok="handleOk"
|
||||
:okText="t('component.cropper.okText')"
|
||||
>
|
||||
<div :class="prefixCls">
|
||||
<div :class="`${prefixCls}-left`">
|
||||
<div :class="`${prefixCls}-cropper`">
|
||||
<CropperImage
|
||||
v-if="src"
|
||||
:src="src"
|
||||
height="300px"
|
||||
:circled="circled"
|
||||
@cropend="handleCropend"
|
||||
@ready="handleReady"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div :class="`${prefixCls}-toolbar`">
|
||||
<Upload :fileList="[]" accept="image/*" :beforeUpload="handleBeforeUpload">
|
||||
<Tooltip :title="t('component.cropper.selectImage')" placement="bottom">
|
||||
<a-button size="small" preIcon="ant-design:upload-outlined" type="primary" />
|
||||
</Tooltip>
|
||||
</Upload>
|
||||
<Space>
|
||||
<Tooltip :title="t('component.cropper.btn_reset')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:reload-outlined"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('reset')"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_rotate_left')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:rotate-left-outlined"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('rotate', -45)"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_rotate_right')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:rotate-right-outlined"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('rotate', 45)"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_scale_x')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="vaadin:arrows-long-h"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('scaleX')"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_scale_y')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="vaadin:arrows-long-v"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('scaleY')"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_zoom_in')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:zoom-in-outlined"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('zoom', 0.1)"
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_zoom_out')" placement="bottom">
|
||||
<a-button
|
||||
type="primary"
|
||||
preIcon="ant-design:zoom-out-outlined"
|
||||
size="small"
|
||||
:disabled="!src"
|
||||
@click="handlerToolbar('zoom', -0.1)"
|
||||
/>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`${prefixCls}-right`">
|
||||
<div :class="`${prefixCls}-preview`">
|
||||
<img :src="previewSource" v-if="previewSource" :alt="t('component.cropper.preview')" />
|
||||
</div>
|
||||
<template v-if="previewSource">
|
||||
<div :class="`${prefixCls}-group`">
|
||||
<Avatar :src="previewSource" size="large" />
|
||||
<Avatar :src="previewSource" :size="48" />
|
||||
<Avatar :src="previewSource" :size="64" />
|
||||
<Avatar :src="previewSource" :size="80" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<BasicModal v-bind="$attrs" @register="register" :title="t('component.cropper.modalTitle')" width="800px" :canFullscreen="false" @ok="handleOk" :okText="t('component.cropper.okText')">
|
||||
<div :class="prefixCls">
|
||||
<div :class="`${prefixCls}-left`">
|
||||
<div :class="`${prefixCls}-cropper`">
|
||||
<CropperImage v-if="src" :src="src" height="300px" :circled="circled" @cropend="handleCropend" @ready="handleReady" />
|
||||
</div>
|
||||
</BasicModal>
|
||||
|
||||
<div :class="`${prefixCls}-toolbar`">
|
||||
<Upload :fileList="[]" accept="image/*" :beforeUpload="handleBeforeUpload">
|
||||
<Tooltip :title="t('component.cropper.selectImage')" placement="bottom">
|
||||
<a-button size="small" preIcon="ant-design:upload-outlined" type="primary" />
|
||||
</Tooltip>
|
||||
</Upload>
|
||||
<Space>
|
||||
<Tooltip :title="t('component.cropper.btn_reset')" placement="bottom">
|
||||
<a-button type="primary" preIcon="ant-design:reload-outlined" size="small" :disabled="!src" @click="handlerToolbar('reset')" />
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_rotate_left')" placement="bottom">
|
||||
<a-button type="primary" preIcon="ant-design:rotate-left-outlined" size="small" :disabled="!src" @click="handlerToolbar('rotate', -45)" />
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_rotate_right')" placement="bottom">
|
||||
<a-button type="primary" preIcon="ant-design:rotate-right-outlined" size="small" :disabled="!src" @click="handlerToolbar('rotate', 45)" />
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_scale_x')" placement="bottom">
|
||||
<a-button type="primary" preIcon="vaadin:arrows-long-h" size="small" :disabled="!src" @click="handlerToolbar('scaleX')" />
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_scale_y')" placement="bottom">
|
||||
<a-button type="primary" preIcon="vaadin:arrows-long-v" size="small" :disabled="!src" @click="handlerToolbar('scaleY')" />
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_zoom_in')" placement="bottom">
|
||||
<a-button type="primary" preIcon="ant-design:zoom-in-outlined" size="small" :disabled="!src" @click="handlerToolbar('zoom', 0.1)" />
|
||||
</Tooltip>
|
||||
<Tooltip :title="t('component.cropper.btn_zoom_out')" placement="bottom">
|
||||
<a-button type="primary" preIcon="ant-design:zoom-out-outlined" size="small" :disabled="!src" @click="handlerToolbar('zoom', -0.1)" />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="`${prefixCls}-right`">
|
||||
<div :class="`${prefixCls}-preview`">
|
||||
<img :src="previewSource" v-if="previewSource" :alt="t('component.cropper.preview')" />
|
||||
</div>
|
||||
<template v-if="previewSource">
|
||||
<div :class="`${prefixCls}-group`">
|
||||
<Avatar :src="previewSource" size="large" />
|
||||
<Avatar :src="previewSource" :size="48" />
|
||||
<Avatar :src="previewSource" :size="64" />
|
||||
<Avatar :src="previewSource" :size="80" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { CropendResult, Cropper } from './typing';
|
||||
import type { CropendResult, Cropper } from './typing';
|
||||
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import CropperImage from './Cropper.vue';
|
||||
import { Space, Upload, Avatar, Tooltip } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { dataURLtoBlob } from '/@/utils/file/base64Conver';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import CropperImage from './Cropper.vue';
|
||||
import { Space, Upload, Avatar, Tooltip } from 'ant-design-vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { dataURLtoBlob } from '/@/utils/file/base64Conver';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
type apiFunParams = { file: Blob; name: string; filename: string };
|
||||
type apiFunParams = { file: Blob; name: string; filename: string };
|
||||
|
||||
const props = {
|
||||
circled: { type: Boolean, default: true },
|
||||
uploadApi: {
|
||||
type: Function as PropType<(params: apiFunParams) => Promise<any>>,
|
||||
},
|
||||
};
|
||||
const props = {
|
||||
circled: { type: Boolean, default: true },
|
||||
uploadApi: {
|
||||
type: Function as PropType<(params: apiFunParams) => Promise<any>>,
|
||||
},
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CropperModal',
|
||||
components: { BasicModal, Space, CropperImage, Upload, Avatar, Tooltip },
|
||||
props,
|
||||
emits: ['uploadSuccess', 'register'],
|
||||
setup(props, { emit }) {
|
||||
let filename = '';
|
||||
const src = ref('');
|
||||
const previewSource = ref('');
|
||||
const cropper = ref<Cropper>();
|
||||
let scaleX = 1;
|
||||
let scaleY = 1;
|
||||
export default defineComponent({
|
||||
name: 'CropperModal',
|
||||
components: { BasicModal, Space, CropperImage, Upload, Avatar, Tooltip },
|
||||
props,
|
||||
emits: ['uploadSuccess', 'register'],
|
||||
setup(props, { emit }) {
|
||||
let filename = '';
|
||||
const src = ref('');
|
||||
const previewSource = ref('');
|
||||
const cropper = ref<Cropper>();
|
||||
let scaleX = 1;
|
||||
let scaleY = 1;
|
||||
|
||||
const { prefixCls } = useDesign('cropper-am');
|
||||
const [register, { closeModal, setModalProps }] = useModalInner();
|
||||
const { t } = useI18n();
|
||||
const { prefixCls } = useDesign('cropper-am');
|
||||
const [register, { closeModal, setModalProps }] = useModalInner();
|
||||
const { t } = useI18n();
|
||||
|
||||
// Block upload
|
||||
function handleBeforeUpload(file: File) {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
src.value = '';
|
||||
previewSource.value = '';
|
||||
reader.onload = function (e) {
|
||||
src.value = (e.target?.result as string) ?? '';
|
||||
filename = file.name;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
// Block upload
|
||||
function handleBeforeUpload(file: File) {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
src.value = '';
|
||||
previewSource.value = '';
|
||||
reader.onload = function (e) {
|
||||
src.value = (e.target?.result as string) ?? '';
|
||||
filename = file.name;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleCropend({ imgBase64 }: CropendResult) {
|
||||
previewSource.value = imgBase64;
|
||||
}
|
||||
function handleCropend({ imgBase64 }: CropendResult) {
|
||||
previewSource.value = imgBase64;
|
||||
}
|
||||
|
||||
function handleReady(cropperInstance: Cropper) {
|
||||
cropper.value = cropperInstance;
|
||||
}
|
||||
function handleReady(cropperInstance: Cropper) {
|
||||
cropper.value = cropperInstance;
|
||||
}
|
||||
|
||||
function handlerToolbar(event: string, arg?: number) {
|
||||
if (event === 'scaleX') {
|
||||
scaleX = arg = scaleX === -1 ? 1 : -1;
|
||||
}
|
||||
if (event === 'scaleY') {
|
||||
scaleY = arg = scaleY === -1 ? 1 : -1;
|
||||
}
|
||||
cropper?.value?.[event]?.(arg);
|
||||
}
|
||||
function handlerToolbar(event: string, arg?: number) {
|
||||
if (event === 'scaleX') {
|
||||
scaleX = arg = scaleX === -1 ? 1 : -1;
|
||||
}
|
||||
if (event === 'scaleY') {
|
||||
scaleY = arg = scaleY === -1 ? 1 : -1;
|
||||
}
|
||||
cropper?.value?.[event]?.(arg);
|
||||
}
|
||||
|
||||
async function handleOk() {
|
||||
const uploadApi = props.uploadApi;
|
||||
if (uploadApi && isFunction(uploadApi)) {
|
||||
const blob = dataURLtoBlob(previewSource.value);
|
||||
try {
|
||||
setModalProps({ confirmLoading: true });
|
||||
const result = await uploadApi({ name: 'file', file: blob, filename });
|
||||
emit('uploadSuccess', { source: previewSource.value, data: result.data || result.message });
|
||||
closeModal();
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
async function handleOk() {
|
||||
const uploadApi = props.uploadApi;
|
||||
if (uploadApi && isFunction(uploadApi)) {
|
||||
const blob = dataURLtoBlob(previewSource.value);
|
||||
try {
|
||||
setModalProps({ confirmLoading: true });
|
||||
const result = await uploadApi({ name: 'file', file: blob, filename });
|
||||
emit('uploadSuccess', { source: previewSource.value, data: result.data || result.message });
|
||||
closeModal();
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
t,
|
||||
prefixCls,
|
||||
src,
|
||||
register,
|
||||
previewSource,
|
||||
handleBeforeUpload,
|
||||
handleCropend,
|
||||
handleReady,
|
||||
handlerToolbar,
|
||||
handleOk,
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
t,
|
||||
prefixCls,
|
||||
src,
|
||||
register,
|
||||
previewSource,
|
||||
handleBeforeUpload,
|
||||
handleCropend,
|
||||
handleReady,
|
||||
handlerToolbar,
|
||||
handleOk,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-cropper-am';
|
||||
@prefix-cls: ~'@{namespace}-cropper-am';
|
||||
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
|
||||
&-left,
|
||||
&-right {
|
||||
height: 340px;
|
||||
}
|
||||
|
||||
&-left {
|
||||
width: 55%;
|
||||
}
|
||||
|
||||
&-right {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
&-cropper {
|
||||
height: 300px;
|
||||
background: #eee;
|
||||
background-image: linear-gradient(
|
||||
45deg,
|
||||
rgba(0, 0, 0, 0.25) 25%,
|
||||
transparent 0,
|
||||
transparent 75%,
|
||||
rgba(0, 0, 0, 0.25) 0
|
||||
),
|
||||
linear-gradient(
|
||||
45deg,
|
||||
rgba(0, 0, 0, 0.25) 25%,
|
||||
transparent 0,
|
||||
transparent 75%,
|
||||
rgba(0, 0, 0, 0.25) 0
|
||||
);
|
||||
background-position: 0 0, 12px 12px;
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
|
||||
&-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&-preview {
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
border: 1px solid @border-color-base;
|
||||
border-radius: 50%;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&-group {
|
||||
display: flex;
|
||||
padding-top: 8px;
|
||||
margin-top: 8px;
|
||||
border-top: 1px solid @border-color-base;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
&-left,
|
||||
&-right {
|
||||
height: 340px;
|
||||
}
|
||||
|
||||
&-left {
|
||||
width: 55%;
|
||||
}
|
||||
|
||||
&-right {
|
||||
width: 45%;
|
||||
}
|
||||
|
||||
&-cropper {
|
||||
height: 300px;
|
||||
background: #eee;
|
||||
background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.25) 25%, transparent 0, transparent 75%, rgba(0, 0, 0, 0.25) 0),
|
||||
linear-gradient(45deg, rgba(0, 0, 0, 0.25) 25%, transparent 0, transparent 75%, rgba(0, 0, 0, 0.25) 0);
|
||||
background-position: 0 0, 12px 12px;
|
||||
background-size: 24px 24px;
|
||||
}
|
||||
|
||||
&-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&-preview {
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
border: 1px solid @border-color-base;
|
||||
border-radius: 50%;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&-group {
|
||||
display: flex;
|
||||
padding-top: 8px;
|
||||
margin-top: 8px;
|
||||
border-top: 1px solid @border-color-base;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,188 +1,181 @@
|
|||
<template>
|
||||
<div :class="getClass" :style="getWrapperStyle">
|
||||
<img
|
||||
v-show="isReady"
|
||||
ref="imgElRef"
|
||||
:src="src"
|
||||
:alt="alt"
|
||||
:crossorigin="crossorigin"
|
||||
:style="getImageStyle"
|
||||
/>
|
||||
</div>
|
||||
<div :class="getClass" :style="getWrapperStyle">
|
||||
<img v-show="isReady" ref="imgElRef" :src="src" :alt="alt" :crossorigin="crossorigin" :style="getImageStyle" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type {CSSProperties} from 'vue';
|
||||
import {defineComponent, onMounted, ref, unref, computed, onUnmounted} from 'vue';
|
||||
import Cropper from 'cropperjs';
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
import {useDesign} from '/@/hooks/web/useDesign';
|
||||
import {useDebounceFn} from '@vueuse/shared';
|
||||
import type { CSSProperties } from 'vue';
|
||||
import { defineComponent, onMounted, ref, unref, computed, onUnmounted } from 'vue';
|
||||
import Cropper from 'cropperjs';
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useDebounceFn } from '@vueuse/shared';
|
||||
|
||||
type Options = Cropper.Options;
|
||||
type Options = Cropper.Options;
|
||||
|
||||
const defaultOptions: Options = {
|
||||
aspectRatio: 1,
|
||||
zoomable: true,
|
||||
zoomOnTouch: true,
|
||||
zoomOnWheel: true,
|
||||
cropBoxMovable: true,
|
||||
cropBoxResizable: true,
|
||||
toggleDragModeOnDblclick: true,
|
||||
autoCrop: true,
|
||||
background: true,
|
||||
highlight: true,
|
||||
center: true,
|
||||
responsive: true,
|
||||
restore: true,
|
||||
checkCrossOrigin: true,
|
||||
checkOrientation: true,
|
||||
scalable: true,
|
||||
modal: true,
|
||||
guides: true,
|
||||
movable: true,
|
||||
rotatable: true,
|
||||
};
|
||||
const defaultOptions: Options = {
|
||||
aspectRatio: 1,
|
||||
zoomable: true,
|
||||
zoomOnTouch: true,
|
||||
zoomOnWheel: true,
|
||||
cropBoxMovable: true,
|
||||
cropBoxResizable: true,
|
||||
toggleDragModeOnDblclick: true,
|
||||
autoCrop: true,
|
||||
background: true,
|
||||
highlight: true,
|
||||
center: true,
|
||||
responsive: true,
|
||||
restore: true,
|
||||
checkCrossOrigin: true,
|
||||
checkOrientation: true,
|
||||
scalable: true,
|
||||
modal: true,
|
||||
guides: true,
|
||||
movable: true,
|
||||
rotatable: true,
|
||||
};
|
||||
|
||||
const props = {
|
||||
src: {type: String, required: true},
|
||||
alt: {type: String},
|
||||
circled: {type: Boolean, default: false},
|
||||
realTimePreview: {type: Boolean, default: true},
|
||||
height: {type: [String, Number], default: '360px'},
|
||||
crossorigin: {
|
||||
type: String as PropType<'' | 'anonymous' | 'use-credentials' | undefined>,
|
||||
default: undefined,
|
||||
},
|
||||
imageStyle: {type: Object as PropType<CSSProperties>, default: () => ({})},
|
||||
options: {type: Object as PropType<Options>, default: () => ({})},
|
||||
};
|
||||
const props = {
|
||||
src: { type: String, required: true },
|
||||
alt: { type: String },
|
||||
circled: { type: Boolean, default: false },
|
||||
realTimePreview: { type: Boolean, default: true },
|
||||
height: { type: [String, Number], default: '360px' },
|
||||
crossorigin: {
|
||||
type: String as PropType<'' | 'anonymous' | 'use-credentials' | undefined>,
|
||||
default: undefined,
|
||||
},
|
||||
imageStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
|
||||
options: { type: Object as PropType<Options>, default: () => ({}) },
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CropperImage',
|
||||
props,
|
||||
emits: ['cropend', 'ready', 'cropendError'],
|
||||
setup(props, {attrs, emit}) {
|
||||
const imgElRef = ref<ElRef<HTMLImageElement>>();
|
||||
const cropper = ref<Nullable<Cropper>>();
|
||||
const isReady = ref(false);
|
||||
export default defineComponent({
|
||||
name: 'CropperImage',
|
||||
props,
|
||||
emits: ['cropend', 'ready', 'cropendError'],
|
||||
setup(props, { attrs, emit }) {
|
||||
const imgElRef = ref<ElRef<HTMLImageElement>>();
|
||||
const cropper = ref<Nullable<Cropper>>();
|
||||
const isReady = ref(false);
|
||||
|
||||
const {prefixCls} = useDesign('cropper-image');
|
||||
const debounceRealTimeCroppered = useDebounceFn(realTimeCroppered, 80);
|
||||
const { prefixCls } = useDesign('cropper-image');
|
||||
const debounceRealTimeCroppered = useDebounceFn(realTimeCroppered, 80);
|
||||
|
||||
const getImageStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
height: props.height,
|
||||
maxWidth: '100%',
|
||||
...props.imageStyle,
|
||||
};
|
||||
const getImageStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
height: props.height,
|
||||
maxWidth: '100%',
|
||||
...props.imageStyle,
|
||||
};
|
||||
});
|
||||
|
||||
const getClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
attrs.class,
|
||||
{
|
||||
[`${prefixCls}--circled`]: props.circled,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
const getWrapperStyle = computed((): CSSProperties => {
|
||||
return { height: `${props.height}`.replace(/px/, '') + 'px' };
|
||||
});
|
||||
|
||||
onMounted(init);
|
||||
|
||||
onUnmounted(() => {
|
||||
cropper.value?.destroy();
|
||||
});
|
||||
|
||||
async function init() {
|
||||
const imgEl = unref(imgElRef);
|
||||
if (!imgEl) {
|
||||
return;
|
||||
}
|
||||
cropper.value = new Cropper(imgEl, {
|
||||
...defaultOptions,
|
||||
ready: () => {
|
||||
isReady.value = true;
|
||||
realTimeCroppered();
|
||||
emit('ready', cropper.value);
|
||||
},
|
||||
crop() {
|
||||
debounceRealTimeCroppered();
|
||||
},
|
||||
zoom() {
|
||||
debounceRealTimeCroppered();
|
||||
},
|
||||
cropmove() {
|
||||
debounceRealTimeCroppered();
|
||||
},
|
||||
...props.options,
|
||||
});
|
||||
}
|
||||
|
||||
// Real-time display preview
|
||||
function realTimeCroppered() {
|
||||
props.realTimePreview && croppered();
|
||||
}
|
||||
|
||||
// event: return base64 and width and height information after cropping
|
||||
function croppered() {
|
||||
if (!cropper.value) {
|
||||
return;
|
||||
}
|
||||
let imgInfo = cropper.value.getData();
|
||||
const canvas = props.circled ? getRoundedCanvas() : cropper.value.getCroppedCanvas();
|
||||
canvas.toBlob((blob) => {
|
||||
if (!blob) {
|
||||
return;
|
||||
}
|
||||
let fileReader: FileReader = new FileReader();
|
||||
fileReader.readAsDataURL(blob);
|
||||
fileReader.onloadend = (e) => {
|
||||
emit('cropend', {
|
||||
imgBase64: e.target?.result ?? '',
|
||||
imgInfo,
|
||||
});
|
||||
};
|
||||
fileReader.onerror = () => {
|
||||
emit('cropendError');
|
||||
};
|
||||
}, 'image/png');
|
||||
}
|
||||
|
||||
const getClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
attrs.class,
|
||||
{
|
||||
[`${prefixCls}--circled`]: props.circled,
|
||||
},
|
||||
];
|
||||
});
|
||||
// Get a circular picture canvas
|
||||
function getRoundedCanvas() {
|
||||
const sourceCanvas = cropper.value!.getCroppedCanvas();
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d')!;
|
||||
const width = sourceCanvas.width;
|
||||
const height = sourceCanvas.height;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
context.imageSmoothingEnabled = true;
|
||||
context.drawImage(sourceCanvas, 0, 0, width, height);
|
||||
context.globalCompositeOperation = 'destination-in';
|
||||
context.beginPath();
|
||||
context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI, true);
|
||||
context.fill();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
const getWrapperStyle = computed((): CSSProperties => {
|
||||
return {height: `${props.height}`.replace(/px/, '') + 'px'};
|
||||
});
|
||||
|
||||
onMounted(init);
|
||||
|
||||
onUnmounted(() => {
|
||||
cropper.value?.destroy();
|
||||
});
|
||||
|
||||
async function init() {
|
||||
const imgEl = unref(imgElRef);
|
||||
if (!imgEl) {
|
||||
return;
|
||||
}
|
||||
cropper.value = new Cropper(imgEl, {
|
||||
...defaultOptions,
|
||||
ready: () => {
|
||||
isReady.value = true;
|
||||
realTimeCroppered();
|
||||
emit('ready', cropper.value);
|
||||
},
|
||||
crop() {
|
||||
debounceRealTimeCroppered();
|
||||
},
|
||||
zoom() {
|
||||
debounceRealTimeCroppered();
|
||||
},
|
||||
cropmove() {
|
||||
debounceRealTimeCroppered();
|
||||
},
|
||||
...props.options,
|
||||
});
|
||||
}
|
||||
|
||||
// Real-time display preview
|
||||
function realTimeCroppered() {
|
||||
props.realTimePreview && croppered();
|
||||
}
|
||||
|
||||
// event: return base64 and width and height information after cropping
|
||||
function croppered() {
|
||||
if (!cropper.value) {
|
||||
return;
|
||||
}
|
||||
let imgInfo = cropper.value.getData();
|
||||
const canvas = props.circled ? getRoundedCanvas() : cropper.value.getCroppedCanvas();
|
||||
canvas.toBlob((blob) => {
|
||||
if (!blob) {
|
||||
return;
|
||||
}
|
||||
let fileReader: FileReader = new FileReader();
|
||||
fileReader.readAsDataURL(blob);
|
||||
fileReader.onloadend = (e) => {
|
||||
emit('cropend', {
|
||||
imgBase64: e.target?.result ?? '',
|
||||
imgInfo,
|
||||
});
|
||||
};
|
||||
fileReader.onerror = () => {
|
||||
emit('cropendError');
|
||||
};
|
||||
}, 'image/png');
|
||||
}
|
||||
|
||||
// Get a circular picture canvas
|
||||
function getRoundedCanvas() {
|
||||
const sourceCanvas = cropper.value!.getCroppedCanvas();
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d')!;
|
||||
const width = sourceCanvas.width;
|
||||
const height = sourceCanvas.height;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
context.imageSmoothingEnabled = true;
|
||||
context.drawImage(sourceCanvas, 0, 0, width, height);
|
||||
context.globalCompositeOperation = 'destination-in';
|
||||
context.beginPath();
|
||||
context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI, true);
|
||||
context.fill();
|
||||
return canvas;
|
||||
}
|
||||
|
||||
return {getClass, imgElRef, getWrapperStyle, getImageStyle, isReady, croppered};
|
||||
},
|
||||
});
|
||||
return { getClass, imgElRef, getWrapperStyle, getImageStyle, isReady, croppered };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-cropper-image';
|
||||
@prefix-cls: ~'@{namespace}-cropper-image';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&--circled {
|
||||
.cropper-view-box,
|
||||
.cropper-face {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
.@{prefix-cls} {
|
||||
&--circled {
|
||||
.cropper-view-box,
|
||||
.cropper-face {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,43 +2,19 @@
|
|||
<div :class="getClass" :style="getStyle">
|
||||
<div :class="`${prefixCls}-image-wrapper`" :style="getImageWrapperStyle" @click="openModal">
|
||||
<div :class="`${prefixCls}-image-mask`" :style="getImageWrapperStyle">
|
||||
<Icon
|
||||
icon="ant-design:cloud-upload-outlined"
|
||||
:size="getIconWidth"
|
||||
:style="getImageWrapperStyle"
|
||||
color="#d6d6d6"
|
||||
/>
|
||||
<Icon icon="ant-design:cloud-upload-outlined" :size="getIconWidth" :style="getImageWrapperStyle" color="#d6d6d6" />
|
||||
</div>
|
||||
<img :src="sourceValue" v-if="sourceValue" alt="avatar" />
|
||||
</div>
|
||||
<a-button
|
||||
:class="`${prefixCls}-upload-btn`"
|
||||
@click="openModal"
|
||||
v-if="showBtn"
|
||||
v-bind="btnProps"
|
||||
>
|
||||
<a-button :class="`${prefixCls}-upload-btn`" @click="openModal" v-if="showBtn" v-bind="btnProps">
|
||||
{{ btnText ? btnText : t('component.cropper.selectImage') }}
|
||||
</a-button>
|
||||
|
||||
<CopperModal
|
||||
@register="register"
|
||||
@uploadSuccess="handleUploadSuccess"
|
||||
:uploadApi="uploadApi"
|
||||
:src="sourceValue"
|
||||
/>
|
||||
<CopperModal @register="register" @uploadSuccess="handleUploadSuccess" :uploadApi="uploadApi" :src="sourceValue" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {
|
||||
defineComponent,
|
||||
computed,
|
||||
CSSProperties,
|
||||
unref,
|
||||
ref,
|
||||
watchEffect,
|
||||
watch,
|
||||
PropType,
|
||||
} from 'vue';
|
||||
import { defineComponent, computed, CSSProperties, unref, ref, watchEffect, watch, PropType } from 'vue';
|
||||
import CopperModal from './CopperModal.vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
|
@ -76,22 +52,20 @@
|
|||
|
||||
const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) }));
|
||||
|
||||
const getImageWrapperStyle = computed(
|
||||
(): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) })
|
||||
);
|
||||
const getImageWrapperStyle = computed((): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) }));
|
||||
|
||||
watchEffect(() => {
|
||||
sourceValue.value = props.value || '';
|
||||
});
|
||||
|
||||
watch(
|
||||
() => sourceValue.value,
|
||||
(v: string) => {
|
||||
emit('update:value', v);
|
||||
}
|
||||
() => sourceValue.value,
|
||||
(v: string) => {
|
||||
emit('update:value', v);
|
||||
}
|
||||
);
|
||||
|
||||
function handleUploadSuccess({ source,data }) {
|
||||
function handleUploadSuccess({ source, data }) {
|
||||
sourceValue.value = source;
|
||||
emit('change', source, data);
|
||||
createMessage.success(t('component.cropper.uploadSuccess'));
|
||||
|
|
|
@ -12,10 +12,7 @@ export interface DescItem {
|
|||
span?: number;
|
||||
show?: (...arg: any) => boolean;
|
||||
// render
|
||||
render?: (
|
||||
val: any,
|
||||
data: Recordable
|
||||
) => VNode | undefined | JSX.Element | Element | string | number;
|
||||
render?: (val: any, data: Recordable) => VNode | undefined | JSX.Element | Element | string | number;
|
||||
}
|
||||
|
||||
export interface DescriptionProps extends DescriptionsProps {
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
<template>
|
||||
<Drawer :class="prefixCls" @close="onClose" v-bind="getBindValues">
|
||||
<template #title v-if="!$slots.title">
|
||||
<DrawerHeader
|
||||
:title="getMergeProps.title"
|
||||
:isDetail="isDetail"
|
||||
:showDetailBack="showDetailBack"
|
||||
@close="onClose"
|
||||
>
|
||||
<DrawerHeader :title="getMergeProps.title" :isDetail="isDetail" :showDetailBack="showDetailBack" @close="onClose">
|
||||
<template #titleToolbar>
|
||||
<slot name="titleToolbar"></slot>
|
||||
</template>
|
||||
|
@ -16,11 +11,7 @@
|
|||
<slot name="title"></slot>
|
||||
</template>
|
||||
|
||||
<ScrollContainer
|
||||
:style="getScrollContentStyle"
|
||||
v-loading="getLoading"
|
||||
:loading-tip="loadingText || t('common.loadingText')"
|
||||
>
|
||||
<ScrollContainer :style="getScrollContentStyle" v-loading="getLoading" :loading-tip="loadingText || t('common.loadingText')">
|
||||
<slot></slot>
|
||||
</ScrollContainer>
|
||||
<DrawerFooter v-bind="getProps" @close="onClose" @ok="handleOk" :height="getFooterHeight">
|
||||
|
@ -33,16 +24,7 @@
|
|||
<script lang="ts">
|
||||
import type { DrawerInstance, DrawerProps } from './typing';
|
||||
import type { CSSProperties } from 'vue';
|
||||
import {
|
||||
defineComponent,
|
||||
ref,
|
||||
computed,
|
||||
watch,
|
||||
unref,
|
||||
nextTick,
|
||||
toRaw,
|
||||
getCurrentInstance,
|
||||
} from 'vue';
|
||||
import { defineComponent, ref, computed, watch, unref, nextTick, toRaw, getCurrentInstance } from 'vue';
|
||||
import { Drawer } from 'ant-design-vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { isFunction, isNumber } from '/@/utils/is';
|
||||
|
@ -115,9 +97,7 @@
|
|||
const getFooterHeight = computed(() => {
|
||||
const { footerHeight, showFooter } = unref(getProps);
|
||||
if (showFooter && footerHeight) {
|
||||
return isNumber(footerHeight)
|
||||
? `${footerHeight}px`
|
||||
: `${footerHeight.replace('px', '')}px`;
|
||||
return isNumber(footerHeight) ? `${footerHeight}px` : `${footerHeight.replace('px', '')}px`;
|
||||
}
|
||||
return `0px`;
|
||||
});
|
||||
|
@ -135,21 +115,21 @@
|
|||
});
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newVal, oldVal) => {
|
||||
if (newVal !== oldVal) visibleRef.value = newVal;
|
||||
},
|
||||
{ deep: true }
|
||||
() => props.visible,
|
||||
(newVal, oldVal) => {
|
||||
if (newVal !== oldVal) visibleRef.value = newVal;
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => visibleRef.value,
|
||||
(visible) => {
|
||||
nextTick(() => {
|
||||
emit('visible-change', visible);
|
||||
instance && drawerInstance.emitVisible?.(visible, instance.uid);
|
||||
});
|
||||
}
|
||||
() => visibleRef.value,
|
||||
(visible) => {
|
||||
nextTick(() => {
|
||||
emit('visible-change', visible);
|
||||
instance && drawerInstance.emitVisible?.(visible, instance.uid);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// Cancel event
|
||||
|
|
|
@ -6,14 +6,7 @@
|
|||
{{ cancelText }}
|
||||
</a-button>
|
||||
<slot name="centerFooter"></slot>
|
||||
<a-button
|
||||
:type="okType"
|
||||
@click="handleOk"
|
||||
v-bind="okButtonProps"
|
||||
class="mr-2"
|
||||
:loading="confirmLoading"
|
||||
v-if="showOkBtn"
|
||||
>
|
||||
<a-button :type="okType" @click="handleOk" v-bind="okButtonProps" class="mr-2" :loading="confirmLoading" v-if="showOkBtn">
|
||||
{{ okText }}
|
||||
</a-button>
|
||||
<slot name="appendFooter"></slot>
|
||||
|
|
|
@ -1,20 +1,5 @@
|
|||
import type {
|
||||
UseDrawerReturnType,
|
||||
DrawerInstance,
|
||||
ReturnMethods,
|
||||
DrawerProps,
|
||||
UseDrawerInnerReturnType,
|
||||
} from './typing';
|
||||
import {
|
||||
ref,
|
||||
getCurrentInstance,
|
||||
unref,
|
||||
reactive,
|
||||
watchEffect,
|
||||
nextTick,
|
||||
toRaw,
|
||||
computed,
|
||||
} from 'vue';
|
||||
import type { UseDrawerReturnType, DrawerInstance, ReturnMethods, DrawerProps, UseDrawerInnerReturnType } from './typing';
|
||||
import { ref, getCurrentInstance, unref, reactive, watchEffect, nextTick, toRaw, computed } from 'vue';
|
||||
import { isProdMode } from '/@/utils/env';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { tryOnUnmounted } from '@vueuse/core';
|
||||
|
|
|
@ -6,16 +6,8 @@
|
|||
<template #overlay>
|
||||
<a-menu :class="[`${prefixCls}-menu`]" :selectedKeys="selectedKeys">
|
||||
<template v-for="item in dropMenuList" :key="`${item.event}`">
|
||||
<a-menu-item
|
||||
v-bind="getAttr(item.event)"
|
||||
@click="handleClickMenu(item)"
|
||||
:disabled="item.disabled"
|
||||
:class="[{'is-pop-confirm': item.popConfirm}]"
|
||||
>
|
||||
<a-popconfirm
|
||||
v-if="popconfirm && item.popConfirm"
|
||||
v-bind="getPopConfirmAttrs(item.popConfirm)"
|
||||
>
|
||||
<a-menu-item v-bind="getAttr(item.event)" @click="handleClickMenu(item)" :disabled="item.disabled" :class="[{ 'is-pop-confirm': item.popConfirm }]">
|
||||
<a-popconfirm v-if="popconfirm && item.popConfirm" v-bind="getPopConfirmAttrs(item.popConfirm)">
|
||||
<template #icon v-if="item.popConfirm.icon">
|
||||
<Icon :icon="item.popConfirm.icon" />
|
||||
</template>
|
||||
|
@ -43,7 +35,7 @@
|
|||
import { Icon } from '/@/components/Icon';
|
||||
import { omit } from 'lodash-es';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import {useDesign} from '/@/hooks/web/useDesign'
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
const ADropdown = Dropdown;
|
||||
const AMenu = Menu;
|
||||
|
@ -87,10 +79,8 @@
|
|||
const getPopConfirmAttrs = computed(() => {
|
||||
return (attrs) => {
|
||||
const originAttrs = omit(attrs, ['confirm', 'cancel', 'icon']);
|
||||
if (!attrs.onConfirm && attrs.confirm && isFunction(attrs.confirm))
|
||||
originAttrs['onConfirm'] = attrs.confirm;
|
||||
if (!attrs.onCancel && attrs.cancel && isFunction(attrs.cancel))
|
||||
originAttrs['onCancel'] = attrs.cancel;
|
||||
if (!attrs.onConfirm && attrs.confirm && isFunction(attrs.confirm)) originAttrs['onConfirm'] = attrs.confirm;
|
||||
if (!attrs.onCancel && attrs.cancel && isFunction(attrs.cancel)) originAttrs['onCancel'] = attrs.cancel;
|
||||
return originAttrs;
|
||||
};
|
||||
});
|
||||
|
@ -99,19 +89,17 @@
|
|||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-dropdown';
|
||||
@prefix-cls: ~'@{namespace}-basic-dropdown';
|
||||
|
||||
.@{prefix-cls} {
|
||||
.@{prefix-cls} {
|
||||
// update-begin--author:sunjianlei---date:20220322---for: 【VUEN-180】更多下拉菜单,只有点到字上才有效,点到空白处什么都不会发生,体验不好
|
||||
&-menu .ant-dropdown-menu-item.is-pop-confirm {
|
||||
padding: 0;
|
||||
|
||||
// update-begin--author:sunjianlei---date:20220322---for: 【VUEN-180】更多下拉菜单,只有点到字上才有效,点到空白处什么都不会发生,体验不好
|
||||
&-menu .ant-dropdown-menu-item.is-pop-confirm {
|
||||
padding: 0;
|
||||
|
||||
.dropdown-event-area {
|
||||
padding: 5px 12px;
|
||||
.dropdown-event-area {
|
||||
padding: 5px 12px;
|
||||
}
|
||||
}
|
||||
// update-end--author:sunjianlei---date:20220322---for: 【VUEN-180】更多下拉菜单,只有点到字上才有效,点到空白处什么都不会发生,体验不好
|
||||
}
|
||||
// update-end--author:sunjianlei---date:20220322---for: 【VUEN-180】更多下拉菜单,只有点到字上才有效,点到空白处什么都不会发生,体验不好
|
||||
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -6,13 +6,7 @@ const { utils, writeFile } = xlsx;
|
|||
|
||||
const DEF_FILE_NAME = 'excel-list.xlsx';
|
||||
|
||||
export function jsonToSheetXlsx<T = any>({
|
||||
data,
|
||||
header,
|
||||
filename = DEF_FILE_NAME,
|
||||
json2sheetOpts = {},
|
||||
write2excelOpts = { bookType: 'xlsx' },
|
||||
}: JsonToSheet<T>) {
|
||||
export function jsonToSheetXlsx<T = any>({ data, header, filename = DEF_FILE_NAME, json2sheetOpts = {}, write2excelOpts = { bookType: 'xlsx' } }: JsonToSheet<T>) {
|
||||
const arrData = [...data];
|
||||
if (header) {
|
||||
arrData.unshift(header);
|
||||
|
@ -33,12 +27,7 @@ export function jsonToSheetXlsx<T = any>({
|
|||
/* at this point, out.xlsb will have been downloaded */
|
||||
}
|
||||
|
||||
export function aoaToSheetXlsx<T = any>({
|
||||
data,
|
||||
header,
|
||||
filename = DEF_FILE_NAME,
|
||||
write2excelOpts = { bookType: 'xlsx' },
|
||||
}: AoAToSheet<T>) {
|
||||
export function aoaToSheetXlsx<T = any>({ data, header, filename = DEF_FILE_NAME, write2excelOpts = { bookType: 'xlsx' } }: AoAToSheet<T>) {
|
||||
const arrData = [...data];
|
||||
if (header) {
|
||||
arrData.unshift(header);
|
||||
|
|
|
@ -1,16 +1,6 @@
|
|||
<template>
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
:title="t('component.excel.exportModalTitle')"
|
||||
@ok="handleOk"
|
||||
@register="registerModal"
|
||||
>
|
||||
<BasicForm
|
||||
:labelWidth="100"
|
||||
:schemas="schemas"
|
||||
:showActionButtonGroup="false"
|
||||
@register="registerForm"
|
||||
/>
|
||||
<BasicModal v-bind="$attrs" :title="t('component.excel.exportModalTitle')" @ok="handleOk" @register="registerModal">
|
||||
<BasicForm :labelWidth="100" :schemas="schemas" :showActionButtonGroup="false" @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<input
|
||||
ref="inputRef"
|
||||
type="file"
|
||||
v-show="false"
|
||||
accept=".xlsx, .xls"
|
||||
@change="handleInputClick"
|
||||
/>
|
||||
<input ref="inputRef" type="file" v-show="false" accept=".xlsx, .xls" @change="handleInputClick" />
|
||||
<div @click="handleUpload">
|
||||
<slot></slot>
|
||||
</div>
|
||||
|
|
|
@ -19,7 +19,7 @@ export { default as JCategorySelect } from './src/jeecg/components/JCategorySele
|
|||
export { default as JSelectMultiple } from './src/jeecg/components/JSelectMultiple.vue';
|
||||
export { default as JPopup } from './src/jeecg/components/JPopup.vue';
|
||||
export { default as JAreaSelect } from './src/jeecg/components/JAreaSelect.vue';
|
||||
export { JEasyCron, JEasyCronInner, JEasyCronModal } from '/@/components/Form/src/jeecg/components/JEasyCron'
|
||||
export { JEasyCron, JEasyCronInner, JEasyCronModal } from '/@/components/Form/src/jeecg/components/JEasyCron';
|
||||
export { default as JCheckbox } from './src/jeecg/components/JCheckbox.vue';
|
||||
export { default as JInput } from './src/jeecg/components/JInput.vue';
|
||||
export { default as JEllipsis } from './src/jeecg/components/JEllipsis.vue';
|
||||
|
@ -30,6 +30,6 @@ export { default as JSelectUserByDept } from './src/jeecg/components/JSelectUser
|
|||
export { default as JEditor } from './src/jeecg/components/JEditor.vue';
|
||||
export { default as JImageUpload } from './src/jeecg/components/JImageUpload.vue';
|
||||
// Jeecg自定义校验
|
||||
export { JCronValidator } from '/@/components/Form/src/jeecg/components/JEasyCron'
|
||||
export { JCronValidator } from '/@/components/Form/src/jeecg/components/JEasyCron';
|
||||
|
||||
export { BasicForm };
|
||||
|
|
|
@ -1,324 +1,316 @@
|
|||
<template>
|
||||
<Form v-bind="getBindValue" :class="getFormClass" ref="formElRef" :model="formModel" @keypress.enter="handleEnterPress">
|
||||
<Row v-bind="getRow">
|
||||
<slot name="formHeader"></slot>
|
||||
<template v-for="schema in getSchema" :key="schema.field">
|
||||
<FormItem :tableAction="tableAction" :formActionType="formActionType" :schema="schema" :formProps="getProps" :allDefaultValues="defaultValueRef" :formModel="formModel" :setFormModel="setFormModel">
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
</FormItem>
|
||||
</template>
|
||||
<Form v-bind="getBindValue" :class="getFormClass" ref="formElRef" :model="formModel" @keypress.enter="handleEnterPress">
|
||||
<Row v-bind="getRow">
|
||||
<slot name="formHeader"></slot>
|
||||
<template v-for="schema in getSchema" :key="schema.field">
|
||||
<FormItem
|
||||
:tableAction="tableAction"
|
||||
:formActionType="formActionType"
|
||||
:schema="schema"
|
||||
:formProps="getProps"
|
||||
:allDefaultValues="defaultValueRef"
|
||||
:formModel="formModel"
|
||||
:setFormModel="setFormModel"
|
||||
>
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
</FormItem>
|
||||
</template>
|
||||
|
||||
<FormAction v-bind="getFormActionBindProps" @toggle-advanced="handleToggleAdvanced">
|
||||
<template #[item]="data" v-for="item in ['resetBefore', 'submitBefore', 'advanceBefore', 'advanceAfter']">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
</FormAction>
|
||||
<slot name="formFooter"></slot>
|
||||
</Row>
|
||||
</Form>
|
||||
<FormAction v-bind="getFormActionBindProps" @toggle-advanced="handleToggleAdvanced">
|
||||
<template #[item]="data" v-for="item in ['resetBefore', 'submitBefore', 'advanceBefore', 'advanceAfter']">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
</FormAction>
|
||||
<slot name="formFooter"></slot>
|
||||
</Row>
|
||||
</Form>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { FormActionType, FormProps, FormSchema } from './types/form';
|
||||
import type { AdvanceState } from './types/hooks';
|
||||
import type { Ref } from 'vue';
|
||||
import type { FormActionType, FormProps, FormSchema } from './types/form';
|
||||
import type { AdvanceState } from './types/hooks';
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
import { defineComponent, reactive, ref, computed, unref, onMounted, watch, nextTick } from 'vue';
|
||||
import { Form, Row } from 'ant-design-vue';
|
||||
import FormItem from './components/FormItem.vue';
|
||||
import FormAction from './components/FormAction.vue';
|
||||
import { defineComponent, reactive, ref, computed, unref, onMounted, watch, nextTick } from 'vue';
|
||||
import { Form, Row } from 'ant-design-vue';
|
||||
import FormItem from './components/FormItem.vue';
|
||||
import FormAction from './components/FormAction.vue';
|
||||
|
||||
import { dateItemType } from './helper';
|
||||
import { dateUtil } from '/@/utils/dateUtil';
|
||||
import { dateItemType } from './helper';
|
||||
import { dateUtil } from '/@/utils/dateUtil';
|
||||
|
||||
// import { cloneDeep } from 'lodash-es';
|
||||
import { deepMerge } from '/@/utils';
|
||||
// import { cloneDeep } from 'lodash-es';
|
||||
import { deepMerge } from '/@/utils';
|
||||
|
||||
import { useFormValues } from './hooks/useFormValues';
|
||||
import useAdvanced from './hooks/useAdvanced';
|
||||
import { useFormEvents } from './hooks/useFormEvents';
|
||||
import { createFormContext } from './hooks/useFormContext';
|
||||
import { useAutoFocus } from './hooks/useAutoFocus';
|
||||
import { useModalContext } from '/@/components/Modal';
|
||||
import { useFormValues } from './hooks/useFormValues';
|
||||
import useAdvanced from './hooks/useAdvanced';
|
||||
import { useFormEvents } from './hooks/useFormEvents';
|
||||
import { createFormContext } from './hooks/useFormContext';
|
||||
import { useAutoFocus } from './hooks/useAutoFocus';
|
||||
import { useModalContext } from '/@/components/Modal';
|
||||
|
||||
import { basicProps } from './props';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { basicProps } from './props';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicForm',
|
||||
components: { FormItem, Form, Row, FormAction },
|
||||
props: basicProps,
|
||||
emits: ['advanced-change', 'reset', 'submit', 'register'],
|
||||
setup(props, { emit, attrs }) {
|
||||
const formModel = reactive<Recordable>({});
|
||||
const modalFn = useModalContext();
|
||||
export default defineComponent({
|
||||
name: 'BasicForm',
|
||||
components: { FormItem, Form, Row, FormAction },
|
||||
props: basicProps,
|
||||
emits: ['advanced-change', 'reset', 'submit', 'register'],
|
||||
setup(props, { emit, attrs }) {
|
||||
const formModel = reactive<Recordable>({});
|
||||
const modalFn = useModalContext();
|
||||
|
||||
const advanceState = reactive<AdvanceState>({
|
||||
// 默认是收起状态
|
||||
isAdvanced: false,
|
||||
hideAdvanceBtn: true,
|
||||
isLoad: false,
|
||||
actionSpan: 6,
|
||||
});
|
||||
const advanceState = reactive<AdvanceState>({
|
||||
// 默认是收起状态
|
||||
isAdvanced: false,
|
||||
hideAdvanceBtn: true,
|
||||
isLoad: false,
|
||||
actionSpan: 6,
|
||||
});
|
||||
|
||||
const defaultValueRef = ref<Recordable>({});
|
||||
const isInitedDefaultRef = ref(false);
|
||||
const propsRef = ref<Partial<FormProps>>({});
|
||||
const schemaRef = ref<Nullable<FormSchema[]>>(null);
|
||||
const formElRef = ref<Nullable<FormActionType>>(null);
|
||||
const defaultValueRef = ref<Recordable>({});
|
||||
const isInitedDefaultRef = ref(false);
|
||||
const propsRef = ref<Partial<FormProps>>({});
|
||||
const schemaRef = ref<Nullable<FormSchema[]>>(null);
|
||||
const formElRef = ref<Nullable<FormActionType>>(null);
|
||||
|
||||
const { prefixCls } = useDesign('basic-form');
|
||||
const { prefixCls } = useDesign('basic-form');
|
||||
|
||||
// Get the basic configuration of the form
|
||||
const getProps = computed((): FormProps => {
|
||||
return { ...props, ...unref(propsRef) } as FormProps;
|
||||
});
|
||||
// Get the basic configuration of the form
|
||||
const getProps = computed((): FormProps => {
|
||||
return { ...props, ...unref(propsRef) } as FormProps;
|
||||
});
|
||||
|
||||
const getFormClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}--compact`]: unref(getProps).compact,
|
||||
},
|
||||
];
|
||||
});
|
||||
const getFormClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}--compact`]: unref(getProps).compact,
|
||||
},
|
||||
];
|
||||
});
|
||||
|
||||
// Get uniform row style and Row configuration for the entire form
|
||||
const getRow = computed((): Recordable => {
|
||||
const { baseRowStyle = {}, rowProps } = unref(getProps);
|
||||
return {
|
||||
style: baseRowStyle,
|
||||
...rowProps,
|
||||
};
|
||||
});
|
||||
// Get uniform row style and Row configuration for the entire form
|
||||
const getRow = computed((): Recordable => {
|
||||
const { baseRowStyle = {}, rowProps } = unref(getProps);
|
||||
return {
|
||||
style: baseRowStyle,
|
||||
...rowProps,
|
||||
};
|
||||
});
|
||||
|
||||
const getBindValue = computed(
|
||||
() => ({ ...attrs, ...props, ...unref(getProps) } as Recordable)
|
||||
);
|
||||
const getBindValue = computed(() => ({ ...attrs, ...props, ...unref(getProps) } as Recordable));
|
||||
|
||||
const getSchema = computed((): FormSchema[] => {
|
||||
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
|
||||
for (const schema of schemas) {
|
||||
const { defaultValue, component } = schema;
|
||||
// handle date type
|
||||
if (defaultValue && dateItemType.includes(component)) {
|
||||
if (!Array.isArray(defaultValue)) {
|
||||
schema.defaultValue = dateUtil(defaultValue);
|
||||
} else {
|
||||
const def: moment.Moment[] = [];
|
||||
defaultValue.forEach((item) => {
|
||||
def.push(dateUtil(item));
|
||||
});
|
||||
schema.defaultValue = def;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unref(getProps).showAdvancedButton) {
|
||||
return schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[];
|
||||
} else {
|
||||
return schemas as FormSchema[];
|
||||
}
|
||||
});
|
||||
|
||||
const { handleToggleAdvanced } = useAdvanced({
|
||||
advanceState,
|
||||
emit,
|
||||
getProps,
|
||||
getSchema,
|
||||
formModel,
|
||||
defaultValueRef,
|
||||
});
|
||||
|
||||
const { handleFormValues, initDefault } = useFormValues({
|
||||
getProps,
|
||||
defaultValueRef,
|
||||
getSchema,
|
||||
formModel,
|
||||
});
|
||||
|
||||
useAutoFocus({
|
||||
getSchema,
|
||||
getProps,
|
||||
isInitedDefault: isInitedDefaultRef,
|
||||
formElRef: formElRef as Ref<FormActionType>,
|
||||
});
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
setFieldsValue,
|
||||
clearValidate,
|
||||
validate,
|
||||
validateFields,
|
||||
getFieldsValue,
|
||||
updateSchema,
|
||||
resetSchema,
|
||||
appendSchemaByField,
|
||||
removeSchemaByFiled,
|
||||
resetFields,
|
||||
scrollToField,
|
||||
} = useFormEvents({
|
||||
emit,
|
||||
getProps,
|
||||
formModel,
|
||||
getSchema,
|
||||
defaultValueRef,
|
||||
formElRef: formElRef as Ref<FormActionType>,
|
||||
schemaRef: schemaRef as Ref<FormSchema[]>,
|
||||
handleFormValues,
|
||||
});
|
||||
|
||||
createFormContext({
|
||||
resetAction: resetFields,
|
||||
submitAction: handleSubmit,
|
||||
});
|
||||
|
||||
watch(
|
||||
() => unref(getProps).model,
|
||||
() => {
|
||||
const { model } = unref(getProps);
|
||||
if (!model) return;
|
||||
setFieldsValue(model);
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => unref(getProps).schemas,
|
||||
(schemas) => {
|
||||
resetSchema(schemas ?? []);
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => getSchema.value,
|
||||
(schema) => {
|
||||
nextTick(() => {
|
||||
// Solve the problem of modal adaptive height calculation when the form is placed in the modal
|
||||
modalFn?.redoModalHeight?.();
|
||||
});
|
||||
if (unref(isInitedDefaultRef)) {
|
||||
return;
|
||||
}
|
||||
if (schema?.length) {
|
||||
initDefault();
|
||||
isInitedDefaultRef.value = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
async function setProps(formProps: Partial<FormProps>): Promise<void> {
|
||||
propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
|
||||
const getSchema = computed((): FormSchema[] => {
|
||||
const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
|
||||
for (const schema of schemas) {
|
||||
const { defaultValue, component } = schema;
|
||||
// handle date type
|
||||
if (defaultValue && dateItemType.includes(component)) {
|
||||
if (!Array.isArray(defaultValue)) {
|
||||
schema.defaultValue = dateUtil(defaultValue);
|
||||
} else {
|
||||
const def: moment.Moment[] = [];
|
||||
defaultValue.forEach((item) => {
|
||||
def.push(dateUtil(item));
|
||||
});
|
||||
schema.defaultValue = def;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unref(getProps).showAdvancedButton) {
|
||||
return schemas.filter((schema) => schema.component !== 'Divider') as FormSchema[];
|
||||
} else {
|
||||
return schemas as FormSchema[];
|
||||
}
|
||||
});
|
||||
|
||||
function setFormModel(key: string, value: any) {
|
||||
formModel[key] = value;
|
||||
const { validateTrigger } = unref(getBindValue);
|
||||
if (!validateTrigger || validateTrigger === 'change') {
|
||||
validateFields([key]).catch((_) => {});
|
||||
}
|
||||
}
|
||||
const { handleToggleAdvanced } = useAdvanced({
|
||||
advanceState,
|
||||
emit,
|
||||
getProps,
|
||||
getSchema,
|
||||
formModel,
|
||||
defaultValueRef,
|
||||
});
|
||||
|
||||
function handleEnterPress(e: KeyboardEvent) {
|
||||
const { autoSubmitOnEnter } = unref(getProps);
|
||||
if (!autoSubmitOnEnter) return;
|
||||
if (e.key === 'Enter' && e.target && e.target instanceof HTMLElement) {
|
||||
const target: HTMLElement = e.target as HTMLElement;
|
||||
if (target && target.tagName && target.tagName.toUpperCase() == 'INPUT') {
|
||||
handleSubmit();
|
||||
}
|
||||
}
|
||||
}
|
||||
const { handleFormValues, initDefault } = useFormValues({
|
||||
getProps,
|
||||
defaultValueRef,
|
||||
getSchema,
|
||||
formModel,
|
||||
});
|
||||
|
||||
const formActionType: Partial<FormActionType> = {
|
||||
getFieldsValue,
|
||||
setFieldsValue,
|
||||
resetFields,
|
||||
updateSchema,
|
||||
resetSchema,
|
||||
setProps,
|
||||
removeSchemaByFiled,
|
||||
appendSchemaByField,
|
||||
clearValidate,
|
||||
validateFields,
|
||||
validate,
|
||||
submit: handleSubmit,
|
||||
scrollToField: scrollToField,
|
||||
};
|
||||
useAutoFocus({
|
||||
getSchema,
|
||||
getProps,
|
||||
isInitedDefault: isInitedDefaultRef,
|
||||
formElRef: formElRef as Ref<FormActionType>,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
initDefault();
|
||||
emit('register', formActionType);
|
||||
});
|
||||
const { handleSubmit, setFieldsValue, clearValidate, validate, validateFields, getFieldsValue, updateSchema, resetSchema, appendSchemaByField, removeSchemaByFiled, resetFields, scrollToField } =
|
||||
useFormEvents({
|
||||
emit,
|
||||
getProps,
|
||||
formModel,
|
||||
getSchema,
|
||||
defaultValueRef,
|
||||
formElRef: formElRef as Ref<FormActionType>,
|
||||
schemaRef: schemaRef as Ref<FormSchema[]>,
|
||||
handleFormValues,
|
||||
});
|
||||
|
||||
return {
|
||||
getBindValue,
|
||||
handleToggleAdvanced,
|
||||
handleEnterPress,
|
||||
formModel,
|
||||
defaultValueRef,
|
||||
advanceState,
|
||||
getRow,
|
||||
getProps,
|
||||
formElRef,
|
||||
getSchema,
|
||||
formActionType: formActionType as any,
|
||||
setFormModel,
|
||||
getFormClass,
|
||||
getFormActionBindProps: computed(
|
||||
(): Recordable => ({ ...getProps.value, ...advanceState })
|
||||
),
|
||||
...formActionType,
|
||||
};
|
||||
createFormContext({
|
||||
resetAction: resetFields,
|
||||
submitAction: handleSubmit,
|
||||
});
|
||||
|
||||
watch(
|
||||
() => unref(getProps).model,
|
||||
() => {
|
||||
const { model } = unref(getProps);
|
||||
if (!model) return;
|
||||
setFieldsValue(model);
|
||||
},
|
||||
});
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => unref(getProps).schemas,
|
||||
(schemas) => {
|
||||
resetSchema(schemas ?? []);
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => getSchema.value,
|
||||
(schema) => {
|
||||
nextTick(() => {
|
||||
// Solve the problem of modal adaptive height calculation when the form is placed in the modal
|
||||
modalFn?.redoModalHeight?.();
|
||||
});
|
||||
if (unref(isInitedDefaultRef)) {
|
||||
return;
|
||||
}
|
||||
if (schema?.length) {
|
||||
initDefault();
|
||||
isInitedDefaultRef.value = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
async function setProps(formProps: Partial<FormProps>): Promise<void> {
|
||||
propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
|
||||
}
|
||||
|
||||
function setFormModel(key: string, value: any) {
|
||||
formModel[key] = value;
|
||||
const { validateTrigger } = unref(getBindValue);
|
||||
if (!validateTrigger || validateTrigger === 'change') {
|
||||
validateFields([key]).catch((_) => {});
|
||||
}
|
||||
}
|
||||
|
||||
function handleEnterPress(e: KeyboardEvent) {
|
||||
const { autoSubmitOnEnter } = unref(getProps);
|
||||
if (!autoSubmitOnEnter) return;
|
||||
if (e.key === 'Enter' && e.target && e.target instanceof HTMLElement) {
|
||||
const target: HTMLElement = e.target as HTMLElement;
|
||||
if (target && target.tagName && target.tagName.toUpperCase() == 'INPUT') {
|
||||
handleSubmit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const formActionType: Partial<FormActionType> = {
|
||||
getFieldsValue,
|
||||
setFieldsValue,
|
||||
resetFields,
|
||||
updateSchema,
|
||||
resetSchema,
|
||||
setProps,
|
||||
removeSchemaByFiled,
|
||||
appendSchemaByField,
|
||||
clearValidate,
|
||||
validateFields,
|
||||
validate,
|
||||
submit: handleSubmit,
|
||||
scrollToField: scrollToField,
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initDefault();
|
||||
emit('register', formActionType);
|
||||
});
|
||||
|
||||
return {
|
||||
getBindValue,
|
||||
handleToggleAdvanced,
|
||||
handleEnterPress,
|
||||
formModel,
|
||||
defaultValueRef,
|
||||
advanceState,
|
||||
getRow,
|
||||
getProps,
|
||||
formElRef,
|
||||
getSchema,
|
||||
formActionType: formActionType as any,
|
||||
setFormModel,
|
||||
getFormClass,
|
||||
getFormActionBindProps: computed((): Recordable => ({ ...getProps.value, ...advanceState })),
|
||||
...formActionType,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@prefix-cls: ~'@{namespace}-basic-form';
|
||||
@prefix-cls: ~'@{namespace}-basic-form';
|
||||
|
||||
.@{prefix-cls} {
|
||||
.ant-form-item {
|
||||
&-label label::after {
|
||||
margin: 0 6px 0 2px;
|
||||
}
|
||||
.@{prefix-cls} {
|
||||
.ant-form-item {
|
||||
&-label label::after {
|
||||
margin: 0 6px 0 2px;
|
||||
}
|
||||
|
||||
&-with-help {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
&-with-help {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&:not(.ant-form-item-with-help) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
&:not(.ant-form-item-with-help) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
&.suffix-item {
|
||||
.ant-form-item-children {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.ant-form-item-control {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.suffix {
|
||||
display: inline-flex;
|
||||
padding-left: 6px;
|
||||
margin-top: 1px;
|
||||
line-height: 1;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
&.suffix-item {
|
||||
.ant-form-item-children {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.ant-form-explain {
|
||||
font-size: 14px;
|
||||
.ant-form-item-control {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
&--compact {
|
||||
.ant-form-item {
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
.suffix {
|
||||
display: inline-flex;
|
||||
padding-left: 6px;
|
||||
margin-top: 1px;
|
||||
line-height: 1;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ant-form-explain {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&--compact {
|
||||
.ant-form-item {
|
||||
margin-bottom: 8px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -4,22 +4,7 @@ import type { ComponentType } from './types/index';
|
|||
/**
|
||||
* Component list, register here to setting it in the form
|
||||
*/
|
||||
import {
|
||||
Input,
|
||||
Select,
|
||||
Radio,
|
||||
Checkbox,
|
||||
AutoComplete,
|
||||
Cascader,
|
||||
DatePicker,
|
||||
InputNumber,
|
||||
Switch,
|
||||
TimePicker,
|
||||
TreeSelect,
|
||||
Slider,
|
||||
Rate,
|
||||
Divider,
|
||||
} from 'ant-design-vue';
|
||||
import { Input, Select, Radio, Checkbox, AutoComplete, Cascader, DatePicker, InputNumber, Switch, TimePicker, TreeSelect, Slider, Rate, Divider } from 'ant-design-vue';
|
||||
import ApiRadioGroup from './components/ApiRadioGroup.vue';
|
||||
import RadioButtonGroup from './components/RadioButtonGroup.vue';
|
||||
import ApiSelect from './components/ApiSelect.vue';
|
||||
|
@ -47,18 +32,18 @@ import JPopup from './jeecg/components/JPopup.vue';
|
|||
import JSwitch from './jeecg/components/JSwitch.vue';
|
||||
import JTreeDict from './jeecg/components/JTreeDict.vue';
|
||||
import JInputPop from './jeecg/components/JInputPop.vue';
|
||||
import { JEasyCron } from './jeecg/components/JEasyCron'
|
||||
import { JEasyCron } from './jeecg/components/JEasyCron';
|
||||
import JCheckbox from './jeecg/components/JCheckbox.vue';
|
||||
import JInput from './jeecg/components/JInput.vue';
|
||||
import JTreeSelect from './jeecg/components/JTreeSelect.vue';
|
||||
import JEllipsis from './jeecg/components/JEllipsis.vue';
|
||||
import JSelectUserByDept from './jeecg/components/JSelectUserByDept.vue';
|
||||
import JUpload from './jeecg/components/JUpload/JUpload.vue'
|
||||
import JSearchSelect from './jeecg/components/JSearchSelect.vue'
|
||||
import JAddInput from './jeecg/components/JAddInput.vue'
|
||||
import {Time} from '/@/components/Time';
|
||||
import JOnlineSelectCascade from './jeecg/components/JOnlineSelectCascade.vue'
|
||||
import JRangeNumber from './jeecg/components/JRangeNumber.vue'
|
||||
import JUpload from './jeecg/components/JUpload/JUpload.vue';
|
||||
import JSearchSelect from './jeecg/components/JSearchSelect.vue';
|
||||
import JAddInput from './jeecg/components/JAddInput.vue';
|
||||
import { Time } from '/@/components/Time';
|
||||
import JOnlineSelectCascade from './jeecg/components/JOnlineSelectCascade.vue';
|
||||
import JRangeNumber from './jeecg/components/JRangeNumber.vue';
|
||||
|
||||
const componentMap = new Map<ComponentType, Component>();
|
||||
|
||||
|
@ -125,8 +110,8 @@ componentMap.set('JSelectUserByDept', JSelectUserByDept);
|
|||
componentMap.set('JUpload', JUpload);
|
||||
componentMap.set('JSearchSelect', JSearchSelect);
|
||||
componentMap.set('JAddInput', JAddInput);
|
||||
componentMap.set('JOnlineSelectCascade', JOnlineSelectCascade)
|
||||
componentMap.set('JRangeNumber', JRangeNumber)
|
||||
componentMap.set('JOnlineSelectCascade', JOnlineSelectCascade);
|
||||
componentMap.set('JRangeNumber', JRangeNumber);
|
||||
|
||||
export function add(compName: ComponentType, component: Component) {
|
||||
componentMap.set(compName, component);
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
() => {
|
||||
!unref(isFirstLoad) && fetch();
|
||||
},
|
||||
{ deep: true },
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
async function fetch() {
|
||||
|
|
|
@ -1,144 +1,138 @@
|
|||
<template>
|
||||
<Select
|
||||
@dropdownVisibleChange="handleFetch"
|
||||
v-bind="$attrs"
|
||||
@change="handleChange"
|
||||
:options="getOptions"
|
||||
v-model:value="state"
|
||||
>
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
<template #suffixIcon v-if="loading">
|
||||
<LoadingOutlined spin />
|
||||
</template>
|
||||
<template #notFoundContent v-if="loading">
|
||||
<Select @dropdownVisibleChange="handleFetch" v-bind="$attrs" @change="handleChange" :options="getOptions" v-model:value="state">
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
<template #suffixIcon v-if="loading">
|
||||
<LoadingOutlined spin />
|
||||
</template>
|
||||
<template #notFoundContent v-if="loading">
|
||||
<span>
|
||||
<LoadingOutlined spin class="mr-1" />
|
||||
{{ t('component.form.apiSelectNotFound') }}
|
||||
</span>
|
||||
</template>
|
||||
</Select>
|
||||
</template>
|
||||
</Select>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, watchEffect, computed, unref, watch } from 'vue';
|
||||
import { Select } from 'ant-design-vue';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { get, omit } from 'lodash-es';
|
||||
import { LoadingOutlined } from '@ant-design/icons-vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { defineComponent, PropType, ref, watchEffect, computed, unref, watch } from 'vue';
|
||||
import { Select } from 'ant-design-vue';
|
||||
import { isFunction } from '/@/utils/is';
|
||||
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { get, omit } from 'lodash-es';
|
||||
import { LoadingOutlined } from '@ant-design/icons-vue';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
type OptionsItem = { label: string; value: string; disabled?: boolean };
|
||||
type OptionsItem = { label: string; value: string; disabled?: boolean };
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ApiSelect',
|
||||
components: {
|
||||
Select,
|
||||
LoadingOutlined,
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: [Array, Object, String, Number],
|
||||
numberToString: propTypes.bool,
|
||||
api: {
|
||||
type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>,
|
||||
default: null,
|
||||
},
|
||||
// api params
|
||||
params: {
|
||||
type: Object as PropType<Recordable>,
|
||||
default: () => ({}),
|
||||
},
|
||||
// support xxx.xxx.xx
|
||||
resultField: propTypes.string.def(''),
|
||||
labelField: propTypes.string.def('label'),
|
||||
valueField: propTypes.string.def('value'),
|
||||
immediate: propTypes.bool.def(true),
|
||||
},
|
||||
emits: ['options-change', 'change'],
|
||||
setup(props, { emit }) {
|
||||
const options = ref<OptionsItem[]>([]);
|
||||
const loading = ref(false);
|
||||
const isFirstLoad = ref(true);
|
||||
const emitData = ref<any[]>([]);
|
||||
const attrs = useAttrs();
|
||||
const { t } = useI18n();
|
||||
export default defineComponent({
|
||||
name: 'ApiSelect',
|
||||
components: {
|
||||
Select,
|
||||
LoadingOutlined,
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: [Array, Object, String, Number],
|
||||
numberToString: propTypes.bool,
|
||||
api: {
|
||||
type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>,
|
||||
default: null,
|
||||
},
|
||||
// api params
|
||||
params: {
|
||||
type: Object as PropType<Recordable>,
|
||||
default: () => ({}),
|
||||
},
|
||||
// support xxx.xxx.xx
|
||||
resultField: propTypes.string.def(''),
|
||||
labelField: propTypes.string.def('label'),
|
||||
valueField: propTypes.string.def('value'),
|
||||
immediate: propTypes.bool.def(true),
|
||||
},
|
||||
emits: ['options-change', 'change'],
|
||||
setup(props, { emit }) {
|
||||
const options = ref<OptionsItem[]>([]);
|
||||
const loading = ref(false);
|
||||
const isFirstLoad = ref(true);
|
||||
const emitData = ref<any[]>([]);
|
||||
const attrs = useAttrs();
|
||||
const { t } = useI18n();
|
||||
|
||||
// Embedded in the form, just use the hook binding to perform form verification
|
||||
const [state, setState] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
// Embedded in the form, just use the hook binding to perform form verification
|
||||
const [state, setState] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
|
||||
const getOptions = computed(() => {
|
||||
const { labelField, valueField, numberToString } = props;
|
||||
return unref(options).reduce((prev, next: Recordable) => {
|
||||
if (next) {
|
||||
const value = next[valueField];
|
||||
prev.push({
|
||||
...omit(next, [labelField, valueField]),
|
||||
label: next[labelField],
|
||||
value: numberToString ? `${value}` : value,
|
||||
});
|
||||
}
|
||||
return prev;
|
||||
}, [] as OptionsItem[]);
|
||||
const getOptions = computed(() => {
|
||||
const { labelField, valueField, numberToString } = props;
|
||||
return unref(options).reduce((prev, next: Recordable) => {
|
||||
if (next) {
|
||||
const value = next[valueField];
|
||||
prev.push({
|
||||
...omit(next, [labelField, valueField]),
|
||||
label: next[labelField],
|
||||
value: numberToString ? `${value}` : value,
|
||||
});
|
||||
}
|
||||
return prev;
|
||||
}, [] as OptionsItem[]);
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
props.immediate && fetch();
|
||||
});
|
||||
watchEffect(() => {
|
||||
props.immediate && fetch();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.params,
|
||||
() => {
|
||||
!unref(isFirstLoad) && fetch();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
async function fetch() {
|
||||
const api = props.api;
|
||||
if (!api || !isFunction(api)) return;
|
||||
options.value = [];
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await api(props.params);
|
||||
if (Array.isArray(res)) {
|
||||
options.value = res;
|
||||
emitChange();
|
||||
return;
|
||||
}
|
||||
if (props.resultField) {
|
||||
options.value = get(res, props.resultField) || [];
|
||||
}
|
||||
emitChange();
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
//--@updateBy-begin----author:liusq---date:20210914------for:判断选择模式,multiple多选情况下的value值空的情况下需要设置为数组------
|
||||
unref(attrs).mode == 'multiple' && !Array.isArray(unref(state)) && setState([])
|
||||
//--@updateBy-end----author:liusq---date:20210914------for:判断选择模式,multiple多选情况下的value值空的情况下需要设置为数组------
|
||||
}
|
||||
}
|
||||
|
||||
async function handleFetch() {
|
||||
if (!props.immediate && unref(isFirstLoad)) {
|
||||
await fetch();
|
||||
isFirstLoad.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function emitChange() {
|
||||
emit('options-change', unref(getOptions));
|
||||
}
|
||||
|
||||
function handleChange(_, ...args) {
|
||||
emitData.value = args;
|
||||
}
|
||||
|
||||
return { state, attrs, getOptions, loading, t, handleFetch, handleChange };
|
||||
watch(
|
||||
() => props.params,
|
||||
() => {
|
||||
!unref(isFirstLoad) && fetch();
|
||||
},
|
||||
});
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
async function fetch() {
|
||||
const api = props.api;
|
||||
if (!api || !isFunction(api)) return;
|
||||
options.value = [];
|
||||
try {
|
||||
loading.value = true;
|
||||
const res = await api(props.params);
|
||||
if (Array.isArray(res)) {
|
||||
options.value = res;
|
||||
emitChange();
|
||||
return;
|
||||
}
|
||||
if (props.resultField) {
|
||||
options.value = get(res, props.resultField) || [];
|
||||
}
|
||||
emitChange();
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
//--@updateBy-begin----author:liusq---date:20210914------for:判断选择模式,multiple多选情况下的value值空的情况下需要设置为数组------
|
||||
unref(attrs).mode == 'multiple' && !Array.isArray(unref(state)) && setState([]);
|
||||
//--@updateBy-end----author:liusq---date:20210914------for:判断选择模式,multiple多选情况下的value值空的情况下需要设置为数组------
|
||||
}
|
||||
}
|
||||
|
||||
async function handleFetch() {
|
||||
if (!props.immediate && unref(isFirstLoad)) {
|
||||
await fetch();
|
||||
isFirstLoad.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function emitChange() {
|
||||
emit('options-change', unref(getOptions));
|
||||
}
|
||||
|
||||
function handleChange(_, ...args) {
|
||||
emitData.value = args;
|
||||
}
|
||||
|
||||
return { state, attrs, getOptions, loading, t, handleFetch, handleChange };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,86 +1,86 @@
|
|||
<template>
|
||||
<a-tree-select v-bind="getAttrs" @change="handleChange">
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
<template #suffixIcon v-if="loading">
|
||||
<LoadingOutlined spin />
|
||||
</template>
|
||||
</a-tree-select>
|
||||
<a-tree-select v-bind="getAttrs" @change="handleChange">
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
<template #suffixIcon v-if="loading">
|
||||
<LoadingOutlined spin />
|
||||
</template>
|
||||
</a-tree-select>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, watch, ref, onMounted, unref } from 'vue';
|
||||
import { TreeSelect } from 'ant-design-vue';
|
||||
import { isArray, isFunction } from '/@/utils/is';
|
||||
import { get } from 'lodash-es';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { LoadingOutlined } from '@ant-design/icons-vue';
|
||||
export default defineComponent({
|
||||
name: 'ApiTreeSelect',
|
||||
components: { ATreeSelect: TreeSelect, LoadingOutlined },
|
||||
props: {
|
||||
api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> },
|
||||
params: { type: Object },
|
||||
immediate: { type: Boolean, default: true },
|
||||
resultField: propTypes.string.def(''),
|
||||
import { computed, defineComponent, watch, ref, onMounted, unref } from 'vue';
|
||||
import { TreeSelect } from 'ant-design-vue';
|
||||
import { isArray, isFunction } from '/@/utils/is';
|
||||
import { get } from 'lodash-es';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { LoadingOutlined } from '@ant-design/icons-vue';
|
||||
export default defineComponent({
|
||||
name: 'ApiTreeSelect',
|
||||
components: { ATreeSelect: TreeSelect, LoadingOutlined },
|
||||
props: {
|
||||
api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> },
|
||||
params: { type: Object },
|
||||
immediate: { type: Boolean, default: true },
|
||||
resultField: propTypes.string.def(''),
|
||||
},
|
||||
emits: ['options-change', 'change'],
|
||||
setup(props, { attrs, emit }) {
|
||||
const treeData = ref<Recordable[]>([]);
|
||||
const isFirstLoaded = ref<Boolean>(false);
|
||||
const loading = ref(false);
|
||||
const getAttrs = computed(() => {
|
||||
return {
|
||||
...(props.api ? { treeData: unref(treeData) } : {}),
|
||||
...attrs,
|
||||
};
|
||||
});
|
||||
|
||||
function handleChange(...args) {
|
||||
emit('change', ...args);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.params,
|
||||
() => {
|
||||
!unref(isFirstLoaded) && fetch();
|
||||
},
|
||||
emits: ['options-change', 'change'],
|
||||
setup(props, { attrs, emit }) {
|
||||
const treeData = ref<Recordable[]>([]);
|
||||
const isFirstLoaded = ref<Boolean>(false);
|
||||
const loading = ref(false);
|
||||
const getAttrs = computed(() => {
|
||||
return {
|
||||
...(props.api ? { treeData: unref(treeData) } : {}),
|
||||
...attrs,
|
||||
};
|
||||
});
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
function handleChange(...args) {
|
||||
emit('change', ...args);
|
||||
}
|
||||
watch(
|
||||
() => props.immediate,
|
||||
(v) => {
|
||||
v && !isFirstLoaded.value && fetch();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.params,
|
||||
() => {
|
||||
!unref(isFirstLoaded) && fetch();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
onMounted(() => {
|
||||
props.immediate && fetch();
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.immediate,
|
||||
(v) => {
|
||||
v && !isFirstLoaded.value && fetch();
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
props.immediate && fetch();
|
||||
});
|
||||
|
||||
async function fetch() {
|
||||
const { api } = props;
|
||||
if (!api || !isFunction(api)) return;
|
||||
loading.value = true;
|
||||
treeData.value = [];
|
||||
let result;
|
||||
try {
|
||||
result = await api(props.params);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
loading.value = false;
|
||||
if (!result) return;
|
||||
if (!isArray(result)) {
|
||||
result = get(result, props.resultField);
|
||||
}
|
||||
treeData.value = (result as Recordable[]) || [];
|
||||
isFirstLoaded.value = true;
|
||||
emit('options-change', treeData.value);
|
||||
}
|
||||
return { getAttrs, loading, handleChange };
|
||||
},
|
||||
});
|
||||
async function fetch() {
|
||||
const { api } = props;
|
||||
if (!api || !isFunction(api)) return;
|
||||
loading.value = true;
|
||||
treeData.value = [];
|
||||
let result;
|
||||
try {
|
||||
result = await api(props.params);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
loading.value = false;
|
||||
if (!result) return;
|
||||
if (!isArray(result)) {
|
||||
result = get(result, props.resultField);
|
||||
}
|
||||
treeData.value = (result as Recordable[]) || [];
|
||||
isFirstLoaded.value = true;
|
||||
emit('options-change', treeData.value);
|
||||
}
|
||||
return { getAttrs, loading, handleChange };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
<a-col v-bind="actionColOpt" v-if="showActionButtonGroup">
|
||||
<div style="width: 100%" :style="{ textAlign: actionColOpt.style.textAlign }">
|
||||
<FormItem>
|
||||
<!-- update-begin-author:zyf Date:20211213 for:调换按钮前后位置-->
|
||||
<slot name="submitBefore"></slot>
|
||||
<!-- update-begin-author:zyf Date:20211213 for:调换按钮前后位置-->
|
||||
<slot name="submitBefore"></slot>
|
||||
<Button type="primary" class="mr-2" v-bind="getSubmitBtnOptions" @click="submitAction" v-if="showSubmitButton">
|
||||
<Icon icon="ant-design:search-outlined"></Icon>
|
||||
<Icon icon="ant-design:search-outlined"></Icon>
|
||||
{{ getSubmitBtnOptions.text }}
|
||||
</Button>
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
|||
<Icon icon="ic:baseline-restart-alt"></Icon>
|
||||
{{ getResetBtnOptions.text }}
|
||||
</Button>
|
||||
<!-- update-end-author:zyf Date:20211213 for:调换按钮前后位置-->
|
||||
<!-- update-end-author:zyf Date:20211213 for:调换按钮前后位置-->
|
||||
|
||||
<slot name="advanceBefore"></slot>
|
||||
<Button type="link" size="small" @click="toggleAdvanced" v-if="showAdvancedButton && !hideAdvanceBtn">
|
||||
|
@ -75,9 +75,7 @@
|
|||
const actionColOpt = computed(() => {
|
||||
const { showAdvancedButton, actionSpan: span, actionColOptions } = props;
|
||||
const actionSpan = 24 - span;
|
||||
const advancedSpanObj = showAdvancedButton
|
||||
? { span: actionSpan < 6 ? 24 : actionSpan }
|
||||
: {};
|
||||
const advancedSpanObj = showAdvancedButton ? { span: actionSpan < 6 ? 24 : actionSpan } : {};
|
||||
const actionColOpt: Partial<ColEx> = {
|
||||
style: { textAlign: 'right' },
|
||||
span: showAdvancedButton ? 6 : 4,
|
||||
|
|
|
@ -1,387 +1,352 @@
|
|||
<script lang="tsx">
|
||||
import type {PropType, Ref} from 'vue';
|
||||
import type {FormActionType, FormProps} from '../types/form';
|
||||
import type {FormSchema} from '../types/form';
|
||||
import type {ValidationRule} from 'ant-design-vue/lib/form/Form';
|
||||
import type {TableActionType} from '/@/components/Table';
|
||||
import {defineComponent, computed, unref, toRefs} from 'vue';
|
||||
import {Form, Col, Divider} from 'ant-design-vue';
|
||||
import {componentMap} from '../componentMap';
|
||||
import {BasicHelp} from '/@/components/Basic';
|
||||
import {isBoolean, isFunction, isNull} from '/@/utils/is';
|
||||
import {getSlot} from '/@/utils/helper/tsxHelper';
|
||||
import {createPlaceholderMessage, setComponentRuleType} from '../helper';
|
||||
import {upperFirst, cloneDeep} from 'lodash-es';
|
||||
import {useItemLabelWidth} from '../hooks/useLabelWidth';
|
||||
import {useI18n} from '/@/hooks/web/useI18n';
|
||||
import type { PropType, Ref } from 'vue';
|
||||
import type { FormActionType, FormProps } from '../types/form';
|
||||
import type { FormSchema } from '../types/form';
|
||||
import type { ValidationRule } from 'ant-design-vue/lib/form/Form';
|
||||
import type { TableActionType } from '/@/components/Table';
|
||||
import { defineComponent, computed, unref, toRefs } from 'vue';
|
||||
import { Form, Col, Divider } from 'ant-design-vue';
|
||||
import { componentMap } from '../componentMap';
|
||||
import { BasicHelp } from '/@/components/Basic';
|
||||
import { isBoolean, isFunction, isNull } from '/@/utils/is';
|
||||
import { getSlot } from '/@/utils/helper/tsxHelper';
|
||||
import { createPlaceholderMessage, setComponentRuleType } from '../helper';
|
||||
import { upperFirst, cloneDeep } from 'lodash-es';
|
||||
import { useItemLabelWidth } from '../hooks/useLabelWidth';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'BasicFormItem',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
schema: {
|
||||
type: Object as PropType<FormSchema>,
|
||||
default: () => ({}),
|
||||
},
|
||||
formProps: {
|
||||
type: Object as PropType<FormProps>,
|
||||
default: () => ({}),
|
||||
},
|
||||
allDefaultValues: {
|
||||
type: Object as PropType<Recordable>,
|
||||
default: () => ({}),
|
||||
},
|
||||
formModel: {
|
||||
type: Object as PropType<Recordable>,
|
||||
default: () => ({}),
|
||||
},
|
||||
setFormModel: {
|
||||
type: Function as PropType<(key: string, value: any) => void>,
|
||||
default: null,
|
||||
},
|
||||
tableAction: {
|
||||
type: Object as PropType<TableActionType>,
|
||||
},
|
||||
formActionType: {
|
||||
type: Object as PropType<FormActionType>,
|
||||
},
|
||||
},
|
||||
setup(props, {slots}) {
|
||||
const {t} = useI18n();
|
||||
export default defineComponent({
|
||||
name: 'BasicFormItem',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
schema: {
|
||||
type: Object as PropType<FormSchema>,
|
||||
default: () => ({}),
|
||||
},
|
||||
formProps: {
|
||||
type: Object as PropType<FormProps>,
|
||||
default: () => ({}),
|
||||
},
|
||||
allDefaultValues: {
|
||||
type: Object as PropType<Recordable>,
|
||||
default: () => ({}),
|
||||
},
|
||||
formModel: {
|
||||
type: Object as PropType<Recordable>,
|
||||
default: () => ({}),
|
||||
},
|
||||
setFormModel: {
|
||||
type: Function as PropType<(key: string, value: any) => void>,
|
||||
default: null,
|
||||
},
|
||||
tableAction: {
|
||||
type: Object as PropType<TableActionType>,
|
||||
},
|
||||
formActionType: {
|
||||
type: Object as PropType<FormActionType>,
|
||||
},
|
||||
},
|
||||
setup(props, { slots }) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const {schema, formProps} = toRefs(props) as {
|
||||
schema: Ref<FormSchema>;
|
||||
formProps: Ref<FormProps>;
|
||||
};
|
||||
const { schema, formProps } = toRefs(props) as {
|
||||
schema: Ref<FormSchema>;
|
||||
formProps: Ref<FormProps>;
|
||||
};
|
||||
|
||||
const itemLabelWidthProp = useItemLabelWidth(schema, formProps);
|
||||
const itemLabelWidthProp = useItemLabelWidth(schema, formProps);
|
||||
|
||||
const getValues = computed(() => {
|
||||
const {allDefaultValues, formModel, schema} = props;
|
||||
const {mergeDynamicData} = props.formProps;
|
||||
return {
|
||||
field: schema.field,
|
||||
model: formModel,
|
||||
values: {
|
||||
...mergeDynamicData,
|
||||
...allDefaultValues,
|
||||
...formModel,
|
||||
} as Recordable,
|
||||
schema: schema,
|
||||
};
|
||||
});
|
||||
const getValues = computed(() => {
|
||||
const { allDefaultValues, formModel, schema } = props;
|
||||
const { mergeDynamicData } = props.formProps;
|
||||
return {
|
||||
field: schema.field,
|
||||
model: formModel,
|
||||
values: {
|
||||
...mergeDynamicData,
|
||||
...allDefaultValues,
|
||||
...formModel,
|
||||
} as Recordable,
|
||||
schema: schema,
|
||||
};
|
||||
});
|
||||
|
||||
const getComponentsProps = computed(() => {
|
||||
const {schema, tableAction, formModel, formActionType} = props;
|
||||
let {componentProps = {}} = schema;
|
||||
if (isFunction(componentProps)) {
|
||||
componentProps = componentProps({schema, tableAction, formModel, formActionType}) ?? {};
|
||||
}
|
||||
if (schema.component === 'Divider') {
|
||||
componentProps = Object.assign({type: 'horizontal'}, componentProps, {
|
||||
orientation: 'left',
|
||||
plain: true,
|
||||
});
|
||||
}
|
||||
return componentProps as Recordable;
|
||||
});
|
||||
const getComponentsProps = computed(() => {
|
||||
const { schema, tableAction, formModel, formActionType } = props;
|
||||
let { componentProps = {} } = schema;
|
||||
if (isFunction(componentProps)) {
|
||||
componentProps = componentProps({ schema, tableAction, formModel, formActionType }) ?? {};
|
||||
}
|
||||
if (schema.component === 'Divider') {
|
||||
componentProps = Object.assign({ type: 'horizontal' }, componentProps, {
|
||||
orientation: 'left',
|
||||
plain: true,
|
||||
});
|
||||
}
|
||||
return componentProps as Recordable;
|
||||
});
|
||||
|
||||
const getDisable = computed(() => {
|
||||
const {disabled: globDisabled} = props.formProps;
|
||||
const {dynamicDisabled} = props.schema;
|
||||
const {disabled: itemDisabled = false} = unref(getComponentsProps);
|
||||
let disabled = !!globDisabled || itemDisabled;
|
||||
if (isBoolean(dynamicDisabled)) {
|
||||
disabled = dynamicDisabled;
|
||||
}
|
||||
if (isFunction(dynamicDisabled)) {
|
||||
disabled = dynamicDisabled(unref(getValues));
|
||||
}
|
||||
return disabled;
|
||||
});
|
||||
const getDisable = computed(() => {
|
||||
const { disabled: globDisabled } = props.formProps;
|
||||
const { dynamicDisabled } = props.schema;
|
||||
const { disabled: itemDisabled = false } = unref(getComponentsProps);
|
||||
let disabled = !!globDisabled || itemDisabled;
|
||||
if (isBoolean(dynamicDisabled)) {
|
||||
disabled = dynamicDisabled;
|
||||
}
|
||||
if (isFunction(dynamicDisabled)) {
|
||||
disabled = dynamicDisabled(unref(getValues));
|
||||
}
|
||||
return disabled;
|
||||
});
|
||||
|
||||
function getShow(): { isShow: boolean; isIfShow: boolean } {
|
||||
const {show, ifShow} = props.schema;
|
||||
const {showAdvancedButton} = props.formProps;
|
||||
const itemIsAdvanced = showAdvancedButton
|
||||
? isBoolean(props.schema.isAdvanced)
|
||||
? props.schema.isAdvanced
|
||||
: true
|
||||
: true;
|
||||
function getShow(): { isShow: boolean; isIfShow: boolean } {
|
||||
const { show, ifShow } = props.schema;
|
||||
const { showAdvancedButton } = props.formProps;
|
||||
const itemIsAdvanced = showAdvancedButton ? (isBoolean(props.schema.isAdvanced) ? props.schema.isAdvanced : true) : true;
|
||||
|
||||
let isShow = true;
|
||||
let isIfShow = true;
|
||||
let isShow = true;
|
||||
let isIfShow = true;
|
||||
|
||||
if (isBoolean(show)) {
|
||||
isShow = show;
|
||||
}
|
||||
if (isBoolean(ifShow)) {
|
||||
isIfShow = ifShow;
|
||||
}
|
||||
if (isFunction(show)) {
|
||||
isShow = show(unref(getValues));
|
||||
}
|
||||
if (isFunction(ifShow)) {
|
||||
isIfShow = ifShow(unref(getValues));
|
||||
}
|
||||
isShow = isShow && itemIsAdvanced;
|
||||
return {isShow, isIfShow};
|
||||
if (isBoolean(show)) {
|
||||
isShow = show;
|
||||
}
|
||||
if (isBoolean(ifShow)) {
|
||||
isIfShow = ifShow;
|
||||
}
|
||||
if (isFunction(show)) {
|
||||
isShow = show(unref(getValues));
|
||||
}
|
||||
if (isFunction(ifShow)) {
|
||||
isIfShow = ifShow(unref(getValues));
|
||||
}
|
||||
isShow = isShow && itemIsAdvanced;
|
||||
return { isShow, isIfShow };
|
||||
}
|
||||
|
||||
function handleRules(): ValidationRule[] {
|
||||
const { rules: defRules = [], component, rulesMessageJoinLabel, label, dynamicRules, required } = props.schema;
|
||||
|
||||
if (isFunction(dynamicRules)) {
|
||||
return dynamicRules(unref(getValues)) as ValidationRule[];
|
||||
}
|
||||
|
||||
let rules: ValidationRule[] = cloneDeep(defRules) as ValidationRule[];
|
||||
const { rulesMessageJoinLabel: globalRulesMessageJoinLabel } = props.formProps;
|
||||
|
||||
const joinLabel = Reflect.has(props.schema, 'rulesMessageJoinLabel') ? rulesMessageJoinLabel : globalRulesMessageJoinLabel;
|
||||
const defaultMsg = createPlaceholderMessage(component) + `${joinLabel ? label : ''}`;
|
||||
|
||||
function validator(rule: any, value: any) {
|
||||
const msg = rule.message || defaultMsg;
|
||||
if (value === undefined || isNull(value)) {
|
||||
// 空值
|
||||
return Promise.reject(msg);
|
||||
} else if (Array.isArray(value) && value.length === 0) {
|
||||
// 数组类型
|
||||
return Promise.reject(msg);
|
||||
} else if (typeof value === 'string' && value.trim() === '') {
|
||||
// 空字符串
|
||||
return Promise.reject(msg);
|
||||
} else if (
|
||||
typeof value === 'object' &&
|
||||
Reflect.has(value, 'checked') &&
|
||||
Reflect.has(value, 'halfChecked') &&
|
||||
Array.isArray(value.checked) &&
|
||||
Array.isArray(value.halfChecked) &&
|
||||
value.checked.length === 0 &&
|
||||
value.halfChecked.length === 0
|
||||
) {
|
||||
// 非关联选择的tree组件
|
||||
return Promise.reject(msg);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const getRequired = isFunction(required) ? required(unref(getValues)) : required;
|
||||
|
||||
if ((!rules || rules.length === 0) && getRequired) {
|
||||
rules = [{ required: getRequired, validator }];
|
||||
}
|
||||
|
||||
const requiredRuleIndex: number = rules.findIndex((rule) => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator'));
|
||||
|
||||
if (requiredRuleIndex !== -1) {
|
||||
const rule = rules[requiredRuleIndex];
|
||||
const { isShow } = getShow();
|
||||
if (!isShow) {
|
||||
rule.required = false;
|
||||
}
|
||||
if (component) {
|
||||
if (!Reflect.has(rule, 'type')) {
|
||||
rule.type = component === 'InputNumber' ? 'number' : 'string';
|
||||
}
|
||||
|
||||
function handleRules(): ValidationRule[] {
|
||||
const {
|
||||
rules: defRules = [],
|
||||
component,
|
||||
rulesMessageJoinLabel,
|
||||
label,
|
||||
dynamicRules,
|
||||
required,
|
||||
} = props.schema;
|
||||
rule.message = rule.message || defaultMsg;
|
||||
|
||||
if (isFunction(dynamicRules)) {
|
||||
return dynamicRules(unref(getValues)) as ValidationRule[];
|
||||
}
|
||||
|
||||
let rules: ValidationRule[] = cloneDeep(defRules) as ValidationRule[];
|
||||
const {rulesMessageJoinLabel: globalRulesMessageJoinLabel} = props.formProps;
|
||||
|
||||
const joinLabel = Reflect.has(props.schema, 'rulesMessageJoinLabel')
|
||||
? rulesMessageJoinLabel
|
||||
: globalRulesMessageJoinLabel;
|
||||
const defaultMsg = createPlaceholderMessage(component) + `${joinLabel ? label : ''}`;
|
||||
|
||||
function validator(rule: any, value: any) {
|
||||
const msg = rule.message || defaultMsg;
|
||||
if (value === undefined || isNull(value)) {
|
||||
// 空值
|
||||
return Promise.reject(msg);
|
||||
} else if (Array.isArray(value) && value.length === 0) {
|
||||
// 数组类型
|
||||
return Promise.reject(msg);
|
||||
} else if (typeof value === 'string' && value.trim() === '') {
|
||||
// 空字符串
|
||||
return Promise.reject(msg);
|
||||
} else if (
|
||||
typeof value === 'object' &&
|
||||
Reflect.has(value, 'checked') &&
|
||||
Reflect.has(value, 'halfChecked') &&
|
||||
Array.isArray(value.checked) &&
|
||||
Array.isArray(value.halfChecked) &&
|
||||
value.checked.length === 0 &&
|
||||
value.halfChecked.length === 0
|
||||
) {
|
||||
// 非关联选择的tree组件
|
||||
return Promise.reject(msg);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const getRequired = isFunction(required) ? required(unref(getValues)) : required;
|
||||
|
||||
if ((!rules || rules.length === 0) && getRequired) {
|
||||
rules = [{required: getRequired, validator}];
|
||||
}
|
||||
|
||||
const requiredRuleIndex: number = rules.findIndex(
|
||||
(rule) => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator')
|
||||
);
|
||||
|
||||
if (requiredRuleIndex !== -1) {
|
||||
const rule = rules[requiredRuleIndex];
|
||||
const {isShow} = getShow();
|
||||
if (!isShow) {
|
||||
rule.required = false;
|
||||
}
|
||||
if (component) {
|
||||
if (!Reflect.has(rule, 'type')) {
|
||||
rule.type = component === 'InputNumber' ? 'number' : 'string';
|
||||
}
|
||||
|
||||
rule.message = rule.message || defaultMsg;
|
||||
|
||||
if (component.includes('Input') || component.includes('Textarea')) {
|
||||
rule.whitespace = true;
|
||||
}
|
||||
const valueFormat = unref(getComponentsProps)?.valueFormat;
|
||||
setComponentRuleType(rule, component, valueFormat);
|
||||
}
|
||||
}
|
||||
|
||||
// Maximum input length rule check
|
||||
const characterInx = rules.findIndex((val) => val.max);
|
||||
if (characterInx !== -1 && !rules[characterInx].validator) {
|
||||
rules[characterInx].message =
|
||||
rules[characterInx].message ||
|
||||
t('component.form.maxTip', [rules[characterInx].max] as Recordable);
|
||||
}
|
||||
return rules;
|
||||
if (component.includes('Input') || component.includes('Textarea')) {
|
||||
rule.whitespace = true;
|
||||
}
|
||||
const valueFormat = unref(getComponentsProps)?.valueFormat;
|
||||
setComponentRuleType(rule, component, valueFormat);
|
||||
}
|
||||
}
|
||||
|
||||
function renderComponent() {
|
||||
const {
|
||||
renderComponentContent,
|
||||
component,
|
||||
field,
|
||||
changeEvent = 'change',
|
||||
valueField,
|
||||
} = props.schema;
|
||||
// Maximum input length rule check
|
||||
const characterInx = rules.findIndex((val) => val.max);
|
||||
if (characterInx !== -1 && !rules[characterInx].validator) {
|
||||
rules[characterInx].message = rules[characterInx].message || t('component.form.maxTip', [rules[characterInx].max] as Recordable);
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
const isCheck = component && ['Switch', 'Checkbox'].includes(component);
|
||||
function renderComponent() {
|
||||
const { renderComponentContent, component, field, changeEvent = 'change', valueField } = props.schema;
|
||||
|
||||
const eventKey = `on${upperFirst(changeEvent)}`;
|
||||
const isCheck = component && ['Switch', 'Checkbox'].includes(component);
|
||||
|
||||
const on = {
|
||||
[eventKey]: (...args: Nullable<Recordable>[]) => {
|
||||
const [e] = args;
|
||||
if (propsData[eventKey]) {
|
||||
propsData[eventKey](...args);
|
||||
}
|
||||
const target = e ? e.target : null;
|
||||
const value = target ? (isCheck ? target.checked : target.value) : e;
|
||||
props.setFormModel(field, value);
|
||||
},
|
||||
};
|
||||
const Comp = componentMap.get(component) as ReturnType<typeof defineComponent>;
|
||||
const eventKey = `on${upperFirst(changeEvent)}`;
|
||||
|
||||
const {autoSetPlaceHolder, size} = props.formProps;
|
||||
const propsData: Recordable = {
|
||||
allowClear: true,
|
||||
getPopupContainer: (trigger: Element) => trigger.parentNode,
|
||||
size,
|
||||
...unref(getComponentsProps),
|
||||
disabled: unref(getDisable),
|
||||
};
|
||||
const on = {
|
||||
[eventKey]: (...args: Nullable<Recordable>[]) => {
|
||||
const [e] = args;
|
||||
if (propsData[eventKey]) {
|
||||
propsData[eventKey](...args);
|
||||
}
|
||||
const target = e ? e.target : null;
|
||||
const value = target ? (isCheck ? target.checked : target.value) : e;
|
||||
props.setFormModel(field, value);
|
||||
},
|
||||
};
|
||||
const Comp = componentMap.get(component) as ReturnType<typeof defineComponent>;
|
||||
|
||||
const { autoSetPlaceHolder, size } = props.formProps;
|
||||
const propsData: Recordable = {
|
||||
allowClear: true,
|
||||
getPopupContainer: (trigger: Element) => trigger.parentNode,
|
||||
size,
|
||||
...unref(getComponentsProps),
|
||||
disabled: unref(getDisable),
|
||||
};
|
||||
|
||||
const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder;
|
||||
// RangePicker place是一个数组
|
||||
if (isCreatePlaceholder && component !== 'RangePicker' && component) {
|
||||
//自动设置placeholder
|
||||
propsData.placeholder =
|
||||
unref(getComponentsProps)?.placeholder ||
|
||||
createPlaceholderMessage(component) + props.schema.label;
|
||||
propsData.placeholder = unref(getComponentsProps)?.placeholder || createPlaceholderMessage(component) + props.schema.label;
|
||||
}
|
||||
propsData.codeField = field;
|
||||
propsData.formValues = unref(getValues);
|
||||
|
||||
const bindValue: Recordable = {
|
||||
[valueField || (isCheck ? 'checked' : 'value')]: props.formModel[field],
|
||||
};
|
||||
const bindValue: Recordable = {
|
||||
[valueField || (isCheck ? 'checked' : 'value')]: props.formModel[field],
|
||||
};
|
||||
|
||||
const compAttr: Recordable = {
|
||||
...propsData,
|
||||
...on,
|
||||
...bindValue,
|
||||
};
|
||||
const compAttr: Recordable = {
|
||||
...propsData,
|
||||
...on,
|
||||
...bindValue,
|
||||
};
|
||||
|
||||
if (!renderComponentContent) {
|
||||
return <Comp {...compAttr} />;
|
||||
}
|
||||
const compSlot = isFunction(renderComponentContent)
|
||||
? {...renderComponentContent(unref(getValues))}
|
||||
: {
|
||||
default: () => renderComponentContent,
|
||||
};
|
||||
return <Comp {...compAttr}>{compSlot}</Comp>;
|
||||
}
|
||||
if (!renderComponentContent) {
|
||||
return <Comp {...compAttr} />;
|
||||
}
|
||||
const compSlot = isFunction(renderComponentContent)
|
||||
? { ...renderComponentContent(unref(getValues)) }
|
||||
: {
|
||||
default: () => renderComponentContent,
|
||||
};
|
||||
return <Comp {...compAttr}>{compSlot}</Comp>;
|
||||
}
|
||||
|
||||
/**
|
||||
*渲染Label
|
||||
* @updateBy:zyf
|
||||
*/
|
||||
function renderLabelHelpMessage() {
|
||||
const {label, helpMessage, helpComponentProps, subLabel} = props.schema;
|
||||
const renderLabel = subLabel ? (
|
||||
<span>
|
||||
/**
|
||||
*渲染Label
|
||||
* @updateBy:zyf
|
||||
*/
|
||||
function renderLabelHelpMessage() {
|
||||
const { label, helpMessage, helpComponentProps, subLabel } = props.schema;
|
||||
const renderLabel = subLabel ? (
|
||||
<span>
|
||||
{label} <span class="text-secondary">{subLabel}</span>
|
||||
</span>
|
||||
) : (
|
||||
label
|
||||
);
|
||||
const getHelpMessage = isFunction(helpMessage)
|
||||
? helpMessage(unref(getValues))
|
||||
: helpMessage;
|
||||
if (!getHelpMessage || (Array.isArray(getHelpMessage) && getHelpMessage.length === 0)) {
|
||||
return renderLabel;
|
||||
}
|
||||
return (
|
||||
<span>
|
||||
) : (
|
||||
label
|
||||
);
|
||||
const getHelpMessage = isFunction(helpMessage) ? helpMessage(unref(getValues)) : helpMessage;
|
||||
if (!getHelpMessage || (Array.isArray(getHelpMessage) && getHelpMessage.length === 0)) {
|
||||
return renderLabel;
|
||||
}
|
||||
return (
|
||||
<span>
|
||||
{renderLabel}
|
||||
<BasicHelp placement="top" class="mx-1" text={getHelpMessage} {...helpComponentProps} />
|
||||
<BasicHelp placement="top" class="mx-1" text={getHelpMessage} {...helpComponentProps} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function renderItem() {
|
||||
const {itemProps, slot, render, field, suffix, component} = props.schema;
|
||||
const {labelCol, wrapperCol} = unref(itemLabelWidthProp);
|
||||
const {colon} = props.formProps;
|
||||
function renderItem() {
|
||||
const { itemProps, slot, render, field, suffix, component } = props.schema;
|
||||
const { labelCol, wrapperCol } = unref(itemLabelWidthProp);
|
||||
const { colon } = props.formProps;
|
||||
|
||||
if (component === 'Divider') {
|
||||
return (
|
||||
<Col span={24}>
|
||||
<Divider {...unref(getComponentsProps)}>{renderLabelHelpMessage()}</Divider>
|
||||
</Col>
|
||||
);
|
||||
} else {
|
||||
const getContent = () => {
|
||||
return slot
|
||||
? getSlot(slots, slot, unref(getValues))
|
||||
: render
|
||||
? render(unref(getValues))
|
||||
: renderComponent();
|
||||
};
|
||||
if (component === 'Divider') {
|
||||
return (
|
||||
<Col span={24}>
|
||||
<Divider {...unref(getComponentsProps)}>{renderLabelHelpMessage()}</Divider>
|
||||
</Col>
|
||||
);
|
||||
} else {
|
||||
const getContent = () => {
|
||||
return slot ? getSlot(slots, slot, unref(getValues)) : render ? render(unref(getValues)) : renderComponent();
|
||||
};
|
||||
|
||||
const showSuffix = !!suffix;
|
||||
const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix;
|
||||
const showSuffix = !!suffix;
|
||||
const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix;
|
||||
|
||||
return (
|
||||
<Form.Item
|
||||
name={field}
|
||||
colon={colon}
|
||||
class={{'suffix-item': showSuffix}}
|
||||
{...(itemProps as Recordable)}
|
||||
label={renderLabelHelpMessage()}
|
||||
rules={handleRules()}
|
||||
labelCol={labelCol}
|
||||
wrapperCol={wrapperCol}
|
||||
>
|
||||
<div style="display:flex">
|
||||
{/* author: sunjianlei for: 【VUEN-744】此处加上 width: 100%; 因为要防止组件宽度超出 FormItem */ }
|
||||
<div style="flex:1; width: 100%;">{getContent()}</div>
|
||||
{showSuffix && <span class="suffix">{getSuffix}</span>}
|
||||
</div>
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Form.Item
|
||||
name={field}
|
||||
colon={colon}
|
||||
class={{ 'suffix-item': showSuffix }}
|
||||
{...(itemProps as Recordable)}
|
||||
label={renderLabelHelpMessage()}
|
||||
rules={handleRules()}
|
||||
labelCol={labelCol}
|
||||
wrapperCol={wrapperCol}
|
||||
>
|
||||
<div style="display:flex">
|
||||
{/* author: sunjianlei for: 【VUEN-744】此处加上 width: 100%; 因为要防止组件宽度超出 FormItem */}
|
||||
<div style="flex:1; width: 100%;">{getContent()}</div>
|
||||
{showSuffix && <span class="suffix">{getSuffix}</span>}
|
||||
</div>
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
const {colProps = {}, colSlot, renderColContent, component} = props.schema;
|
||||
if (!componentMap.has(component)) {
|
||||
return null;
|
||||
}
|
||||
return () => {
|
||||
const { colProps = {}, colSlot, renderColContent, component } = props.schema;
|
||||
if (!componentMap.has(component)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {baseColProps = {}} = props.formProps;
|
||||
const realColProps = {...baseColProps, ...colProps};
|
||||
const {isIfShow, isShow} = getShow();
|
||||
const values = unref(getValues);
|
||||
const { baseColProps = {} } = props.formProps;
|
||||
const realColProps = { ...baseColProps, ...colProps };
|
||||
const { isIfShow, isShow } = getShow();
|
||||
const values = unref(getValues);
|
||||
|
||||
const getContent = () => {
|
||||
return colSlot
|
||||
? getSlot(slots, colSlot, values)
|
||||
: renderColContent
|
||||
? renderColContent(values)
|
||||
: renderItem();
|
||||
};
|
||||
const getContent = () => {
|
||||
return colSlot ? getSlot(slots, colSlot, values) : renderColContent ? renderColContent(values) : renderItem();
|
||||
};
|
||||
|
||||
return (
|
||||
isIfShow && (
|
||||
<Col {...realColProps} v-show={isShow}>
|
||||
{getContent()}
|
||||
</Col>
|
||||
)
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
return (
|
||||
isIfShow && (
|
||||
<Col {...realColProps} v-show={isShow}>
|
||||
{getContent()}
|
||||
</Col>
|
||||
)
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -16,13 +16,7 @@ export function createPlaceholderMessage(component: ComponentType) {
|
|||
if (component.includes('Picker')) {
|
||||
return t('common.chooseText');
|
||||
}
|
||||
if (
|
||||
component.includes('Select') ||
|
||||
component.includes('Cascader') ||
|
||||
component.includes('Checkbox') ||
|
||||
component.includes('Radio') ||
|
||||
component.includes('Switch')
|
||||
) {
|
||||
if (component.includes('Select') || component.includes('Cascader') || component.includes('Checkbox') || component.includes('Radio') || component.includes('Switch')) {
|
||||
// return `请选择${label}`;
|
||||
return t('common.chooseText');
|
||||
}
|
||||
|
@ -35,11 +29,7 @@ function genType() {
|
|||
return [...DATE_TYPE, 'RangePicker'];
|
||||
}
|
||||
|
||||
export function setComponentRuleType(
|
||||
rule: ValidationRule,
|
||||
component: ComponentType,
|
||||
valueFormat: string
|
||||
) {
|
||||
export function setComponentRuleType(rule: ValidationRule, component: ComponentType, valueFormat: string) {
|
||||
if (['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'].includes(component)) {
|
||||
rule.type = valueFormat ? 'string' : 'object';
|
||||
} else if (['RangePicker', 'Upload', 'CheckboxGroup', 'TimePicker'].includes(component)) {
|
||||
|
|
|
@ -18,14 +18,7 @@ interface UseAdvancedContext {
|
|||
defaultValueRef: Ref<Recordable>;
|
||||
}
|
||||
|
||||
export default function ({
|
||||
advanceState,
|
||||
emit,
|
||||
getProps,
|
||||
getSchema,
|
||||
formModel,
|
||||
defaultValueRef,
|
||||
}: UseAdvancedContext) {
|
||||
export default function ({ advanceState, emit, getProps, getSchema, formModel, defaultValueRef }: UseAdvancedContext) {
|
||||
const { realWidthRef, screenEnum, screenRef } = useBreakpoint();
|
||||
|
||||
const getEmptySpan = computed((): number => {
|
||||
|
@ -51,25 +44,20 @@ export default function ({
|
|||
const debounceUpdateAdvanced = useDebounceFn(updateAdvanced, 30);
|
||||
|
||||
watch(
|
||||
[() => unref(getSchema), () => advanceState.isAdvanced, () => unref(realWidthRef)],
|
||||
() => {
|
||||
const { showAdvancedButton } = unref(getProps);
|
||||
if (showAdvancedButton) {
|
||||
debounceUpdateAdvanced();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
[() => unref(getSchema), () => advanceState.isAdvanced, () => unref(realWidthRef)],
|
||||
() => {
|
||||
const { showAdvancedButton } = unref(getProps);
|
||||
if (showAdvancedButton) {
|
||||
debounceUpdateAdvanced();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
function getAdvanced(itemCol: Partial<ColEx>, itemColSum = 0, isLastAction = false, index = 0) {
|
||||
const width = unref(realWidthRef);
|
||||
|
||||
const mdWidth =
|
||||
parseInt(itemCol.md as string) ||
|
||||
parseInt(itemCol.xs as string) ||
|
||||
parseInt(itemCol.sm as string) ||
|
||||
(itemCol.span as number) ||
|
||||
BASIC_COL_LEN;
|
||||
const mdWidth = parseInt(itemCol.md as string) || parseInt(itemCol.xs as string) || parseInt(itemCol.sm as string) || (itemCol.span as number) || BASIC_COL_LEN;
|
||||
|
||||
const lgWidth = parseInt(itemCol.lg as string) || mdWidth;
|
||||
const xlWidth = parseInt(itemCol.xl as string) || lgWidth;
|
||||
|
@ -84,7 +72,7 @@ export default function ({
|
|||
itemColSum += xxlWidth;
|
||||
}
|
||||
|
||||
let autoAdvancedCol = (unref(getProps).autoAdvancedCol ?? 3)
|
||||
let autoAdvancedCol = unref(getProps).autoAdvancedCol ?? 3;
|
||||
|
||||
if (isLastAction) {
|
||||
advanceState.hideAdvanceBtn = unref(getSchema).length <= autoAdvancedCol;
|
||||
|
@ -95,10 +83,7 @@ export default function ({
|
|||
advanceState.isAdvanced = true;
|
||||
} else */
|
||||
// update-end--author:sunjianlei---date:20211108---for: 注释掉该逻辑,使小于等于2行时,也显示展开收起按钮
|
||||
if (
|
||||
itemColSum > BASIC_COL_LEN * 2 &&
|
||||
itemColSum <= BASIC_COL_LEN * (unref(getProps).autoAdvancedLine || 3)
|
||||
) {
|
||||
if (itemColSum > BASIC_COL_LEN * 2 && itemColSum <= BASIC_COL_LEN * (unref(getProps).autoAdvancedLine || 3)) {
|
||||
advanceState.hideAdvanceBtn = false;
|
||||
|
||||
// 默认超过 3 行折叠
|
||||
|
@ -107,8 +92,8 @@ export default function ({
|
|||
advanceState.isAdvanced = !advanceState.isAdvanced;
|
||||
// update-begin--author:sunjianlei---date:20211108---for: 如果总列数大于 autoAdvancedCol,就默认折叠
|
||||
if (unref(getSchema).length > autoAdvancedCol) {
|
||||
advanceState.hideAdvanceBtn = false
|
||||
advanceState.isAdvanced = false
|
||||
advanceState.hideAdvanceBtn = false;
|
||||
advanceState.isAdvanced = false;
|
||||
}
|
||||
// update-end--author:sunjianlei---date:20211108---for: 如果总列数大于 autoAdvancedCol,就默认折叠
|
||||
}
|
||||
|
@ -116,9 +101,9 @@ export default function ({
|
|||
}
|
||||
if (itemColSum > BASIC_COL_LEN * (unref(getProps).alwaysShowLines || 1)) {
|
||||
return { isAdvanced: advanceState.isAdvanced, itemColSum };
|
||||
} else if (!advanceState.isAdvanced && (index + 1) > autoAdvancedCol) {
|
||||
} else if (!advanceState.isAdvanced && index + 1 > autoAdvancedCol) {
|
||||
// 如果当前是收起状态,并且当前列下标 > autoAdvancedCol,就隐藏
|
||||
return { isAdvanced: false, itemColSum }
|
||||
return { isAdvanced: false, itemColSum };
|
||||
} else {
|
||||
// The first line is always displayed
|
||||
return { isAdvanced: true, itemColSum };
|
||||
|
@ -130,9 +115,9 @@ export default function ({
|
|||
let realItemColSum = 0;
|
||||
const { baseColProps = {} } = unref(getProps);
|
||||
|
||||
const schemas = unref(getSchema)
|
||||
const schemas = unref(getSchema);
|
||||
for (let i = 0; i < schemas.length; i++) {
|
||||
const schema = schemas[i]
|
||||
const schema = schemas[i];
|
||||
const { show, colProps } = schema;
|
||||
let isShow = true;
|
||||
|
||||
|
@ -153,10 +138,7 @@ export default function ({
|
|||
}
|
||||
|
||||
if (isShow && (colProps || baseColProps)) {
|
||||
const { itemColSum: sum, isAdvanced } = getAdvanced(
|
||||
{ ...baseColProps, ...colProps },
|
||||
itemColSum, false, i,
|
||||
);
|
||||
const { itemColSum: sum, isAdvanced } = getAdvanced({ ...baseColProps, ...colProps }, itemColSum, false, i);
|
||||
|
||||
itemColSum = sum || 0;
|
||||
if (isAdvanced) {
|
||||
|
|
|
@ -9,12 +9,7 @@ interface UseAutoFocusContext {
|
|||
isInitedDefault: Ref<boolean>;
|
||||
formElRef: Ref<FormActionType>;
|
||||
}
|
||||
export async function useAutoFocus({
|
||||
getSchema,
|
||||
getProps,
|
||||
formElRef,
|
||||
isInitedDefault,
|
||||
}: UseAutoFocusContext) {
|
||||
export async function useAutoFocus({ getSchema, getProps, formElRef, isInitedDefault }: UseAutoFocusContext) {
|
||||
watchEffect(async () => {
|
||||
if (unref(isInitedDefault) || !unref(getProps).autoFocusFirstItem) {
|
||||
return;
|
||||
|
|
|
@ -12,101 +12,95 @@ export declare type ValidateFields = (nameList?: NamePath[]) => Promise<Recordab
|
|||
type Props = Partial<DynamicProps<FormProps>>;
|
||||
|
||||
export function useForm(props?: Props): UseFormReturnType {
|
||||
const formRef = ref<Nullable<FormActionType>>(null);
|
||||
const loadedRef = ref<Nullable<boolean>>(false);
|
||||
const formRef = ref<Nullable<FormActionType>>(null);
|
||||
const loadedRef = ref<Nullable<boolean>>(false);
|
||||
|
||||
async function getForm() {
|
||||
const form = unref(formRef);
|
||||
if (!form) {
|
||||
error(
|
||||
'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!'
|
||||
);
|
||||
}
|
||||
await nextTick();
|
||||
return form as FormActionType;
|
||||
async function getForm() {
|
||||
const form = unref(formRef);
|
||||
if (!form) {
|
||||
error('The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!');
|
||||
}
|
||||
await nextTick();
|
||||
return form as FormActionType;
|
||||
}
|
||||
|
||||
function register(instance: FormActionType) {
|
||||
isProdMode() &&
|
||||
onUnmounted(() => {
|
||||
formRef.value = null;
|
||||
loadedRef.value = null;
|
||||
});
|
||||
if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return;
|
||||
function register(instance: FormActionType) {
|
||||
isProdMode() &&
|
||||
onUnmounted(() => {
|
||||
formRef.value = null;
|
||||
loadedRef.value = null;
|
||||
});
|
||||
if (unref(loadedRef) && isProdMode() && instance === unref(formRef)) return;
|
||||
|
||||
formRef.value = instance;
|
||||
loadedRef.value = true;
|
||||
formRef.value = instance;
|
||||
loadedRef.value = true;
|
||||
|
||||
watch(
|
||||
() => props,
|
||||
() => {
|
||||
props && instance.setProps(getDynamicProps(props));
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
watch(
|
||||
() => props,
|
||||
() => {
|
||||
props && instance.setProps(getDynamicProps(props));
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const methods: FormActionType = {
|
||||
scrollToField: async (name: NamePath, options?: ScrollOptions | undefined) => {
|
||||
const form = await getForm();
|
||||
form.scrollToField(name, options);
|
||||
},
|
||||
setProps: async (formProps: Partial<FormProps>) => {
|
||||
const form = await getForm();
|
||||
form.setProps(formProps);
|
||||
},
|
||||
const methods: FormActionType = {
|
||||
scrollToField: async (name: NamePath, options?: ScrollOptions | undefined) => {
|
||||
const form = await getForm();
|
||||
form.scrollToField(name, options);
|
||||
},
|
||||
setProps: async (formProps: Partial<FormProps>) => {
|
||||
const form = await getForm();
|
||||
form.setProps(formProps);
|
||||
},
|
||||
|
||||
updateSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
|
||||
const form = await getForm();
|
||||
form.updateSchema(data);
|
||||
},
|
||||
updateSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
|
||||
const form = await getForm();
|
||||
form.updateSchema(data);
|
||||
},
|
||||
|
||||
resetSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
|
||||
const form = await getForm();
|
||||
form.resetSchema(data);
|
||||
},
|
||||
resetSchema: async (data: Partial<FormSchema> | Partial<FormSchema>[]) => {
|
||||
const form = await getForm();
|
||||
form.resetSchema(data);
|
||||
},
|
||||
|
||||
clearValidate: async (name?: string | string[]) => {
|
||||
const form = await getForm();
|
||||
form.clearValidate(name);
|
||||
},
|
||||
clearValidate: async (name?: string | string[]) => {
|
||||
const form = await getForm();
|
||||
form.clearValidate(name);
|
||||
},
|
||||
|
||||
resetFields: async () => {
|
||||
getForm().then(async (form) => {
|
||||
await form.resetFields();
|
||||
});
|
||||
},
|
||||
resetFields: async () => {
|
||||
getForm().then(async (form) => {
|
||||
await form.resetFields();
|
||||
});
|
||||
},
|
||||
|
||||
removeSchemaByFiled: async (field: string | string[]) => {
|
||||
unref(formRef)?.removeSchemaByFiled(field);
|
||||
},
|
||||
removeSchemaByFiled: async (field: string | string[]) => {
|
||||
unref(formRef)?.removeSchemaByFiled(field);
|
||||
},
|
||||
|
||||
// TODO promisify
|
||||
getFieldsValue: <T>() => {
|
||||
return unref(formRef)?.getFieldsValue() as T;
|
||||
},
|
||||
// TODO promisify
|
||||
getFieldsValue: <T>() => {
|
||||
return unref(formRef)?.getFieldsValue() as T;
|
||||
},
|
||||
|
||||
setFieldsValue: async <T>(values: T) => {
|
||||
const form = await getForm();
|
||||
form.setFieldsValue<T>(values);
|
||||
},
|
||||
setFieldsValue: async <T>(values: T) => {
|
||||
const form = await getForm();
|
||||
form.setFieldsValue<T>(values);
|
||||
},
|
||||
|
||||
appendSchemaByField: async (
|
||||
schema: FormSchema,
|
||||
prefixField: string | undefined,
|
||||
first: boolean
|
||||
) => {
|
||||
const form = await getForm();
|
||||
form.appendSchemaByField(schema, prefixField, first);
|
||||
},
|
||||
appendSchemaByField: async (schema: FormSchema, prefixField: string | undefined, first: boolean) => {
|
||||
const form = await getForm();
|
||||
form.appendSchemaByField(schema, prefixField, first);
|
||||
},
|
||||
|
||||
submit: async (): Promise<any> => {
|
||||
const form = await getForm();
|
||||
return form.submit();
|
||||
},
|
||||
submit: async (): Promise<any> => {
|
||||
const form = await getForm();
|
||||
return form.submit();
|
||||
},
|
||||
|
||||
/**
|
||||
* 表单验证并返回表单值
|
||||
|
@ -125,9 +119,9 @@ export function useForm(props?: Props): UseFormReturnType {
|
|||
}
|
||||
}
|
||||
}
|
||||
//--@updateBy-begin----author:liusq---date:20210916------for:处理区域事件字典信息------
|
||||
return handleRangeValue(props,values);
|
||||
//--@updateBy-end----author:liusq---date:20210916------for:处理区域事件字典信息------
|
||||
//--@updateBy-begin----author:liusq---date:20210916------for:处理区域事件字典信息------
|
||||
return handleRangeValue(props, values);
|
||||
//--@updateBy-end----author:liusq---date:20210916------for:处理区域事件字典信息------
|
||||
});
|
||||
return values;
|
||||
},
|
||||
|
|
|
@ -10,266 +10,249 @@ import { cloneDeep, uniqBy } from 'lodash-es';
|
|||
import { error } from '/@/utils/log';
|
||||
|
||||
interface UseFormActionContext {
|
||||
emit: EmitType;
|
||||
getProps: ComputedRef<FormProps>;
|
||||
getSchema: ComputedRef<FormSchema[]>;
|
||||
formModel: Recordable;
|
||||
defaultValueRef: Ref<Recordable>;
|
||||
formElRef: Ref<FormActionType>;
|
||||
schemaRef: Ref<FormSchema[]>;
|
||||
handleFormValues: Fn;
|
||||
emit: EmitType;
|
||||
getProps: ComputedRef<FormProps>;
|
||||
getSchema: ComputedRef<FormSchema[]>;
|
||||
formModel: Recordable;
|
||||
defaultValueRef: Ref<Recordable>;
|
||||
formElRef: Ref<FormActionType>;
|
||||
schemaRef: Ref<FormSchema[]>;
|
||||
handleFormValues: Fn;
|
||||
}
|
||||
export function useFormEvents({
|
||||
emit,
|
||||
getProps,
|
||||
formModel,
|
||||
getSchema,
|
||||
defaultValueRef,
|
||||
formElRef,
|
||||
schemaRef,
|
||||
handleFormValues,
|
||||
}: UseFormActionContext) {
|
||||
async function resetFields(): Promise<void> {
|
||||
const { resetFunc, submitOnReset } = unref(getProps);
|
||||
resetFunc && isFunction(resetFunc) && (await resetFunc());
|
||||
export function useFormEvents({ emit, getProps, formModel, getSchema, defaultValueRef, formElRef, schemaRef, handleFormValues }: UseFormActionContext) {
|
||||
async function resetFields(): Promise<void> {
|
||||
const { resetFunc, submitOnReset } = unref(getProps);
|
||||
resetFunc && isFunction(resetFunc) && (await resetFunc());
|
||||
|
||||
const formEl = unref(formElRef);
|
||||
if (!formEl) return;
|
||||
const formEl = unref(formElRef);
|
||||
if (!formEl) return;
|
||||
|
||||
Object.keys(formModel).forEach((key) => {
|
||||
formModel[key] = defaultValueRef.value[key];
|
||||
});
|
||||
clearValidate();
|
||||
emit('reset', toRaw(formModel));
|
||||
submitOnReset && handleSubmit();
|
||||
}
|
||||
Object.keys(formModel).forEach((key) => {
|
||||
formModel[key] = defaultValueRef.value[key];
|
||||
});
|
||||
clearValidate();
|
||||
emit('reset', toRaw(formModel));
|
||||
submitOnReset && handleSubmit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Set form value
|
||||
*/
|
||||
async function setFieldsValue(values: Recordable): Promise<void> {
|
||||
const fields = unref(getSchema)
|
||||
.map((item) => item.field)
|
||||
.filter(Boolean);
|
||||
/**
|
||||
* @description: Set form value
|
||||
*/
|
||||
async function setFieldsValue(values: Recordable): Promise<void> {
|
||||
const fields = unref(getSchema)
|
||||
.map((item) => item.field)
|
||||
.filter(Boolean);
|
||||
|
||||
const validKeys: string[] = [];
|
||||
Object.keys(values).forEach((key) => {
|
||||
const schema = unref(getSchema).find((item) => item.field === key);
|
||||
let value = values[key];
|
||||
const validKeys: string[] = [];
|
||||
Object.keys(values).forEach((key) => {
|
||||
const schema = unref(getSchema).find((item) => item.field === key);
|
||||
let value = values[key];
|
||||
|
||||
const hasKey = Reflect.has(values, key);
|
||||
const hasKey = Reflect.has(values, key);
|
||||
|
||||
value = handleInputNumberValue(schema?.component, value);
|
||||
// 0| '' is allow
|
||||
if (hasKey && fields.includes(key)) {
|
||||
// time type
|
||||
if (itemIsDateType(key)) {
|
||||
if (Array.isArray(value)) {
|
||||
const arr: any[] = [];
|
||||
for (const ele of value) {
|
||||
arr.push(ele ? dateUtil(ele) : null);
|
||||
}
|
||||
formModel[key] = arr;
|
||||
} else {
|
||||
const { componentProps } = schema || {};
|
||||
let _props = componentProps as any;
|
||||
if (typeof componentProps === 'function') {
|
||||
_props = _props({ formModel });
|
||||
}
|
||||
formModel[key] = value ? (_props?.valueFormat ? value : dateUtil(value)) : null;
|
||||
}
|
||||
} else {
|
||||
formModel[key] = value;
|
||||
}
|
||||
validKeys.push(key);
|
||||
value = handleInputNumberValue(schema?.component, value);
|
||||
// 0| '' is allow
|
||||
if (hasKey && fields.includes(key)) {
|
||||
// time type
|
||||
if (itemIsDateType(key)) {
|
||||
if (Array.isArray(value)) {
|
||||
const arr: any[] = [];
|
||||
for (const ele of value) {
|
||||
arr.push(ele ? dateUtil(ele) : null);
|
||||
}
|
||||
});
|
||||
validateFields(validKeys).catch((_) => {});
|
||||
}
|
||||
/**
|
||||
* @description: Delete based on field name
|
||||
*/
|
||||
async function removeSchemaByFiled(fields: string | string[]): Promise<void> {
|
||||
const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
|
||||
if (!fields) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fieldList: string[] = isString(fields) ? [fields] : fields;
|
||||
if (isString(fields)) {
|
||||
fieldList = [fields];
|
||||
}
|
||||
for (const field of fieldList) {
|
||||
_removeSchemaByFiled(field, schemaList);
|
||||
}
|
||||
schemaRef.value = schemaList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Delete based on field name
|
||||
*/
|
||||
function _removeSchemaByFiled(field: string, schemaList: FormSchema[]): void {
|
||||
if (isString(field)) {
|
||||
const index = schemaList.findIndex((schema) => schema.field === field);
|
||||
if (index !== -1) {
|
||||
delete formModel[field];
|
||||
schemaList.splice(index, 1);
|
||||
formModel[key] = arr;
|
||||
} else {
|
||||
const { componentProps } = schema || {};
|
||||
let _props = componentProps as any;
|
||||
if (typeof componentProps === 'function') {
|
||||
_props = _props({ formModel });
|
||||
}
|
||||
formModel[key] = value ? (_props?.valueFormat ? value : dateUtil(value)) : null;
|
||||
}
|
||||
} else {
|
||||
formModel[key] = value;
|
||||
}
|
||||
validKeys.push(key);
|
||||
}
|
||||
});
|
||||
validateFields(validKeys).catch((_) => {});
|
||||
}
|
||||
/**
|
||||
* @description: Delete based on field name
|
||||
*/
|
||||
async function removeSchemaByFiled(fields: string | string[]): Promise<void> {
|
||||
const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
|
||||
if (!fields) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Insert after a certain field, if not insert the last
|
||||
*/
|
||||
async function appendSchemaByField(schema: FormSchema, prefixField?: string, first = false) {
|
||||
const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
|
||||
let fieldList: string[] = isString(fields) ? [fields] : fields;
|
||||
if (isString(fields)) {
|
||||
fieldList = [fields];
|
||||
}
|
||||
for (const field of fieldList) {
|
||||
_removeSchemaByFiled(field, schemaList);
|
||||
}
|
||||
schemaRef.value = schemaList;
|
||||
}
|
||||
|
||||
const index = schemaList.findIndex((schema) => schema.field === prefixField);
|
||||
const hasInList = schemaList.some((item) => item.field === prefixField || schema.field);
|
||||
/**
|
||||
* @description: Delete based on field name
|
||||
*/
|
||||
function _removeSchemaByFiled(field: string, schemaList: FormSchema[]): void {
|
||||
if (isString(field)) {
|
||||
const index = schemaList.findIndex((schema) => schema.field === field);
|
||||
if (index !== -1) {
|
||||
delete formModel[field];
|
||||
schemaList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasInList) return;
|
||||
/**
|
||||
* @description: Insert after a certain field, if not insert the last
|
||||
*/
|
||||
async function appendSchemaByField(schema: FormSchema, prefixField?: string, first = false) {
|
||||
const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
|
||||
|
||||
if (!prefixField || index === -1 || first) {
|
||||
first ? schemaList.unshift(schema) : schemaList.push(schema);
|
||||
schemaRef.value = schemaList;
|
||||
return;
|
||||
}
|
||||
if (index !== -1) {
|
||||
schemaList.splice(index + 1, 0, schema);
|
||||
}
|
||||
schemaRef.value = schemaList;
|
||||
const index = schemaList.findIndex((schema) => schema.field === prefixField);
|
||||
const hasInList = schemaList.some((item) => item.field === prefixField || schema.field);
|
||||
|
||||
if (!hasInList) return;
|
||||
|
||||
if (!prefixField || index === -1 || first) {
|
||||
first ? schemaList.unshift(schema) : schemaList.push(schema);
|
||||
schemaRef.value = schemaList;
|
||||
return;
|
||||
}
|
||||
if (index !== -1) {
|
||||
schemaList.splice(index + 1, 0, schema);
|
||||
}
|
||||
schemaRef.value = schemaList;
|
||||
}
|
||||
|
||||
async function resetSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
|
||||
let updateData: Partial<FormSchema>[] = [];
|
||||
if (isObject(data)) {
|
||||
updateData.push(data as FormSchema);
|
||||
}
|
||||
if (isArray(data)) {
|
||||
updateData = [...data];
|
||||
}
|
||||
|
||||
async function resetSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
|
||||
let updateData: Partial<FormSchema>[] = [];
|
||||
if (isObject(data)) {
|
||||
updateData.push(data as FormSchema);
|
||||
const hasField = updateData.every((item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field));
|
||||
|
||||
if (!hasField) {
|
||||
error('All children of the form Schema array that need to be updated must contain the `field` field');
|
||||
return;
|
||||
}
|
||||
schemaRef.value = updateData as FormSchema[];
|
||||
}
|
||||
|
||||
async function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
|
||||
let updateData: Partial<FormSchema>[] = [];
|
||||
if (isObject(data)) {
|
||||
updateData.push(data as FormSchema);
|
||||
}
|
||||
if (isArray(data)) {
|
||||
updateData = [...data];
|
||||
}
|
||||
|
||||
const hasField = updateData.every((item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field));
|
||||
|
||||
if (!hasField) {
|
||||
error('All children of the form Schema array that need to be updated must contain the `field` field');
|
||||
return;
|
||||
}
|
||||
const schema: FormSchema[] = [];
|
||||
updateData.forEach((item) => {
|
||||
unref(getSchema).forEach((val) => {
|
||||
if (val.field === item.field) {
|
||||
const newSchema = deepMerge(val, item);
|
||||
schema.push(newSchema as FormSchema);
|
||||
} else {
|
||||
schema.push(val);
|
||||
}
|
||||
if (isArray(data)) {
|
||||
updateData = [...data];
|
||||
});
|
||||
});
|
||||
schemaRef.value = uniqBy(schema, 'field');
|
||||
}
|
||||
|
||||
function getFieldsValue(): Recordable {
|
||||
const formEl = unref(formElRef);
|
||||
if (!formEl) return {};
|
||||
return handleFormValues(toRaw(unref(formModel)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Is it time
|
||||
*/
|
||||
function itemIsDateType(key: string) {
|
||||
return unref(getSchema).some((item) => {
|
||||
return item.field === key ? dateItemType.includes(item.component) : false;
|
||||
});
|
||||
}
|
||||
|
||||
async function validateFields(nameList?: NamePath[] | undefined) {
|
||||
return unref(formElRef)?.validateFields(nameList);
|
||||
}
|
||||
|
||||
async function validate(nameList?: NamePath[] | undefined) {
|
||||
return await unref(formElRef)?.validate(nameList);
|
||||
}
|
||||
|
||||
async function clearValidate(name?: string | string[]) {
|
||||
await unref(formElRef)?.clearValidate(name);
|
||||
}
|
||||
|
||||
async function scrollToField(name: NamePath, options?: ScrollOptions | undefined) {
|
||||
await unref(formElRef)?.scrollToField(name, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Form submission
|
||||
*/
|
||||
async function handleSubmit(e?: Event): Promise<void> {
|
||||
e && e.preventDefault();
|
||||
const { submitFunc } = unref(getProps);
|
||||
if (submitFunc && isFunction(submitFunc)) {
|
||||
await submitFunc();
|
||||
return;
|
||||
}
|
||||
const formEl = unref(formElRef);
|
||||
if (!formEl) return;
|
||||
try {
|
||||
const values = await validate();
|
||||
//update-begin---author:zhangdaihao Date:20140212 for:[bug号]树机构调整------------
|
||||
//--updateBy-begin----author:zyf---date:20211206------for:对查询表单提交的数组处理成字符串------
|
||||
for (let key in values) {
|
||||
if (values[key] instanceof Array) {
|
||||
let valueType = getValueType(getProps, key);
|
||||
if (valueType === 'string') {
|
||||
values[key] = values[key].join(',');
|
||||
}
|
||||
}
|
||||
|
||||
const hasField = updateData.every(
|
||||
(item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field)
|
||||
);
|
||||
|
||||
if (!hasField) {
|
||||
error(
|
||||
'All children of the form Schema array that need to be updated must contain the `field` field'
|
||||
);
|
||||
return;
|
||||
}
|
||||
schemaRef.value = updateData as FormSchema[];
|
||||
}
|
||||
//--updateBy-end----author:zyf---date:20211206------for:对查询表单提交的数组处理成字符串------
|
||||
const res = handleFormValues(values);
|
||||
emit('submit', res);
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
|
||||
let updateData: Partial<FormSchema>[] = [];
|
||||
if (isObject(data)) {
|
||||
updateData.push(data as FormSchema);
|
||||
}
|
||||
if (isArray(data)) {
|
||||
updateData = [...data];
|
||||
}
|
||||
|
||||
const hasField = updateData.every(
|
||||
(item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field)
|
||||
);
|
||||
|
||||
if (!hasField) {
|
||||
error(
|
||||
'All children of the form Schema array that need to be updated must contain the `field` field'
|
||||
);
|
||||
return;
|
||||
}
|
||||
const schema: FormSchema[] = [];
|
||||
updateData.forEach((item) => {
|
||||
unref(getSchema).forEach((val) => {
|
||||
if (val.field === item.field) {
|
||||
const newSchema = deepMerge(val, item);
|
||||
schema.push(newSchema as FormSchema);
|
||||
} else {
|
||||
schema.push(val);
|
||||
}
|
||||
});
|
||||
});
|
||||
schemaRef.value = uniqBy(schema, 'field');
|
||||
}
|
||||
|
||||
function getFieldsValue(): Recordable {
|
||||
const formEl = unref(formElRef);
|
||||
if (!formEl) return {};
|
||||
return handleFormValues(toRaw(unref(formModel)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Is it time
|
||||
*/
|
||||
function itemIsDateType(key: string) {
|
||||
return unref(getSchema).some((item) => {
|
||||
return item.field === key ? dateItemType.includes(item.component) : false;
|
||||
});
|
||||
}
|
||||
|
||||
async function validateFields(nameList?: NamePath[] | undefined) {
|
||||
return unref(formElRef)?.validateFields(nameList);
|
||||
}
|
||||
|
||||
async function validate(nameList?: NamePath[] | undefined) {
|
||||
return await unref(formElRef)?.validate(nameList);
|
||||
}
|
||||
|
||||
async function clearValidate(name?: string | string[]) {
|
||||
await unref(formElRef)?.clearValidate(name);
|
||||
}
|
||||
|
||||
async function scrollToField(name: NamePath, options?: ScrollOptions | undefined) {
|
||||
await unref(formElRef)?.scrollToField(name, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description: Form submission
|
||||
*/
|
||||
async function handleSubmit(e?: Event): Promise<void> {
|
||||
e && e.preventDefault();
|
||||
const { submitFunc } = unref(getProps);
|
||||
if (submitFunc && isFunction(submitFunc)) {
|
||||
await submitFunc();
|
||||
return;
|
||||
}
|
||||
const formEl = unref(formElRef);
|
||||
if (!formEl) return;
|
||||
try {
|
||||
const values = await validate();
|
||||
//update-begin---author:zhangdaihao Date:20140212 for:[bug号]树机构调整------------
|
||||
//--updateBy-begin----author:zyf---date:20211206------for:对查询表单提交的数组处理成字符串------
|
||||
for (let key in values) {
|
||||
if (values[key] instanceof Array) {
|
||||
let valueType = getValueType(getProps, key);
|
||||
if (valueType === 'string') {
|
||||
values[key] = values[key].join(',');
|
||||
}
|
||||
}
|
||||
}
|
||||
//--updateBy-end----author:zyf---date:20211206------for:对查询表单提交的数组处理成字符串------
|
||||
const res = handleFormValues(values);
|
||||
emit('submit', res);
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
handleSubmit,
|
||||
clearValidate,
|
||||
validate,
|
||||
validateFields,
|
||||
getFieldsValue,
|
||||
updateSchema,
|
||||
resetSchema,
|
||||
appendSchemaByField,
|
||||
removeSchemaByFiled,
|
||||
resetFields,
|
||||
setFieldsValue,
|
||||
scrollToField,
|
||||
};
|
||||
return {
|
||||
handleSubmit,
|
||||
clearValidate,
|
||||
validate,
|
||||
validateFields,
|
||||
getFieldsValue,
|
||||
updateSchema,
|
||||
resetSchema,
|
||||
appendSchemaByField,
|
||||
removeSchemaByFiled,
|
||||
resetFields,
|
||||
setFieldsValue,
|
||||
scrollToField,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,12 +12,7 @@ interface UseFormValuesContext {
|
|||
getProps: ComputedRef<FormProps>;
|
||||
formModel: Recordable;
|
||||
}
|
||||
export function useFormValues({
|
||||
defaultValueRef,
|
||||
getSchema,
|
||||
formModel,
|
||||
getProps,
|
||||
}: UseFormValuesContext) {
|
||||
export function useFormValues({ defaultValueRef, getSchema, formModel, getProps }: UseFormValuesContext) {
|
||||
// Processing form values
|
||||
function handleFormValues(values: Recordable) {
|
||||
if (!isObject(values)) {
|
||||
|
@ -43,10 +38,9 @@ export function useFormValues({
|
|||
}
|
||||
set(res, key, value);
|
||||
}
|
||||
return handleRangeValue(getProps,res);
|
||||
return handleRangeValue(getProps, res);
|
||||
}
|
||||
|
||||
|
||||
function initDefault() {
|
||||
const schemas = unref(getSchema);
|
||||
const obj: Recordable = {};
|
||||
|
|
|
@ -10,20 +10,16 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
|
|||
const { labelCol = {}, wrapperCol = {} } = schemaItem.itemProps || {};
|
||||
const { labelWidth, disabledLabelWidth } = schemaItem;
|
||||
|
||||
const {
|
||||
labelWidth: globalLabelWidth,
|
||||
labelCol: globalLabelCol,
|
||||
wrapperCol: globWrapperCol,
|
||||
} = unref(propsRef);
|
||||
const { labelWidth: globalLabelWidth, labelCol: globalLabelCol, wrapperCol: globWrapperCol } = unref(propsRef);
|
||||
|
||||
// update-begin--author:sunjianlei---date:20211104---for: 禁用全局 labelWidth,不自动设置 textAlign --------
|
||||
if (disabledLabelWidth) {
|
||||
return { labelCol, wrapperCol }
|
||||
return { labelCol, wrapperCol };
|
||||
}
|
||||
// update-begin--author:sunjianlei---date:20211104---for: 禁用全局 labelWidth,不自动设置 textAlign --------
|
||||
|
||||
// If labelWidth is set globally, all items setting
|
||||
if ((!globalLabelWidth && !labelWidth && !globalLabelCol)) {
|
||||
if (!globalLabelWidth && !labelWidth && !globalLabelCol) {
|
||||
labelCol.style = {
|
||||
textAlign: 'left',
|
||||
};
|
||||
|
|
|
@ -1,119 +1,114 @@
|
|||
<template>
|
||||
<div v-for="(param, index) in dynamicInput.params" :key="index" style="display: flex">
|
||||
<a-input placeholder="请输入参数key" v-model:value="param.label" style="width: 30%;margin-bottom: 5px" @input="emitChange"/>
|
||||
<a-input placeholder="请输入参数value" v-model:value="param.value" style="width: 30%;margin: 0 0 5px 5px" @input="emitChange"/>
|
||||
<MinusCircleOutlined
|
||||
v-if="dynamicInput.params.length > 1"
|
||||
class="dynamic-delete-button"
|
||||
@click="remove(param)"
|
||||
style="width: 50px"
|
||||
></MinusCircleOutlined>
|
||||
</div>
|
||||
<div>
|
||||
<a-button type="dashed" style="width: 60%" @click="add">
|
||||
<PlusOutlined/>
|
||||
新增
|
||||
</a-button>
|
||||
</div>
|
||||
<div v-for="(param, index) in dynamicInput.params" :key="index" style="display: flex">
|
||||
<a-input placeholder="请输入参数key" v-model:value="param.label" style="width: 30%; margin-bottom: 5px" @input="emitChange" />
|
||||
<a-input placeholder="请输入参数value" v-model:value="param.value" style="width: 30%; margin: 0 0 5px 5px" @input="emitChange" />
|
||||
<MinusCircleOutlined v-if="dynamicInput.params.length > 1" class="dynamic-delete-button" @click="remove(param)" style="width: 50px"></MinusCircleOutlined>
|
||||
</div>
|
||||
<div>
|
||||
<a-button type="dashed" style="width: 60%" @click="add">
|
||||
<PlusOutlined />
|
||||
新增
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {MinusCircleOutlined, PlusOutlined} from '@ant-design/icons-vue';
|
||||
import {defineComponent, reactive, ref, UnwrapRef, watchEffect} from 'vue';
|
||||
import {propTypes} from '/@/utils/propTypes';
|
||||
import { isEmpty } from '/@/utils/is'
|
||||
import { tryOnMounted, tryOnUnmounted } from '@vueuse/core';
|
||||
interface Params {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||||
import { defineComponent, reactive, ref, UnwrapRef, watchEffect } from 'vue';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { isEmpty } from '/@/utils/is';
|
||||
import { tryOnMounted, tryOnUnmounted } from '@vueuse/core';
|
||||
interface Params {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JAddInput',
|
||||
props: {
|
||||
value: propTypes.string.def('')
|
||||
},
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, {emit}) {
|
||||
//input动态数据
|
||||
const dynamicInput: UnwrapRef<{ params: Params[] }> = reactive({params: []});
|
||||
//删除Input
|
||||
const remove = (item: Params) => {
|
||||
let index = dynamicInput.params.indexOf(item);
|
||||
if (index !== -1) {
|
||||
dynamicInput.params.splice(index, 1);
|
||||
}
|
||||
emitChange()
|
||||
};
|
||||
//新增Input
|
||||
const add = () => {
|
||||
dynamicInput.params.push({
|
||||
label: '',
|
||||
value: '',
|
||||
});
|
||||
emitChange()
|
||||
};
|
||||
export default defineComponent({
|
||||
name: 'JAddInput',
|
||||
props: {
|
||||
value: propTypes.string.def(''),
|
||||
},
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, { emit }) {
|
||||
//input动态数据
|
||||
const dynamicInput: UnwrapRef<{ params: Params[] }> = reactive({ params: [] });
|
||||
//删除Input
|
||||
const remove = (item: Params) => {
|
||||
let index = dynamicInput.params.indexOf(item);
|
||||
if (index !== -1) {
|
||||
dynamicInput.params.splice(index, 1);
|
||||
}
|
||||
emitChange();
|
||||
};
|
||||
//新增Input
|
||||
const add = () => {
|
||||
dynamicInput.params.push({
|
||||
label: '',
|
||||
value: '',
|
||||
});
|
||||
emitChange();
|
||||
};
|
||||
|
||||
//监听传入数据value
|
||||
watchEffect(() => {
|
||||
initVal();
|
||||
});
|
||||
//监听传入数据value
|
||||
watchEffect(() => {
|
||||
initVal();
|
||||
});
|
||||
|
||||
/**
|
||||
* 初始化数值
|
||||
*/
|
||||
function initVal() {
|
||||
console.log("props.value",props.value)
|
||||
dynamicInput.params = [];
|
||||
if(props.value && props.value.indexOf("{")==0){
|
||||
let jsonObj = JSON.parse(props.value);
|
||||
Object.keys(jsonObj).forEach((key) => {
|
||||
dynamicInput.params.push({label: key, value: jsonObj[key]});
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 数值改变
|
||||
*/
|
||||
function emitChange() {
|
||||
let obj = {};
|
||||
if (dynamicInput.params.length > 0) {
|
||||
dynamicInput.params.forEach(item => {
|
||||
obj[item['label']] = item['value']
|
||||
})
|
||||
}
|
||||
emit("change", isEmpty(obj)?'': JSON.stringify(obj));
|
||||
emit("update:value",isEmpty(obj)?'': JSON.stringify(obj))
|
||||
}
|
||||
|
||||
return {
|
||||
dynamicInput,
|
||||
emitChange,
|
||||
remove,
|
||||
add,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
MinusCircleOutlined,
|
||||
PlusOutlined,
|
||||
},
|
||||
});
|
||||
/**
|
||||
* 初始化数值
|
||||
*/
|
||||
function initVal() {
|
||||
console.log('props.value', props.value);
|
||||
dynamicInput.params = [];
|
||||
if (props.value && props.value.indexOf('{') == 0) {
|
||||
let jsonObj = JSON.parse(props.value);
|
||||
Object.keys(jsonObj).forEach((key) => {
|
||||
dynamicInput.params.push({ label: key, value: jsonObj[key] });
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 数值改变
|
||||
*/
|
||||
function emitChange() {
|
||||
let obj = {};
|
||||
if (dynamicInput.params.length > 0) {
|
||||
dynamicInput.params.forEach((item) => {
|
||||
obj[item['label']] = item['value'];
|
||||
});
|
||||
}
|
||||
emit('change', isEmpty(obj) ? '' : JSON.stringify(obj));
|
||||
emit('update:value', isEmpty(obj) ? '' : JSON.stringify(obj));
|
||||
}
|
||||
|
||||
return {
|
||||
dynamicInput,
|
||||
emitChange,
|
||||
remove,
|
||||
add,
|
||||
};
|
||||
},
|
||||
components: {
|
||||
MinusCircleOutlined,
|
||||
PlusOutlined,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.dynamic-delete-button {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
font-size: 24px;
|
||||
color: #999;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.dynamic-delete-button {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
font-size: 24px;
|
||||
color: #999;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.dynamic-delete-button:hover {
|
||||
color: #777;
|
||||
}
|
||||
.dynamic-delete-button:hover {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.dynamic-delete-button[disabled] {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.dynamic-delete-button[disabled] {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,59 +1,56 @@
|
|||
<template>
|
||||
<Cascader v-bind="attrs" v-model:value="state" :options="getOptions" @change="handleChange"/>
|
||||
<Cascader v-bind="attrs" v-model:value="state" :options="getOptions" @change="handleChange" />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {defineComponent, PropType, ref,reactive, watchEffect, computed, unref, watch, onMounted} from 'vue';
|
||||
import {Cascader} from 'ant-design-vue';
|
||||
import {provinceAndCityData, regionData, provinceAndCityDataPlus, regionDataPlus} from "../../utils/areaDataUtil";
|
||||
import {useRuleFormItem} from "/@/hooks/component/useFormItem";
|
||||
import {propTypes} from "/@/utils/propTypes";
|
||||
import {useAttrs} from "/@/hooks/core/useAttrs";
|
||||
export default defineComponent({
|
||||
name: 'JAreaLinkage',
|
||||
components: {
|
||||
Cascader
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: propTypes.oneOfType([
|
||||
propTypes.object,
|
||||
propTypes.array
|
||||
]),
|
||||
//是否显示区县
|
||||
showArea:propTypes.bool.def(true),
|
||||
//是否是全部
|
||||
showAll:propTypes.bool.def(false)
|
||||
},
|
||||
emits: ['options-change', 'change'],
|
||||
setup(props, {emit,refs}) {
|
||||
const emitData = ref<any[]>([]);
|
||||
const attrs = useAttrs();
|
||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
const getOptions = computed(() => {
|
||||
if(props.showArea&&props.showAll){
|
||||
return regionDataPlus
|
||||
}
|
||||
if(props.showArea&&!props.showAll){
|
||||
return regionData
|
||||
}
|
||||
if(!props.showArea&&!props.showAll){
|
||||
return provinceAndCityData
|
||||
}
|
||||
if(!props.showArea&&props.showAll){
|
||||
return provinceAndCityDataPlus
|
||||
}
|
||||
});
|
||||
function handleChange(_, ...args) {
|
||||
emitData.value = args;
|
||||
console.info(emitData)
|
||||
}
|
||||
return {
|
||||
state,
|
||||
attrs,
|
||||
regionData,
|
||||
getOptions,
|
||||
handleChange
|
||||
};
|
||||
},
|
||||
});
|
||||
import { defineComponent, PropType, ref, reactive, watchEffect, computed, unref, watch, onMounted } from 'vue';
|
||||
import { Cascader } from 'ant-design-vue';
|
||||
import { provinceAndCityData, regionData, provinceAndCityDataPlus, regionDataPlus } from '../../utils/areaDataUtil';
|
||||
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
export default defineComponent({
|
||||
name: 'JAreaLinkage',
|
||||
components: {
|
||||
Cascader,
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: propTypes.oneOfType([propTypes.object, propTypes.array]),
|
||||
//是否显示区县
|
||||
showArea: propTypes.bool.def(true),
|
||||
//是否是全部
|
||||
showAll: propTypes.bool.def(false),
|
||||
},
|
||||
emits: ['options-change', 'change'],
|
||||
setup(props, { emit, refs }) {
|
||||
const emitData = ref<any[]>([]);
|
||||
const attrs = useAttrs();
|
||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
const getOptions = computed(() => {
|
||||
if (props.showArea && props.showAll) {
|
||||
return regionDataPlus;
|
||||
}
|
||||
if (props.showArea && !props.showAll) {
|
||||
return regionData;
|
||||
}
|
||||
if (!props.showArea && !props.showAll) {
|
||||
return provinceAndCityData;
|
||||
}
|
||||
if (!props.showArea && props.showAll) {
|
||||
return provinceAndCityDataPlus;
|
||||
}
|
||||
});
|
||||
function handleChange(_, ...args) {
|
||||
emitData.value = args;
|
||||
console.info(emitData);
|
||||
}
|
||||
return {
|
||||
state,
|
||||
attrs,
|
||||
regionData,
|
||||
getOptions,
|
||||
handleChange,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,153 +1,153 @@
|
|||
<template>
|
||||
<div class="area-select">
|
||||
<!--省份-->
|
||||
<a-select v-model:value="province" @change="proChange" allowClear>
|
||||
<template v-for="item in provinceOptions" :key="`${item.value}`">
|
||||
<a-select-option :value="item.value">{{ item.label }}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
<!--城市-->
|
||||
<a-select v-if="level>=2" v-model:value="city" @change="cityChange">
|
||||
<template v-for="item in cityOptions" :key="`${item.value}`">
|
||||
<a-select-option :value="item.value">{{ item.label }}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
<!--地区-->
|
||||
<a-select v-if="level>=3" v-model:value="area" @change="areaChange">
|
||||
<template v-for="item in areaOptions" :key="`${item.value}`">
|
||||
<a-select-option :value="item.value">{{ item.label }}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
</div>
|
||||
<div class="area-select">
|
||||
<!--省份-->
|
||||
<a-select v-model:value="province" @change="proChange" allowClear>
|
||||
<template v-for="item in provinceOptions" :key="`${item.value}`">
|
||||
<a-select-option :value="item.value">{{ item.label }}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
<!--城市-->
|
||||
<a-select v-if="level >= 2" v-model:value="city" @change="cityChange">
|
||||
<template v-for="item in cityOptions" :key="`${item.value}`">
|
||||
<a-select-option :value="item.value">{{ item.label }}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
<!--地区-->
|
||||
<a-select v-if="level >= 3" v-model:value="area" @change="areaChange">
|
||||
<template v-for="item in areaOptions" :key="`${item.value}`">
|
||||
<a-select-option :value="item.value">{{ item.label }}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {defineComponent, PropType, ref, reactive, watchEffect, computed, unref, watch, onMounted, onUnmounted, toRefs} from 'vue';
|
||||
import {propTypes} from "/@/utils/propTypes";
|
||||
import {useRuleFormItem} from '/@/hooks/component/useFormItem';
|
||||
import {provinceOptions, getDataByCode, getRealCode} from "../../utils/areaDataUtil";
|
||||
import { defineComponent, PropType, ref, reactive, watchEffect, computed, unref, watch, onMounted, onUnmounted, toRefs } from 'vue';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
||||
import { provinceOptions, getDataByCode, getRealCode } from '../../utils/areaDataUtil';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JAreaSelect',
|
||||
props: {
|
||||
value: [Array, String],
|
||||
province: [String],
|
||||
city: [String],
|
||||
area: [String],
|
||||
level: propTypes.number.def(3),
|
||||
},
|
||||
emits: ['change','update:value'],
|
||||
setup(props, {emit, refs}) {
|
||||
const emitData = ref<any[]>([]);
|
||||
//下拉框的选择值
|
||||
const pca = reactive({
|
||||
province: '',
|
||||
city: '',
|
||||
area: '',
|
||||
});
|
||||
//表单值
|
||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
//城市下拉框的选项
|
||||
const cityOptions = computed(() => {
|
||||
return pca.province ? getDataByCode(pca.province) : [];
|
||||
});
|
||||
//地区下拉框的选项
|
||||
const areaOptions = computed(() => {
|
||||
return pca.city ? getDataByCode(pca.city) : [];
|
||||
});
|
||||
/**
|
||||
* 监听props值
|
||||
*/
|
||||
watchEffect(() => {
|
||||
props && initValue();
|
||||
});
|
||||
export default defineComponent({
|
||||
name: 'JAreaSelect',
|
||||
props: {
|
||||
value: [Array, String],
|
||||
province: [String],
|
||||
city: [String],
|
||||
area: [String],
|
||||
level: propTypes.number.def(3),
|
||||
},
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, { emit, refs }) {
|
||||
const emitData = ref<any[]>([]);
|
||||
//下拉框的选择值
|
||||
const pca = reactive({
|
||||
province: '',
|
||||
city: '',
|
||||
area: '',
|
||||
});
|
||||
//表单值
|
||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
//城市下拉框的选项
|
||||
const cityOptions = computed(() => {
|
||||
return pca.province ? getDataByCode(pca.province) : [];
|
||||
});
|
||||
//地区下拉框的选项
|
||||
const areaOptions = computed(() => {
|
||||
return pca.city ? getDataByCode(pca.city) : [];
|
||||
});
|
||||
/**
|
||||
* 监听props值
|
||||
*/
|
||||
watchEffect(() => {
|
||||
props && initValue();
|
||||
});
|
||||
|
||||
/**
|
||||
* 监听组件值变化
|
||||
*/
|
||||
watch(pca, (newVal) => {
|
||||
if(!props.value){
|
||||
emit("update:province",pca.province);
|
||||
emit("update:city",pca.city);
|
||||
emit("update:area",pca.area);
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 数据初始化
|
||||
*/
|
||||
function initValue() {
|
||||
if (props.value) {
|
||||
//传参是数组的情况下的处理
|
||||
if (Array.isArray(props.value)) {
|
||||
pca.province = props.value[0];
|
||||
pca.city = props.value[1] ? props.value[1] : '';
|
||||
pca.area = props.value[2] ? props.value[2] : '';
|
||||
} else {
|
||||
//传参是数值
|
||||
let valueArr = getRealCode(props.value, props.level);
|
||||
if (valueArr) {
|
||||
pca.province = valueArr[0];
|
||||
pca.city = props.level >= 2 && valueArr[1] ? valueArr[1] : '';
|
||||
pca.area = props.level >= 3 && valueArr[2] ? valueArr[2] : '';
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//绑定三个数据的情况
|
||||
pca.province = props.province?props.province:'';
|
||||
pca.city = props.city?props.city:'';
|
||||
pca.area = props.area?props.area:'';
|
||||
}
|
||||
/**
|
||||
* 监听组件值变化
|
||||
*/
|
||||
watch(pca, (newVal) => {
|
||||
if (!props.value) {
|
||||
emit('update:province', pca.province);
|
||||
emit('update:city', pca.city);
|
||||
emit('update:area', pca.area);
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 数据初始化
|
||||
*/
|
||||
function initValue() {
|
||||
if (props.value) {
|
||||
//传参是数组的情况下的处理
|
||||
if (Array.isArray(props.value)) {
|
||||
pca.province = props.value[0];
|
||||
pca.city = props.value[1] ? props.value[1] : '';
|
||||
pca.area = props.value[2] ? props.value[2] : '';
|
||||
} else {
|
||||
//传参是数值
|
||||
let valueArr = getRealCode(props.value, props.level);
|
||||
if (valueArr) {
|
||||
pca.province = valueArr[0];
|
||||
pca.city = props.level >= 2 && valueArr[1] ? valueArr[1] : '';
|
||||
pca.area = props.level >= 3 && valueArr[2] ? valueArr[2] : '';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//绑定三个数据的情况
|
||||
pca.province = props.province ? props.province : '';
|
||||
pca.city = props.city ? props.city : '';
|
||||
pca.area = props.area ? props.area : '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 省份change事件
|
||||
*/
|
||||
function proChange(val) {
|
||||
pca.city = (val && getDataByCode(val)[0]?.value);
|
||||
pca.area = (pca.city && getDataByCode(pca.city)[0]?.value);
|
||||
state.value = props.level <= 1 ? val : (props.level <= 2 ? pca.city : pca.area);
|
||||
emit("update:value",unref(state));
|
||||
}
|
||||
/**
|
||||
* 省份change事件
|
||||
*/
|
||||
function proChange(val) {
|
||||
pca.city = val && getDataByCode(val)[0]?.value;
|
||||
pca.area = pca.city && getDataByCode(pca.city)[0]?.value;
|
||||
state.value = props.level <= 1 ? val : props.level <= 2 ? pca.city : pca.area;
|
||||
emit('update:value', unref(state));
|
||||
}
|
||||
|
||||
/**
|
||||
* 城市change事件
|
||||
*/
|
||||
function cityChange(val) {
|
||||
pca.area = (val && getDataByCode(val)[0]?.value);
|
||||
state.value = props.level <= 2 ? val : pca.area;
|
||||
emit("update:value",unref(state));
|
||||
}
|
||||
/**
|
||||
* 城市change事件
|
||||
*/
|
||||
function cityChange(val) {
|
||||
pca.area = val && getDataByCode(val)[0]?.value;
|
||||
state.value = props.level <= 2 ? val : pca.area;
|
||||
emit('update:value', unref(state));
|
||||
}
|
||||
|
||||
/**
|
||||
* 区域change事件
|
||||
*/
|
||||
function areaChange(val) {
|
||||
state.value = val;
|
||||
emit("update:value",unref(state));
|
||||
}
|
||||
/**
|
||||
* 区域change事件
|
||||
*/
|
||||
function areaChange(val) {
|
||||
state.value = val;
|
||||
emit('update:value', unref(state));
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(pca),
|
||||
provinceOptions,
|
||||
cityOptions,
|
||||
areaOptions,
|
||||
proChange,
|
||||
cityChange,
|
||||
areaChange
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
...toRefs(pca),
|
||||
provinceOptions,
|
||||
cityOptions,
|
||||
areaOptions,
|
||||
proChange,
|
||||
cityChange,
|
||||
areaChange,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.area-select {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
.area-select {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
.ant-select{
|
||||
width: 33.3%;
|
||||
}
|
||||
|
||||
.ant-select:not(:first-child) {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.ant-select {
|
||||
width: 33.3%;
|
||||
}
|
||||
|
||||
.ant-select:not(:first-child) {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
<!--下拉树-->
|
||||
<template>
|
||||
<a-tree-select
|
||||
allowClear
|
||||
labelInValue
|
||||
style="width: 100%"
|
||||
:disabled="disabled"
|
||||
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
:placeholder="placeholder"
|
||||
:loadData="asyncLoadTreeData"
|
||||
:value="treeValue"
|
||||
:treeData="treeData"
|
||||
:multiple="multiple"
|
||||
@change="onChange">
|
||||
</a-tree-select>
|
||||
<a-tree-select
|
||||
allowClear
|
||||
labelInValue
|
||||
style="width: 100%"
|
||||
:disabled="disabled"
|
||||
:dropdownStyle="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
:placeholder="placeholder"
|
||||
:loadData="asyncLoadTreeData"
|
||||
:value="treeValue"
|
||||
:treeData="treeData"
|
||||
:multiple="multiple"
|
||||
@change="onChange"
|
||||
>
|
||||
</a-tree-select>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, unref, watch } from 'vue';
|
||||
|
@ -28,10 +29,7 @@
|
|||
components: {},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: propTypes.oneOfType([
|
||||
propTypes.string,
|
||||
propTypes.array,
|
||||
]),
|
||||
value: propTypes.oneOfType([propTypes.string, propTypes.array]),
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择',
|
||||
|
@ -49,7 +47,7 @@
|
|||
},
|
||||
// 是否支持多选
|
||||
multiple: {
|
||||
type: [Boolean,String],
|
||||
type: [Boolean, String],
|
||||
default: false,
|
||||
},
|
||||
loadTriggleChange: {
|
||||
|
@ -86,14 +84,14 @@
|
|||
() => {
|
||||
loadItemByCode();
|
||||
},
|
||||
{ deep: true },
|
||||
{ deep: true }
|
||||
);
|
||||
watch(
|
||||
() => props.pcode,
|
||||
() => {
|
||||
loadRoot();
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
function loadRoot() {
|
||||
|
@ -103,7 +101,7 @@
|
|||
condition: props.condition,
|
||||
};
|
||||
console.info(param);
|
||||
loadTreeData(param).then(res => {
|
||||
loadTreeData(param).then((res) => {
|
||||
for (let i of res) {
|
||||
i.value = i.key;
|
||||
if (i.leaf == false) {
|
||||
|
@ -114,15 +112,13 @@
|
|||
}
|
||||
treeData.value = res;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
function loadItemByCode() {
|
||||
if (!props.value || props.value == '0') {
|
||||
treeValue.value = [];
|
||||
} else {
|
||||
loadDictItem({ ids: props.value }).then(res => {
|
||||
loadDictItem({ ids: props.value }).then((res) => {
|
||||
let values = props.value.split(',');
|
||||
treeValue.value = res.map((item, index) => ({
|
||||
key: values[index],
|
||||
|
@ -139,7 +135,6 @@
|
|||
if (!props.multiple && props.loadTriggleChange) {
|
||||
backValue(props.value, text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function backValue(value, label) {
|
||||
|
@ -163,7 +158,7 @@
|
|||
pid: pid,
|
||||
condition: props.condition,
|
||||
};
|
||||
loadTreeData(param).then(res => {
|
||||
loadTreeData(param).then((res) => {
|
||||
if (res) {
|
||||
for (let i of res) {
|
||||
i.value = i.key;
|
||||
|
@ -204,7 +199,7 @@
|
|||
treeValue.value = '';
|
||||
} else if (Array.isArray(value)) {
|
||||
let labels = [];
|
||||
let values = value.map(item => {
|
||||
let values = value.map((item) => {
|
||||
labels.push(item.label);
|
||||
return item.value;
|
||||
});
|
||||
|
@ -251,6 +246,5 @@
|
|||
asyncLoadTreeData,
|
||||
};
|
||||
},
|
||||
})
|
||||
;
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,83 +1,83 @@
|
|||
<template>
|
||||
<a-checkbox-group v-bind="attrs" v-model:value="checkboxArray" :options="checkOptions" @change="handleChange"></a-checkbox-group>
|
||||
<a-checkbox-group v-bind="attrs" v-model:value="checkboxArray" :options="checkOptions" @change="handleChange"></a-checkbox-group>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent, computed, watch, watchEffect, ref, unref} from 'vue';
|
||||
import {propTypes} from "/@/utils/propTypes";
|
||||
import {useAttrs} from '/@/hooks/core/useAttrs';
|
||||
import {initDictOptions} from "/@/utils/dict/index"
|
||||
import { defineComponent, computed, watch, watchEffect, ref, unref } from 'vue';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { initDictOptions } from '/@/utils/dict/index';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JCheckbox',
|
||||
props: {
|
||||
value: propTypes.string,
|
||||
dictCode: propTypes.string,
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, {emit}) {
|
||||
const attrs = useAttrs();
|
||||
//checkbox选项
|
||||
const checkOptions = ref<any[]>([]);
|
||||
//checkbox数值
|
||||
const checkboxArray = ref<any[]>([]);
|
||||
/**
|
||||
* 监听value
|
||||
*/
|
||||
watchEffect(() => {
|
||||
props.value && (checkboxArray.value = props.value ? props.value.split(",") : []);
|
||||
//update-begin-author:taoyan date:20220401 for: 调用表单的 resetFields不会清空当前信息,界面显示上一次的数据
|
||||
if(props.value === '' || props.value === undefined){
|
||||
checkboxArray.value = []
|
||||
}
|
||||
//update-end-author:taoyan date:20220401 for: 调用表单的 resetFields不会清空当前信息,界面显示上一次的数据
|
||||
});
|
||||
/**
|
||||
* 监听字典code
|
||||
*/
|
||||
watchEffect(() => {
|
||||
props && initOptions();
|
||||
});
|
||||
export default defineComponent({
|
||||
name: 'JCheckbox',
|
||||
props: {
|
||||
value: propTypes.string,
|
||||
dictCode: propTypes.string,
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, { emit }) {
|
||||
const attrs = useAttrs();
|
||||
//checkbox选项
|
||||
const checkOptions = ref<any[]>([]);
|
||||
//checkbox数值
|
||||
const checkboxArray = ref<any[]>([]);
|
||||
/**
|
||||
* 监听value
|
||||
*/
|
||||
watchEffect(() => {
|
||||
props.value && (checkboxArray.value = props.value ? props.value.split(',') : []);
|
||||
//update-begin-author:taoyan date:20220401 for: 调用表单的 resetFields不会清空当前信息,界面显示上一次的数据
|
||||
if (props.value === '' || props.value === undefined) {
|
||||
checkboxArray.value = [];
|
||||
}
|
||||
//update-end-author:taoyan date:20220401 for: 调用表单的 resetFields不会清空当前信息,界面显示上一次的数据
|
||||
});
|
||||
/**
|
||||
* 监听字典code
|
||||
*/
|
||||
watchEffect(() => {
|
||||
props && initOptions();
|
||||
});
|
||||
|
||||
/**
|
||||
* 初始化选项
|
||||
*/
|
||||
async function initOptions() {
|
||||
//根据options, 初始化选项
|
||||
if (props.options && props.options.length > 0) {
|
||||
checkOptions.value = props.options;
|
||||
return;
|
||||
}
|
||||
//根据字典Code, 初始化选项
|
||||
if(props.dictCode){
|
||||
const dictData = await initDictOptions(props.dictCode);
|
||||
checkOptions.value = dictData.reduce((prev, next) => {
|
||||
if (next) {
|
||||
const value = next['value'];
|
||||
prev.push({
|
||||
label: next['text'],
|
||||
value: value,
|
||||
});
|
||||
}
|
||||
return prev;
|
||||
}, []);
|
||||
}
|
||||
/**
|
||||
* 初始化选项
|
||||
*/
|
||||
async function initOptions() {
|
||||
//根据options, 初始化选项
|
||||
if (props.options && props.options.length > 0) {
|
||||
checkOptions.value = props.options;
|
||||
return;
|
||||
}
|
||||
//根据字典Code, 初始化选项
|
||||
if (props.dictCode) {
|
||||
const dictData = await initDictOptions(props.dictCode);
|
||||
checkOptions.value = dictData.reduce((prev, next) => {
|
||||
if (next) {
|
||||
const value = next['value'];
|
||||
prev.push({
|
||||
label: next['text'],
|
||||
value: value,
|
||||
});
|
||||
}
|
||||
return prev;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* change事件
|
||||
* @param $event
|
||||
*/
|
||||
function handleChange($event) {
|
||||
emit('update:value', $event.join(','));
|
||||
emit('change', $event.join(','));
|
||||
}
|
||||
/**
|
||||
* change事件
|
||||
* @param $event
|
||||
*/
|
||||
function handleChange($event) {
|
||||
emit('update:value', $event.join(','));
|
||||
emit('change', $event.join(','));
|
||||
}
|
||||
|
||||
return {checkboxArray, checkOptions, attrs, handleChange};
|
||||
},
|
||||
});
|
||||
return { checkboxArray, checkOptions, attrs, handleChange };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<template>
|
||||
<div v-bind="boxBindProps">
|
||||
<!-- 全屏按钮 -->
|
||||
<a-icon v-if="fullScreen" class="full-screen-icon" :type="fullScreenIcon" @click="onToggleFullScreen"/>
|
||||
<textarea ref="textarea" v-bind="getBindValue"></textarea>
|
||||
</div>
|
||||
<div v-bind="boxBindProps">
|
||||
<!-- 全屏按钮 -->
|
||||
<a-icon v-if="fullScreen" class="full-screen-icon" :type="fullScreenIcon" @click="onToggleFullScreen" />
|
||||
<textarea ref="textarea" v-bind="getBindValue"></textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent, onMounted, reactive, ref, watch, unref, computed} from 'vue';
|
||||
import { defineComponent, onMounted, reactive, ref, watch, unref, computed } from 'vue';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
||||
// 引入全局实例
|
||||
import _CodeMirror, { EditorFromTextArea } from 'codemirror'
|
||||
import _CodeMirror, { EditorFromTextArea } from 'codemirror';
|
||||
// 核心样式
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
// 引入主题后还需要在 options 中指定主题才会生效
|
||||
|
@ -29,22 +29,22 @@
|
|||
import 'codemirror/mode/swift/swift.js';
|
||||
import 'codemirror/mode/vue/vue.js';
|
||||
// 折叠资源引入:开始
|
||||
import "codemirror/addon/fold/foldgutter.css";
|
||||
import "codemirror/addon/fold/foldcode.js";
|
||||
import "codemirror/addon/fold/brace-fold.js";
|
||||
import "codemirror/addon/fold/comment-fold.js";
|
||||
import "codemirror/addon/fold/indent-fold.js";
|
||||
import "codemirror/addon/fold/foldgutter.js";
|
||||
import 'codemirror/addon/fold/foldgutter.css';
|
||||
import 'codemirror/addon/fold/foldcode.js';
|
||||
import 'codemirror/addon/fold/brace-fold.js';
|
||||
import 'codemirror/addon/fold/comment-fold.js';
|
||||
import 'codemirror/addon/fold/indent-fold.js';
|
||||
import 'codemirror/addon/fold/foldgutter.js';
|
||||
// 折叠资源引入:结束
|
||||
//光标行背景高亮,配置里面也需要styleActiveLine设置为true
|
||||
import "codemirror/addon/selection/active-line.js";
|
||||
import 'codemirror/addon/selection/active-line.js';
|
||||
// 支持代码自动补全
|
||||
import "codemirror/addon/hint/show-hint.css";
|
||||
import "codemirror/addon/hint/show-hint.js";
|
||||
import "codemirror/addon/hint/anyword-hint.js";
|
||||
import 'codemirror/addon/hint/show-hint.css';
|
||||
import 'codemirror/addon/hint/show-hint.js';
|
||||
import 'codemirror/addon/hint/anyword-hint.js';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import {useDesign} from '/@/hooks/web/useDesign'
|
||||
import {isJsonObjectString} from '/@/utils/is.ts'
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { isJsonObjectString } from '/@/utils/is.ts';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JCodeEditor',
|
||||
|
@ -53,7 +53,7 @@
|
|||
components: {},
|
||||
props: {
|
||||
value: propTypes.string.def(''),
|
||||
height:propTypes.string.def('auto'),
|
||||
height: propTypes.string.def('auto'),
|
||||
disabled: propTypes.bool.def(false),
|
||||
// 是否显示全屏按钮
|
||||
fullScreen: propTypes.bool.def(false),
|
||||
|
@ -68,62 +68,67 @@
|
|||
//表单值
|
||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
const textarea = ref<HTMLTextAreaElement>();
|
||||
let coder: Nullable<EditorFromTextArea> = null
|
||||
let coder: Nullable<EditorFromTextArea> = null;
|
||||
const attrs = useAttrs();
|
||||
const height =ref(props.height);
|
||||
const height = ref(props.height);
|
||||
const options = reactive({
|
||||
// 缩进格式
|
||||
tabSize: 2,
|
||||
// 主题,对应主题库 JS 需要提前引入
|
||||
theme: 'cobalt',
|
||||
smartIndent: true, // 是否智能缩进
|
||||
smartIndent: true, // 是否智能缩进
|
||||
// 显示行号
|
||||
lineNumbers: true,
|
||||
line: true,
|
||||
// 启用代码折叠相关功能:开始
|
||||
foldGutter: true,
|
||||
lineWrapping: true,
|
||||
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'],
|
||||
// 启用代码折叠相关功能:结束
|
||||
// 光标行高亮
|
||||
// 光标行高亮
|
||||
styleActiveLine: true,
|
||||
//代码格式化
|
||||
extraKeys:{
|
||||
Tab: function autoFormat(editor) {
|
||||
//var totalLines = editor.lineCount();
|
||||
//editor.autoFormatRange({line:0, ch:0}, {line:totalLines});
|
||||
setValue(innerValue,false)
|
||||
}
|
||||
}
|
||||
//代码格式化
|
||||
extraKeys: {
|
||||
Tab: function autoFormat(editor) {
|
||||
//var totalLines = editor.lineCount();
|
||||
//editor.autoFormatRange({line:0, ch:0}, {line:totalLines});
|
||||
setValue(innerValue, false);
|
||||
},
|
||||
},
|
||||
});
|
||||
let innerValue = ''
|
||||
let innerValue = '';
|
||||
// 全屏状态
|
||||
const isFullScreen = ref(false)
|
||||
const fullScreenIcon = computed(() => isFullScreen.value ? 'fullscreen-exit' : 'fullscreen')
|
||||
const isFullScreen = ref(false);
|
||||
const fullScreenIcon = computed(() => (isFullScreen.value ? 'fullscreen-exit' : 'fullscreen'));
|
||||
// 外部盒子参数
|
||||
const boxBindProps = computed(() => {
|
||||
let _props = {
|
||||
class: [
|
||||
prefixCls, 'full-screen-parent', 'auto-height',
|
||||
prefixCls,
|
||||
'full-screen-parent',
|
||||
'auto-height',
|
||||
{
|
||||
'full-screen': isFullScreen.value,
|
||||
},
|
||||
],
|
||||
style: {},
|
||||
}
|
||||
};
|
||||
if (isFullScreen.value) {
|
||||
_props.style['z-index'] = props.zIndex
|
||||
_props.style['z-index'] = props.zIndex;
|
||||
}
|
||||
return _props
|
||||
})
|
||||
return _props;
|
||||
});
|
||||
/**
|
||||
* 监听组件值
|
||||
*/
|
||||
watch(() => props.value, () => {
|
||||
if (innerValue != props.value) {
|
||||
setValue(props.value, false);
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
if (innerValue != props.value) {
|
||||
setValue(props.value, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
onMounted(() => {
|
||||
initialize();
|
||||
});
|
||||
|
@ -134,12 +139,12 @@
|
|||
* @param trigger 是否触发 change 事件
|
||||
*/
|
||||
function setValue(value: string, trigger = true) {
|
||||
if(value && isJsonObjectString(value)){
|
||||
value = JSON.stringify(JSON.parse(value),null,2);
|
||||
if (value && isJsonObjectString(value)) {
|
||||
value = JSON.stringify(JSON.parse(value), null, 2);
|
||||
}
|
||||
coder?.setValue(value ?? '')
|
||||
innerValue = value
|
||||
trigger && emitChange(innerValue)
|
||||
coder?.setValue(value ?? '');
|
||||
innerValue = value;
|
||||
trigger && emitChange(innerValue);
|
||||
}
|
||||
|
||||
//编辑器值修改事件
|
||||
|
@ -147,7 +152,7 @@
|
|||
let value = obj.getValue();
|
||||
innerValue = value || '';
|
||||
if (props.value != innerValue) {
|
||||
emitChange(innerValue)
|
||||
emitChange(innerValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,12 +167,12 @@
|
|||
//绑定值修改事件
|
||||
coder.on('change', onChange);
|
||||
// 初始化成功时赋值一次
|
||||
setValue(innerValue, false)
|
||||
setValue(innerValue, false);
|
||||
}
|
||||
|
||||
// 切换全屏状态
|
||||
function onToggleFullScreen() {
|
||||
isFullScreen.value = !isFullScreen.value
|
||||
isFullScreen.value = !isFullScreen.value;
|
||||
}
|
||||
|
||||
const getBindValue = Object.assign({}, unref(props), unref(attrs));
|
||||
|
@ -186,74 +191,72 @@
|
|||
</script>
|
||||
|
||||
<style lang="less">
|
||||
//noinspection LessUnresolvedVariable
|
||||
@prefix-cls: ~'@{namespace}-code-editer';
|
||||
.@{prefix-cls} {
|
||||
|
||||
&.auto-height {
|
||||
.CodeMirror {
|
||||
height: v-bind(height) !important;
|
||||
min-height: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 全屏样式 */
|
||||
|
||||
&.full-screen-parent {
|
||||
position: relative;
|
||||
|
||||
.full-screen-icon {
|
||||
opacity: 0;
|
||||
color: black;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 24px;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
z-index: 9;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
padding: 2px 0 0 1.5px;
|
||||
//noinspection LessUnresolvedVariable
|
||||
@prefix-cls: ~'@{namespace}-code-editer';
|
||||
.@{prefix-cls} {
|
||||
&.auto-height {
|
||||
.CodeMirror {
|
||||
height: v-bind(height) !important;
|
||||
min-height: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
/* 全屏样式 */
|
||||
|
||||
&.full-screen-parent {
|
||||
position: relative;
|
||||
|
||||
.full-screen-icon {
|
||||
opacity: 1;
|
||||
opacity: 0;
|
||||
color: black;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 24px;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
z-index: 9;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
padding: 2px 0 0 1.5px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.88);
|
||||
&:hover {
|
||||
.full-screen-icon {
|
||||
opacity: 1;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.88);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.full-screen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 8px;
|
||||
background-color: #f5f5f5;
|
||||
&.full-screen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 8px;
|
||||
background-color: #f5f5f5;
|
||||
|
||||
.full-screen-icon {
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
.full-screen-icon {
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.full-screen-child,
|
||||
.CodeMirror {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.full-screen-child,
|
||||
.CodeMirror {
|
||||
.full-screen-child {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.full-screen-child {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,164 +1,161 @@
|
|||
<template>
|
||||
<a-radio-group v-if="compType===CompTypeEnum.Radio" v-bind="attrs" v-model:value="state" @change="handleChange">
|
||||
<template v-for="item in dictOptions" :key="`${item.value}`">
|
||||
<a-radio :value="item.value">
|
||||
{{ item.label }}
|
||||
</a-radio>
|
||||
</template>
|
||||
</a-radio-group>
|
||||
<a-radio-group v-if="compType === CompTypeEnum.Radio" v-bind="attrs" v-model:value="state" @change="handleChange">
|
||||
<template v-for="item in dictOptions" :key="`${item.value}`">
|
||||
<a-radio :value="item.value">
|
||||
{{ item.label }}
|
||||
</a-radio>
|
||||
</template>
|
||||
</a-radio-group>
|
||||
|
||||
<a-radio-group v-else-if="compType===CompTypeEnum.RadioButton" v-bind="attrs" v-model:value="state" buttonStyle="solid" @change="handleChange">
|
||||
<template v-for="item in dictOptions" :key="`${item.value}`">
|
||||
<a-radio-button :value="item.value">
|
||||
{{ item.label }}
|
||||
</a-radio-button>
|
||||
</template>
|
||||
</a-radio-group>
|
||||
<a-radio-group v-else-if="compType === CompTypeEnum.RadioButton" v-bind="attrs" v-model:value="state" buttonStyle="solid" @change="handleChange">
|
||||
<template v-for="item in dictOptions" :key="`${item.value}`">
|
||||
<a-radio-button :value="item.value">
|
||||
{{ item.label }}
|
||||
</a-radio-button>
|
||||
</template>
|
||||
</a-radio-group>
|
||||
|
||||
<template v-else-if="compType===CompTypeEnum.Select">
|
||||
<template v-else-if="compType === CompTypeEnum.Select">
|
||||
<!-- 显示加载效果 -->
|
||||
<a-input v-if="loadingEcho" readOnly placeholder="加载中…">
|
||||
<template #prefix>
|
||||
<LoadingOutlined/>
|
||||
<LoadingOutlined />
|
||||
</template>
|
||||
</a-input>
|
||||
<a-select v-else :placeholder="placeholder" v-bind="attrs" v-model:value="state" :filterOption="handleFilterOption" :getPopupContainer="getPopupContainer" @change="handleChange">
|
||||
<a-select-option v-if="showChooseOption" :value="undefined">请选择</a-select-option>
|
||||
<template v-for="item in dictOptions" :key="`${item.value}`">
|
||||
<a-select-option :value="item.value">
|
||||
<span style="display: inline-block;width: 100%" :title=" item.label ">
|
||||
<a-select-option v-if="showChooseOption" :value="undefined">请选择</a-select-option>
|
||||
<template v-for="item in dictOptions" :key="`${item.value}`">
|
||||
<a-select-option :value="item.value">
|
||||
<span style="display: inline-block; width: 100%" :title="item.label">
|
||||
{{ item.label }}
|
||||
</span>
|
||||
</a-select-option>
|
||||
</template>
|
||||
</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
</template>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import {defineComponent, PropType, ref, reactive, watchEffect, computed, unref, watch, onMounted} from 'vue';
|
||||
import {propTypes} from "/@/utils/propTypes";
|
||||
import {useAttrs} from "/@/hooks/core/useAttrs";
|
||||
import {initDictOptions} from "/@/utils/dict/index"
|
||||
import {get, omit} from 'lodash-es';
|
||||
import {useRuleFormItem} from '/@/hooks/component/useFormItem';
|
||||
import {CompTypeEnum} from '/@/enums/CompTypeEnum.ts';
|
||||
import {LoadingOutlined} from '@ant-design/icons-vue'
|
||||
import { defineComponent, PropType, ref, reactive, watchEffect, computed, unref, watch, onMounted } from 'vue';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { initDictOptions } from '/@/utils/dict/index';
|
||||
import { get, omit } from 'lodash-es';
|
||||
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
||||
import { CompTypeEnum } from '/@/enums/CompTypeEnum.ts';
|
||||
import { LoadingOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JDictSelectTag',
|
||||
inheritAttrs: false,
|
||||
components: {LoadingOutlined},
|
||||
props: {
|
||||
value: propTypes.oneOfType([
|
||||
propTypes.string,
|
||||
propTypes.number,
|
||||
propTypes.array,
|
||||
]),
|
||||
dictCode: propTypes.string,
|
||||
type: propTypes.string,
|
||||
placeholder: propTypes.string,
|
||||
stringToNumber: propTypes.bool,
|
||||
getPopupContainer: {
|
||||
type: Function,
|
||||
default: (node) => node.parentNode
|
||||
},
|
||||
// 是否显示【请选择】选项
|
||||
showChooseOption: propTypes.bool.def(true),
|
||||
// 下拉项-online使用
|
||||
options: {
|
||||
type: Array,
|
||||
default: [],
|
||||
required: false
|
||||
},
|
||||
},
|
||||
emits: ['options-change', 'change'],
|
||||
setup(props, {emit, refs}) {
|
||||
const emitData = ref<any[]>([]);
|
||||
const dictOptions = ref<any[]>([]);
|
||||
const attrs = useAttrs();
|
||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
const getBindValue = Object.assign({}, unref(props), unref(attrs));
|
||||
// 是否正在加载回显数据
|
||||
const loadingEcho = ref<boolean>(false)
|
||||
// 是否是首次加载回显,只有首次加载,才会显示 loading
|
||||
let isFirstLoadEcho = true
|
||||
export default defineComponent({
|
||||
name: 'JDictSelectTag',
|
||||
inheritAttrs: false,
|
||||
components: { LoadingOutlined },
|
||||
props: {
|
||||
value: propTypes.oneOfType([propTypes.string, propTypes.number, propTypes.array]),
|
||||
dictCode: propTypes.string,
|
||||
type: propTypes.string,
|
||||
placeholder: propTypes.string,
|
||||
stringToNumber: propTypes.bool,
|
||||
getPopupContainer: {
|
||||
type: Function,
|
||||
default: (node) => node.parentNode,
|
||||
},
|
||||
// 是否显示【请选择】选项
|
||||
showChooseOption: propTypes.bool.def(true),
|
||||
// 下拉项-online使用
|
||||
options: {
|
||||
type: Array,
|
||||
default: [],
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
emits: ['options-change', 'change'],
|
||||
setup(props, { emit, refs }) {
|
||||
const emitData = ref<any[]>([]);
|
||||
const dictOptions = ref<any[]>([]);
|
||||
const attrs = useAttrs();
|
||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
|
||||
const getBindValue = Object.assign({}, unref(props), unref(attrs));
|
||||
// 是否正在加载回显数据
|
||||
const loadingEcho = ref<boolean>(false);
|
||||
// 是否是首次加载回显,只有首次加载,才会显示 loading
|
||||
let isFirstLoadEcho = true;
|
||||
|
||||
//组件类型
|
||||
const compType = computed(() => {
|
||||
return (!props.type || props.type === "list") ? 'select' : props.type;
|
||||
});
|
||||
/**
|
||||
* 监听字典code
|
||||
*/
|
||||
watchEffect(() => {
|
||||
if (props.dictCode) {
|
||||
loadingEcho.value = isFirstLoadEcho
|
||||
isFirstLoadEcho = false
|
||||
initDictData().finally(() => {
|
||||
loadingEcho.value = isFirstLoadEcho
|
||||
})
|
||||
}
|
||||
//update-begin-author:taoyan date: 如果没有提供dictCode 可以走options的配置--
|
||||
if(!props.dictCode){
|
||||
dictOptions.value = props.options
|
||||
}
|
||||
//update-end-author:taoyan date: 如果没有提供dictCode 可以走options的配置--
|
||||
|
||||
});
|
||||
|
||||
//update-begin-author:taoyan date:20220404 for: 使用useRuleFormItem定义的value,会有一个问题,如果不是操作设置的值而是代码设置的控件值而不能触发change事件
|
||||
// 此处添加空值的change事件,即当组件调用地代码设置value为''也能触发change事件
|
||||
watch(()=>props.value, ()=>{
|
||||
if(props.value===''){
|
||||
emit('change', '')
|
||||
}
|
||||
});
|
||||
//update-end-author:taoyan date:20220404 for: 使用useRuleFormItem定义的value,会有一个问题,如果不是操作设置的值而是代码设置的控件值而不能触发change事件
|
||||
|
||||
//组件类型
|
||||
const compType = computed(() => {
|
||||
return !props.type || props.type === 'list' ? 'select' : props.type;
|
||||
});
|
||||
/**
|
||||
* 监听字典code
|
||||
*/
|
||||
watchEffect(() => {
|
||||
if (props.dictCode) {
|
||||
loadingEcho.value = isFirstLoadEcho;
|
||||
isFirstLoadEcho = false;
|
||||
initDictData().finally(() => {
|
||||
loadingEcho.value = isFirstLoadEcho;
|
||||
});
|
||||
}
|
||||
//update-begin-author:taoyan date: 如果没有提供dictCode 可以走options的配置--
|
||||
if (!props.dictCode) {
|
||||
dictOptions.value = props.options;
|
||||
}
|
||||
//update-end-author:taoyan date: 如果没有提供dictCode 可以走options的配置--
|
||||
});
|
||||
|
||||
async function initDictData() {
|
||||
let {dictCode, stringToNumber} = props;
|
||||
//根据字典Code, 初始化字典数组
|
||||
const dictData = await initDictOptions(dictCode);
|
||||
dictOptions.value = dictData.reduce((prev, next) => {
|
||||
if (next) {
|
||||
const value = next['value'];
|
||||
prev.push({
|
||||
label: next['text'] || next['label'],
|
||||
value: stringToNumber ? +value : value,
|
||||
...omit(next, ['text', 'value']),
|
||||
});
|
||||
}
|
||||
return prev;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function handleChange(e) {
|
||||
emitData.value = [e?.target?.value || e];
|
||||
//update-begin-author:taoyan date:20220404 for: 使用useRuleFormItem定义的value,会有一个问题,如果不是操作设置的值而是代码设置的控件值而不能触发change事件
|
||||
// 此处添加空值的change事件,即当组件调用地代码设置value为''也能触发change事件
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
if (props.value === '') {
|
||||
emit('change', '');
|
||||
}
|
||||
}
|
||||
);
|
||||
//update-end-author:taoyan date:20220404 for: 使用useRuleFormItem定义的value,会有一个问题,如果不是操作设置的值而是代码设置的控件值而不能触发change事件
|
||||
|
||||
/** 用于搜索下拉框中的内容 */
|
||||
function handleFilterOption(input, option) {
|
||||
// 在 label 中搜索
|
||||
let labelIf = option?.children[0]?.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
if (labelIf) {
|
||||
return true
|
||||
}
|
||||
// 在 value 中搜索
|
||||
return (option.value || '').toString().toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
async function initDictData() {
|
||||
let { dictCode, stringToNumber } = props;
|
||||
//根据字典Code, 初始化字典数组
|
||||
const dictData = await initDictOptions(dictCode);
|
||||
dictOptions.value = dictData.reduce((prev, next) => {
|
||||
if (next) {
|
||||
const value = next['value'];
|
||||
prev.push({
|
||||
label: next['text'] || next['label'],
|
||||
value: stringToNumber ? +value : value,
|
||||
...omit(next, ['text', 'value']),
|
||||
});
|
||||
}
|
||||
return prev;
|
||||
}, []);
|
||||
}
|
||||
|
||||
return {
|
||||
state,
|
||||
compType,
|
||||
attrs,
|
||||
loadingEcho,
|
||||
getBindValue,
|
||||
dictOptions,
|
||||
CompTypeEnum,
|
||||
handleChange,
|
||||
handleFilterOption,
|
||||
};
|
||||
},
|
||||
});
|
||||
function handleChange(e) {
|
||||
emitData.value = [e?.target?.value || e];
|
||||
}
|
||||
|
||||
/** 用于搜索下拉框中的内容 */
|
||||
function handleFilterOption(input, option) {
|
||||
// 在 label 中搜索
|
||||
let labelIf = option?.children[0]?.children.toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
if (labelIf) {
|
||||
return true;
|
||||
}
|
||||
// 在 value 中搜索
|
||||
return (option.value || '').toString().toLowerCase().indexOf(input.toLowerCase()) >= 0;
|
||||
}
|
||||
|
||||
return {
|
||||
state,
|
||||
compType,
|
||||
attrs,
|
||||
loadingEcho,
|
||||
getBindValue,
|
||||
dictOptions,
|
||||
CompTypeEnum,
|
||||
handleChange,
|
||||
handleFilterOption,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -3,78 +3,78 @@
|
|||
<div class="content">
|
||||
<a-tabs :size="`small`" v-model:activeKey="activeKey">
|
||||
<a-tab-pane tab="秒" key="second" v-if="!hideSecond">
|
||||
<SecondUI v-model:value="second" :disabled="disabled"/>
|
||||
<SecondUI v-model:value="second" :disabled="disabled" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="分" key="minute">
|
||||
<MinuteUI v-model:value="minute" :disabled="disabled"/>
|
||||
<MinuteUI v-model:value="minute" :disabled="disabled" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="时" key="hour">
|
||||
<HourUI v-model:value="hour" :disabled="disabled"/>
|
||||
<HourUI v-model:value="hour" :disabled="disabled" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="日" key="day">
|
||||
<DayUI v-model:value="day" :week="week" :disabled="disabled"/>
|
||||
<DayUI v-model:value="day" :week="week" :disabled="disabled" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="月" key="month">
|
||||
<MonthUI v-model:value="month" :disabled="disabled"/>
|
||||
<MonthUI v-model:value="month" :disabled="disabled" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="周" key="week">
|
||||
<WeekUI v-model:value="week" :day="day" :disabled="disabled"/>
|
||||
<WeekUI v-model:value="week" :day="day" :disabled="disabled" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="年" key="year" v-if="!hideYear && !hideSecond">
|
||||
<YearUI v-model:value="year" :disabled="disabled"/>
|
||||
<YearUI v-model:value="year" :disabled="disabled" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<a-divider/>
|
||||
<a-divider />
|
||||
<!-- 执行时间预览 -->
|
||||
<a-row :gutter="8">
|
||||
<a-col :span="18" style="margin-top: 22px;">
|
||||
<a-col :span="18" style="margin-top: 22px">
|
||||
<a-row :gutter="8">
|
||||
<a-col :span="8" style="margin-bottom: 12px;">
|
||||
<a-col :span="8" style="margin-bottom: 12px">
|
||||
<a-input v-model:value="inputValues.second" @blur="onInputBlur">
|
||||
<template #addonBefore>
|
||||
<span class="allow-click" @click="activeKey='second'">秒</span>
|
||||
<span class="allow-click" @click="activeKey = 'second'">秒</span>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 12px;">
|
||||
<a-col :span="8" style="margin-bottom: 12px">
|
||||
<a-input v-model:value="inputValues.minute" @blur="onInputBlur">
|
||||
<template #addonBefore>
|
||||
<span class="allow-click" @click="activeKey='minute'">分</span>
|
||||
<span class="allow-click" @click="activeKey = 'minute'">分</span>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 12px;">
|
||||
<a-col :span="8" style="margin-bottom: 12px">
|
||||
<a-input v-model:value="inputValues.hour" @blur="onInputBlur">
|
||||
<template #addonBefore>
|
||||
<span class="allow-click" @click="activeKey='hour'">时</span>
|
||||
<span class="allow-click" @click="activeKey = 'hour'">时</span>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 12px;">
|
||||
<a-col :span="8" style="margin-bottom: 12px">
|
||||
<a-input v-model:value="inputValues.day" @blur="onInputBlur">
|
||||
<template #addonBefore>
|
||||
<span class="allow-click" @click="activeKey='day'">日</span>
|
||||
<span class="allow-click" @click="activeKey = 'day'">日</span>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 12px;">
|
||||
<a-col :span="8" style="margin-bottom: 12px">
|
||||
<a-input v-model:value="inputValues.month" @blur="onInputBlur">
|
||||
<template #addonBefore>
|
||||
<span class="allow-click" @click="activeKey='month'">月</span>
|
||||
<span class="allow-click" @click="activeKey = 'month'">月</span>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 12px;">
|
||||
<a-col :span="8" style="margin-bottom: 12px">
|
||||
<a-input v-model:value="inputValues.week" @blur="onInputBlur">
|
||||
<template #addonBefore>
|
||||
<span class="allow-click" @click="activeKey='week'">周</span>
|
||||
<span class="allow-click" @click="activeKey = 'week'">周</span>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
<a-input v-model:value="inputValues.year" @blur="onInputBlur">
|
||||
<template #addonBefore>
|
||||
<span class="allow-click" @click="activeKey='year'">年</span>
|
||||
<span class="allow-click" @click="activeKey = 'year'">年</span>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-col>
|
||||
|
@ -89,7 +89,7 @@
|
|||
</a-col>
|
||||
<a-col :span="6">
|
||||
<div>近十次执行时间(不含年)</div>
|
||||
<a-textarea type="textarea" :value="preTimeList" :rows="5"/>
|
||||
<a-textarea type="textarea" :value="preTimeList" :rows="5" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
|
@ -97,209 +97,214 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive, ref, watch, provide } from 'vue'
|
||||
import { useDesign } from '/@/hooks/web/useDesign'
|
||||
import CronParser from 'cron-parser'
|
||||
import SecondUI from './tabs/SecondUI.vue'
|
||||
import MinuteUI from './tabs/MinuteUI.vue'
|
||||
import HourUI from './tabs/HourUI.vue'
|
||||
import DayUI from './tabs/DayUI.vue'
|
||||
import MonthUI from './tabs/MonthUI.vue'
|
||||
import WeekUI from './tabs/WeekUI.vue'
|
||||
import YearUI from './tabs/YearUI.vue'
|
||||
import { cronEmits, cronProps } from './easy.cron.data'
|
||||
import { dateFormat, simpleDebounce } from '/@/utils/common/compUtils'
|
||||
import { computed, reactive, ref, watch, provide } from 'vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import CronParser from 'cron-parser';
|
||||
import SecondUI from './tabs/SecondUI.vue';
|
||||
import MinuteUI from './tabs/MinuteUI.vue';
|
||||
import HourUI from './tabs/HourUI.vue';
|
||||
import DayUI from './tabs/DayUI.vue';
|
||||
import MonthUI from './tabs/MonthUI.vue';
|
||||
import WeekUI from './tabs/WeekUI.vue';
|
||||
import YearUI from './tabs/YearUI.vue';
|
||||
import { cronEmits, cronProps } from './easy.cron.data';
|
||||
import { dateFormat, simpleDebounce } from '/@/utils/common/compUtils';
|
||||
|
||||
const { prefixCls } = useDesign('easy-cron-inner')
|
||||
provide('prefixCls', prefixCls)
|
||||
const emit = defineEmits([...cronEmits])
|
||||
const props = defineProps({ ...cronProps })
|
||||
const activeKey = ref(props.hideSecond ? 'minute' : 'second')
|
||||
const second = ref('*')
|
||||
const minute = ref('*')
|
||||
const hour = ref('*')
|
||||
const day = ref('*')
|
||||
const month = ref('*')
|
||||
const week = ref('?')
|
||||
const year = ref('*')
|
||||
const inputValues = reactive({ second: '', minute: '', hour: '', day: '', month: '', week: '', year: '', cron: '' })
|
||||
const preTimeList = ref('执行预览,会忽略年份参数。')
|
||||
const { prefixCls } = useDesign('easy-cron-inner');
|
||||
provide('prefixCls', prefixCls);
|
||||
const emit = defineEmits([...cronEmits]);
|
||||
const props = defineProps({ ...cronProps });
|
||||
const activeKey = ref(props.hideSecond ? 'minute' : 'second');
|
||||
const second = ref('*');
|
||||
const minute = ref('*');
|
||||
const hour = ref('*');
|
||||
const day = ref('*');
|
||||
const month = ref('*');
|
||||
const week = ref('?');
|
||||
const year = ref('*');
|
||||
const inputValues = reactive({ second: '', minute: '', hour: '', day: '', month: '', week: '', year: '', cron: '' });
|
||||
const preTimeList = ref('执行预览,会忽略年份参数。');
|
||||
|
||||
// cron表达式
|
||||
const cronValueInner = computed(() => {
|
||||
let result: string[] = []
|
||||
if (!props.hideSecond) {
|
||||
result.push(second.value ? second.value : '*')
|
||||
}
|
||||
result.push(minute.value ? minute.value : '*')
|
||||
result.push(hour.value ? hour.value : '*')
|
||||
result.push(day.value ? day.value : '*')
|
||||
result.push(month.value ? month.value : '*')
|
||||
result.push(week.value ? week.value : '?')
|
||||
if (!props.hideYear && !props.hideSecond) result.push(year.value ? year.value : '*')
|
||||
return result.join(' ')
|
||||
})
|
||||
// 不含年
|
||||
const cronValueNoYear = computed(() => {
|
||||
const v = cronValueInner.value
|
||||
if (props.hideYear || props.hideSecond) return v
|
||||
const vs = v.split(' ')
|
||||
if (vs.length >= 6) {
|
||||
// 转成 Quartz 的规则
|
||||
vs[5] = convertWeekToQuartz(vs[5])
|
||||
}
|
||||
return vs.slice(0, vs.length - 1).join(' ')
|
||||
})
|
||||
const calTriggerList = simpleDebounce(calTriggerListInner, 500)
|
||||
|
||||
watch(() => props.value, (newVal) => {
|
||||
if (newVal === cronValueInner.value) {
|
||||
return
|
||||
}
|
||||
formatValue()
|
||||
})
|
||||
|
||||
|
||||
watch(cronValueInner, (newValue) => {
|
||||
calTriggerList()
|
||||
emitValue(newValue)
|
||||
assignInput()
|
||||
})
|
||||
|
||||
// watch(minute, () => {
|
||||
// if (second.value === '*') {
|
||||
// second.value = '0'
|
||||
// }
|
||||
// })
|
||||
// watch(hour, () => {
|
||||
// if (minute.value === '*') {
|
||||
// minute.value = '0'
|
||||
// }
|
||||
// })
|
||||
// watch(day, () => {
|
||||
// if (day.value !== '?' && hour.value === '*') {
|
||||
// hour.value = '0'
|
||||
// }
|
||||
// })
|
||||
// watch(week, () => {
|
||||
// if (week.value !== '?' && hour.value === '*') {
|
||||
// hour.value = '0'
|
||||
// }
|
||||
// })
|
||||
// watch(month, () => {
|
||||
// if (day.value === '?' && week.value === '*') {
|
||||
// week.value = '1'
|
||||
// } else if (week.value === '?' && day.value === '*') {
|
||||
// day.value = '1'
|
||||
// }
|
||||
// })
|
||||
// watch(year, () => {
|
||||
// if (month.value === '*') {
|
||||
// month.value = '1'
|
||||
// }
|
||||
// })
|
||||
|
||||
assignInput()
|
||||
formatValue()
|
||||
calTriggerListInner()
|
||||
|
||||
function assignInput() {
|
||||
inputValues.second = second.value
|
||||
inputValues.minute = minute.value
|
||||
inputValues.hour = hour.value
|
||||
inputValues.day = day.value
|
||||
inputValues.month = month.value
|
||||
inputValues.week = week.value
|
||||
inputValues.year = year.value
|
||||
inputValues.cron = cronValueInner.value
|
||||
}
|
||||
|
||||
function formatValue() {
|
||||
if (!props.value) return
|
||||
const values = props.value.split(' ').filter(item => !!item)
|
||||
if (!values || values.length <= 0) return
|
||||
let i = 0
|
||||
if (!props.hideSecond) second.value = values[i++]
|
||||
if (values.length > i) minute.value = values[i++]
|
||||
if (values.length > i) hour.value = values[i++]
|
||||
if (values.length > i) day.value = values[i++]
|
||||
if (values.length > i) month.value = values[i++]
|
||||
if (values.length > i) week.value = values[i++]
|
||||
if (values.length > i) year.value = values[i]
|
||||
assignInput()
|
||||
}
|
||||
|
||||
// Quartz 的规则:
|
||||
// 1 = 周日,2 = 周一,3 = 周二,4 = 周三,5 = 周四,6 = 周五,7 = 周六
|
||||
function convertWeekToQuartz(week: string) {
|
||||
let convert = (v: string) => {
|
||||
if (v === '0') {
|
||||
return '1'
|
||||
// cron表达式
|
||||
const cronValueInner = computed(() => {
|
||||
let result: string[] = [];
|
||||
if (!props.hideSecond) {
|
||||
result.push(second.value ? second.value : '*');
|
||||
}
|
||||
if (v === '1') {
|
||||
return '0'
|
||||
result.push(minute.value ? minute.value : '*');
|
||||
result.push(hour.value ? hour.value : '*');
|
||||
result.push(day.value ? day.value : '*');
|
||||
result.push(month.value ? month.value : '*');
|
||||
result.push(week.value ? week.value : '?');
|
||||
if (!props.hideYear && !props.hideSecond) result.push(year.value ? year.value : '*');
|
||||
return result.join(' ');
|
||||
});
|
||||
// 不含年
|
||||
const cronValueNoYear = computed(() => {
|
||||
const v = cronValueInner.value;
|
||||
if (props.hideYear || props.hideSecond) return v;
|
||||
const vs = v.split(' ');
|
||||
if (vs.length >= 6) {
|
||||
// 转成 Quartz 的规则
|
||||
vs[5] = convertWeekToQuartz(vs[5]);
|
||||
}
|
||||
return (Number.parseInt(v) - 1).toString()
|
||||
}
|
||||
// 匹配示例 1-7 or 1/7
|
||||
let patten1 = /^([0-7])([-/])([0-7])$/
|
||||
// 匹配示例 1,4,7
|
||||
let patten2 = /^([0-7])(,[0-7])+$/
|
||||
if (/^[0-7]$/.test(week)) {
|
||||
return convert(week)
|
||||
} else if (patten1.test(week)) {
|
||||
return week.replace(patten1, ($0, before, separator, after) => {
|
||||
if (separator === '/') {
|
||||
return convert(before) + separator + after
|
||||
} else {
|
||||
return convert(before) + separator + convert(after)
|
||||
return vs.slice(0, vs.length - 1).join(' ');
|
||||
});
|
||||
const calTriggerList = simpleDebounce(calTriggerListInner, 500);
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(newVal) => {
|
||||
if (newVal === cronValueInner.value) {
|
||||
return;
|
||||
}
|
||||
})
|
||||
} else if (patten2.test(week)) {
|
||||
return week.split(',').map(v => convert(v)).join(',')
|
||||
}
|
||||
return week
|
||||
}
|
||||
formatValue();
|
||||
}
|
||||
);
|
||||
|
||||
function calTriggerListInner() {
|
||||
// 设置了回调函数
|
||||
if (props.remote) {
|
||||
props.remote(cronValueInner.value, +new Date(), v => {
|
||||
preTimeList.value = v
|
||||
})
|
||||
return
|
||||
}
|
||||
const format = 'yyyy-MM-dd hh:mm:ss'
|
||||
const options = {
|
||||
currentDate: dateFormat(new Date(), format),
|
||||
}
|
||||
const iter = CronParser.parseExpression(cronValueNoYear.value, options)
|
||||
const result: string[] = []
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
result.push(dateFormat(new Date(iter.next() as any), format))
|
||||
}
|
||||
preTimeList.value = result.length > 0 ? result.join('\n') : '无执行时间'
|
||||
}
|
||||
watch(cronValueInner, (newValue) => {
|
||||
calTriggerList();
|
||||
emitValue(newValue);
|
||||
assignInput();
|
||||
});
|
||||
|
||||
function onInputBlur() {
|
||||
second.value = inputValues.second
|
||||
minute.value = inputValues.minute
|
||||
hour.value = inputValues.hour
|
||||
day.value = inputValues.day
|
||||
month.value = inputValues.month
|
||||
week.value = inputValues.week
|
||||
year.value = inputValues.year
|
||||
}
|
||||
// watch(minute, () => {
|
||||
// if (second.value === '*') {
|
||||
// second.value = '0'
|
||||
// }
|
||||
// })
|
||||
// watch(hour, () => {
|
||||
// if (minute.value === '*') {
|
||||
// minute.value = '0'
|
||||
// }
|
||||
// })
|
||||
// watch(day, () => {
|
||||
// if (day.value !== '?' && hour.value === '*') {
|
||||
// hour.value = '0'
|
||||
// }
|
||||
// })
|
||||
// watch(week, () => {
|
||||
// if (week.value !== '?' && hour.value === '*') {
|
||||
// hour.value = '0'
|
||||
// }
|
||||
// })
|
||||
// watch(month, () => {
|
||||
// if (day.value === '?' && week.value === '*') {
|
||||
// week.value = '1'
|
||||
// } else if (week.value === '?' && day.value === '*') {
|
||||
// day.value = '1'
|
||||
// }
|
||||
// })
|
||||
// watch(year, () => {
|
||||
// if (month.value === '*') {
|
||||
// month.value = '1'
|
||||
// }
|
||||
// })
|
||||
|
||||
function onInputCronBlur(event) {
|
||||
emitValue(event.target.value)
|
||||
}
|
||||
assignInput();
|
||||
formatValue();
|
||||
calTriggerListInner();
|
||||
|
||||
function emitValue(value) {
|
||||
emit('change', value)
|
||||
emit('update:value', value)
|
||||
}
|
||||
function assignInput() {
|
||||
inputValues.second = second.value;
|
||||
inputValues.minute = minute.value;
|
||||
inputValues.hour = hour.value;
|
||||
inputValues.day = day.value;
|
||||
inputValues.month = month.value;
|
||||
inputValues.week = week.value;
|
||||
inputValues.year = year.value;
|
||||
inputValues.cron = cronValueInner.value;
|
||||
}
|
||||
|
||||
function formatValue() {
|
||||
if (!props.value) return;
|
||||
const values = props.value.split(' ').filter((item) => !!item);
|
||||
if (!values || values.length <= 0) return;
|
||||
let i = 0;
|
||||
if (!props.hideSecond) second.value = values[i++];
|
||||
if (values.length > i) minute.value = values[i++];
|
||||
if (values.length > i) hour.value = values[i++];
|
||||
if (values.length > i) day.value = values[i++];
|
||||
if (values.length > i) month.value = values[i++];
|
||||
if (values.length > i) week.value = values[i++];
|
||||
if (values.length > i) year.value = values[i];
|
||||
assignInput();
|
||||
}
|
||||
|
||||
// Quartz 的规则:
|
||||
// 1 = 周日,2 = 周一,3 = 周二,4 = 周三,5 = 周四,6 = 周五,7 = 周六
|
||||
function convertWeekToQuartz(week: string) {
|
||||
let convert = (v: string) => {
|
||||
if (v === '0') {
|
||||
return '1';
|
||||
}
|
||||
if (v === '1') {
|
||||
return '0';
|
||||
}
|
||||
return (Number.parseInt(v) - 1).toString();
|
||||
};
|
||||
// 匹配示例 1-7 or 1/7
|
||||
let patten1 = /^([0-7])([-/])([0-7])$/;
|
||||
// 匹配示例 1,4,7
|
||||
let patten2 = /^([0-7])(,[0-7])+$/;
|
||||
if (/^[0-7]$/.test(week)) {
|
||||
return convert(week);
|
||||
} else if (patten1.test(week)) {
|
||||
return week.replace(patten1, ($0, before, separator, after) => {
|
||||
if (separator === '/') {
|
||||
return convert(before) + separator + after;
|
||||
} else {
|
||||
return convert(before) + separator + convert(after);
|
||||
}
|
||||
});
|
||||
} else if (patten2.test(week)) {
|
||||
return week
|
||||
.split(',')
|
||||
.map((v) => convert(v))
|
||||
.join(',');
|
||||
}
|
||||
return week;
|
||||
}
|
||||
|
||||
function calTriggerListInner() {
|
||||
// 设置了回调函数
|
||||
if (props.remote) {
|
||||
props.remote(cronValueInner.value, +new Date(), (v) => {
|
||||
preTimeList.value = v;
|
||||
});
|
||||
return;
|
||||
}
|
||||
const format = 'yyyy-MM-dd hh:mm:ss';
|
||||
const options = {
|
||||
currentDate: dateFormat(new Date(), format),
|
||||
};
|
||||
const iter = CronParser.parseExpression(cronValueNoYear.value, options);
|
||||
const result: string[] = [];
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
result.push(dateFormat(new Date(iter.next() as any), format));
|
||||
}
|
||||
preTimeList.value = result.length > 0 ? result.join('\n') : '无执行时间';
|
||||
}
|
||||
|
||||
function onInputBlur() {
|
||||
second.value = inputValues.second;
|
||||
minute.value = inputValues.minute;
|
||||
hour.value = inputValues.hour;
|
||||
day.value = inputValues.day;
|
||||
month.value = inputValues.month;
|
||||
week.value = inputValues.week;
|
||||
year.value = inputValues.year;
|
||||
}
|
||||
|
||||
function onInputCronBlur(event) {
|
||||
emitValue(event.target.value);
|
||||
}
|
||||
|
||||
function emitValue(value) {
|
||||
emit('change', value);
|
||||
emit('update:value', value);
|
||||
}
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import "easy.cron.inner";
|
||||
</style>
|
||||
@import 'easy.cron.inner';
|
||||
</style>
|
||||
|
|
|
@ -2,62 +2,55 @@
|
|||
<div :class="`${prefixCls}`">
|
||||
<a-input :placeholder="placeholder" v-model:value="editCronValue" :disabled="disabled">
|
||||
<template #addonAfter>
|
||||
<a class="open-btn" :disabled="disabled?'disabled':null" @click="showConfigModal">
|
||||
<Icon icon="ant-design:setting-outlined"/>
|
||||
<a class="open-btn" :disabled="disabled ? 'disabled' : null" @click="showConfigModal">
|
||||
<Icon icon="ant-design:setting-outlined" />
|
||||
<span>选择</span>
|
||||
</a>
|
||||
</template>
|
||||
</a-input>
|
||||
<EasyCronModal
|
||||
@register="registerModal"
|
||||
v-model:value="editCronValue"
|
||||
:exeStartTime="exeStartTime"
|
||||
:hideYear="hideYear"
|
||||
:remote="remote"
|
||||
:hideSecond="hideSecond"/>
|
||||
<EasyCronModal @register="registerModal" v-model:value="editCronValue" :exeStartTime="exeStartTime" :hideYear="hideYear" :remote="remote" :hideSecond="hideSecond" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { useDesign } from '/@/hooks/web/useDesign'
|
||||
import { useModal } from '/@/components/Modal'
|
||||
import { propTypes } from '/@/utils/propTypes'
|
||||
import Icon from '/@/components/Icon/src/Icon.vue'
|
||||
import EasyCronModal from './EasyCronModal.vue'
|
||||
import { cronEmits, cronProps } from './easy.cron.data'
|
||||
import { ref, watch } from 'vue';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import Icon from '/@/components/Icon/src/Icon.vue';
|
||||
import EasyCronModal from './EasyCronModal.vue';
|
||||
import { cronEmits, cronProps } from './easy.cron.data';
|
||||
|
||||
const { prefixCls } = useDesign('easy-cron-input')
|
||||
const emit = defineEmits([...cronEmits])
|
||||
const props = defineProps({
|
||||
...cronProps,
|
||||
placeholder: propTypes.string.def('请输入cron表达式'),
|
||||
exeStartTime: propTypes.oneOfType([
|
||||
propTypes.number,
|
||||
propTypes.string,
|
||||
propTypes.object,
|
||||
]).def(0),
|
||||
})
|
||||
const [registerModal, { openModal }] = useModal()
|
||||
const editCronValue = ref(props.value)
|
||||
const { prefixCls } = useDesign('easy-cron-input');
|
||||
const emit = defineEmits([...cronEmits]);
|
||||
const props = defineProps({
|
||||
...cronProps,
|
||||
placeholder: propTypes.string.def('请输入cron表达式'),
|
||||
exeStartTime: propTypes.oneOfType([propTypes.number, propTypes.string, propTypes.object]).def(0),
|
||||
});
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const editCronValue = ref(props.value);
|
||||
|
||||
watch(() => props.value, (newVal) => {
|
||||
if (newVal !== editCronValue.value) {
|
||||
editCronValue.value = newVal
|
||||
watch(
|
||||
() => props.value,
|
||||
(newVal) => {
|
||||
if (newVal !== editCronValue.value) {
|
||||
editCronValue.value = newVal;
|
||||
}
|
||||
}
|
||||
);
|
||||
watch(editCronValue, (newVal) => {
|
||||
emit('change', newVal);
|
||||
emit('update:value', newVal);
|
||||
});
|
||||
|
||||
function showConfigModal() {
|
||||
if (!props.disabled) {
|
||||
openModal();
|
||||
}
|
||||
}
|
||||
})
|
||||
watch(editCronValue, (newVal) => {
|
||||
emit('change', newVal)
|
||||
emit('update:value', newVal)
|
||||
})
|
||||
|
||||
function showConfigModal() {
|
||||
if (!props.disabled) {
|
||||
openModal()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@import "easy.cron.input";
|
||||
@import 'easy.cron.input';
|
||||
</style>
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
<template>
|
||||
<BasicModal @register="registerModal" title="Cron表达式" width="800px" @ok="onOk">
|
||||
<EasyCron v-bind="attrs"/>
|
||||
<EasyCron v-bind="attrs" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs'
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal'
|
||||
import EasyCron from './EasyCronInner.vue'
|
||||
import { defineComponent } from 'vue';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import EasyCron from './EasyCronInner.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'EasyCronModal',
|
||||
inheritAttrs: false,
|
||||
components: { BasicModal, EasyCron },
|
||||
setup() {
|
||||
const attrs = useAttrs()
|
||||
const [registerModal, { closeModal }] = useModalInner()
|
||||
export default defineComponent({
|
||||
name: 'EasyCronModal',
|
||||
inheritAttrs: false,
|
||||
components: { BasicModal, EasyCron },
|
||||
setup() {
|
||||
const attrs = useAttrs();
|
||||
const [registerModal, { closeModal }] = useModalInner();
|
||||
|
||||
function onOk() {
|
||||
closeModal()
|
||||
}
|
||||
function onOk() {
|
||||
closeModal();
|
||||
}
|
||||
|
||||
return { attrs, registerModal, onOk }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
return { attrs, registerModal, onOk };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { propTypes } from '/@/utils/propTypes'
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
export const cronEmits = ['change', 'update:value']
|
||||
export const cronEmits = ['change', 'update:value'];
|
||||
export const cronProps = {
|
||||
value: propTypes.string.def(''),
|
||||
disabled: propTypes.bool.def(false),
|
||||
hideSecond: propTypes.bool.def(false),
|
||||
hideYear: propTypes.bool.def(false),
|
||||
remote: propTypes.func,
|
||||
}
|
||||
};
|
||||
|
|
|
@ -44,11 +44,11 @@
|
|||
}
|
||||
|
||||
.tip-info {
|
||||
color: #999
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.allow-click {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,4 +11,4 @@
|
|||
right: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 原开源项目地址:https://gitee.com/toktok/easy-cron
|
||||
|
||||
export { default as JEasyCron } from './EasyCronInput.vue'
|
||||
export { default as JEasyCronInner } from './EasyCronInner.vue'
|
||||
export { default as JEasyCronModal } from './EasyCronModal.vue'
|
||||
export { default as JCronValidator } from './validator'
|
||||
export { default as JEasyCron } from './EasyCronInput.vue';
|
||||
export { default as JEasyCronInner } from './EasyCronInner.vue';
|
||||
export { default as JEasyCronModal } from './EasyCronModal.vue';
|
||||
export { default as JCronValidator } from './validator';
|
||||
|
|
|
@ -11,23 +11,23 @@
|
|||
<div class="item">
|
||||
<a-radio :value="TypeEnum.range" v-bind="beforeRadioAttrs">区间</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber v-model:value="valueRange.start" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber v-model:value="valueRange.start" v-bind="typeRangeAttrs" />
|
||||
<span> 日 至 </span>
|
||||
<InputNumber v-model:value="valueRange.end" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber v-model:value="valueRange.end" v-bind="typeRangeAttrs" />
|
||||
<span> 日 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs">循环</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber v-model:value="valueLoop.start" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.start" v-bind="typeLoopAttrs" />
|
||||
<span> 日开始,间隔 </span>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs" />
|
||||
<span> 日 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio :value="TypeEnum.work" v-bind="beforeRadioAttrs">工作日</a-radio>
|
||||
<span> 本月 </span>
|
||||
<InputNumber v-model:value="valueWork" v-bind="typeWorkAttrs"/>
|
||||
<InputNumber v-model:value="valueWork" v-bind="typeWorkAttrs" />
|
||||
<span> 日,最近的工作日 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
|
@ -48,43 +48,46 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, watch } from 'vue'
|
||||
import { InputNumber } from 'ant-design-vue'
|
||||
import { TypeEnum, useTabEmits, useTabProps, useTabSetup } from './useTabMixin'
|
||||
import { computed, defineComponent, watch } from 'vue';
|
||||
import { InputNumber } from 'ant-design-vue';
|
||||
import { TypeEnum, useTabEmits, useTabProps, useTabSetup } from './useTabMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DayUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
props: {
|
||||
week: { type: String, default: '?' },
|
||||
},
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
const disabledChoice = computed(() => {
|
||||
return (props.week && props.week !== '?') || props.disabled
|
||||
})
|
||||
const setup = useTabSetup(props, context, {
|
||||
export default defineComponent({
|
||||
name: 'DayUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
valueWork: 1,
|
||||
minValue: 1,
|
||||
maxValue: 31,
|
||||
valueRange: { start: 1, end: 31 },
|
||||
valueLoop: { start: 1, interval: 1 },
|
||||
disabled: disabledChoice,
|
||||
})
|
||||
const typeWorkAttrs = computed(() => ({
|
||||
disabled: setup.type.value !== TypeEnum.work || props.disabled || disabledChoice.value,
|
||||
...setup.inputNumberAttrs.value,
|
||||
}))
|
||||
props: {
|
||||
week: { type: String, default: '?' },
|
||||
},
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
const disabledChoice = computed(() => {
|
||||
return (props.week && props.week !== '?') || props.disabled;
|
||||
});
|
||||
const setup = useTabSetup(props, context, {
|
||||
defaultValue: '*',
|
||||
valueWork: 1,
|
||||
minValue: 1,
|
||||
maxValue: 31,
|
||||
valueRange: { start: 1, end: 31 },
|
||||
valueLoop: { start: 1, interval: 1 },
|
||||
disabled: disabledChoice,
|
||||
});
|
||||
const typeWorkAttrs = computed(() => ({
|
||||
disabled: setup.type.value !== TypeEnum.work || props.disabled || disabledChoice.value,
|
||||
...setup.inputNumberAttrs.value,
|
||||
}));
|
||||
|
||||
watch(() => props.week, () => {
|
||||
setup.updateValue(disabledChoice.value ? '?' : setup.computeValue.value)
|
||||
})
|
||||
watch(
|
||||
() => props.week,
|
||||
() => {
|
||||
setup.updateValue(disabledChoice.value ? '?' : setup.computeValue.value);
|
||||
}
|
||||
);
|
||||
|
||||
return { ...setup, typeWorkAttrs }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
return { ...setup, typeWorkAttrs };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -7,17 +7,17 @@
|
|||
<div class="item">
|
||||
<a-radio :value="TypeEnum.range" v-bind="beforeRadioAttrs">区间</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber v-model:value="valueRange.start" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber v-model:value="valueRange.start" v-bind="typeRangeAttrs" />
|
||||
<span> 时 至 </span>
|
||||
<InputNumber v-model:value="valueRange.end" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber v-model:value="valueRange.end" v-bind="typeRangeAttrs" />
|
||||
<span> 时 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs">循环</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber v-model:value="valueLoop.start" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.start" v-bind="typeLoopAttrs" />
|
||||
<span> 时开始,间隔 </span>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs" />
|
||||
<span> 时 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
|
@ -35,25 +35,25 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { InputNumber } from 'ant-design-vue'
|
||||
import { useTabProps, useTabEmits, useTabSetup } from './useTabMixin'
|
||||
import { defineComponent } from 'vue';
|
||||
import { InputNumber } from 'ant-design-vue';
|
||||
import { useTabProps, useTabEmits, useTabSetup } from './useTabMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'HourUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
return useTabSetup(props, context, {
|
||||
export default defineComponent({
|
||||
name: 'HourUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
minValue: 0,
|
||||
maxValue: 23,
|
||||
valueRange: { start: 0, end: 23 },
|
||||
valueLoop: { start: 0, interval: 1 },
|
||||
})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
return useTabSetup(props, context, {
|
||||
defaultValue: '*',
|
||||
minValue: 0,
|
||||
maxValue: 23,
|
||||
valueRange: { start: 0, end: 23 },
|
||||
valueLoop: { start: 0, interval: 1 },
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -7,17 +7,17 @@
|
|||
<div class="item">
|
||||
<a-radio :value="TypeEnum.range" v-bind="beforeRadioAttrs">区间</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber v-model:value="valueRange.start" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber v-model:value="valueRange.start" v-bind="typeRangeAttrs" />
|
||||
<span> 分 至 </span>
|
||||
<InputNumber v-model:value="valueRange.end" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber v-model:value="valueRange.end" v-bind="typeRangeAttrs" />
|
||||
<span> 分 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs">循环</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber v-model:value="valueLoop.start" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.start" v-bind="typeLoopAttrs" />
|
||||
<span> 分开始,间隔 </span>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs" />
|
||||
<span> 分 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
|
@ -35,25 +35,25 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { InputNumber } from 'ant-design-vue'
|
||||
import { useTabProps, useTabEmits, useTabSetup } from './useTabMixin'
|
||||
import { defineComponent } from 'vue';
|
||||
import { InputNumber } from 'ant-design-vue';
|
||||
import { useTabProps, useTabEmits, useTabSetup } from './useTabMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MinuteUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
return useTabSetup(props, context, {
|
||||
export default defineComponent({
|
||||
name: 'MinuteUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
minValue: 0,
|
||||
maxValue: 59,
|
||||
valueRange: { start: 0, end: 59 },
|
||||
valueLoop: { start: 0, interval: 1 },
|
||||
})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
return useTabSetup(props, context, {
|
||||
defaultValue: '*',
|
||||
minValue: 0,
|
||||
maxValue: 59,
|
||||
valueRange: { start: 0, end: 59 },
|
||||
valueLoop: { start: 0, interval: 1 },
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -7,17 +7,17 @@
|
|||
<div class="item">
|
||||
<a-radio :value="TypeEnum.range" v-bind="beforeRadioAttrs">区间</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber v-model:value="valueRange.start" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber v-model:value="valueRange.start" v-bind="typeRangeAttrs" />
|
||||
<span> 月 至 </span>
|
||||
<InputNumber v-model:value="valueRange.end" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber v-model:value="valueRange.end" v-bind="typeRangeAttrs" />
|
||||
<span> 月 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs">循环</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber v-model:value="valueLoop.start" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.start" v-bind="typeLoopAttrs" />
|
||||
<span> 月开始,间隔 </span>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs" />
|
||||
<span> 月 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
|
@ -35,25 +35,25 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { InputNumber } from 'ant-design-vue'
|
||||
import { useTabProps, useTabEmits, useTabSetup } from './useTabMixin'
|
||||
import { defineComponent } from 'vue';
|
||||
import { InputNumber } from 'ant-design-vue';
|
||||
import { useTabProps, useTabEmits, useTabSetup } from './useTabMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MonthUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
return useTabSetup(props, context, {
|
||||
export default defineComponent({
|
||||
name: 'MonthUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
minValue: 1,
|
||||
maxValue: 12,
|
||||
valueRange: { start: 1, end: 12 },
|
||||
valueLoop: { start: 1, interval: 1 },
|
||||
})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
return useTabSetup(props, context, {
|
||||
defaultValue: '*',
|
||||
minValue: 1,
|
||||
maxValue: 12,
|
||||
valueRange: { start: 1, end: 12 },
|
||||
valueLoop: { start: 1, interval: 1 },
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -7,17 +7,17 @@
|
|||
<div class="item">
|
||||
<a-radio :value="TypeEnum.range" v-bind="beforeRadioAttrs">区间</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber v-model:value="valueRange.start" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber v-model:value="valueRange.start" v-bind="typeRangeAttrs" />
|
||||
<span> 秒 至 </span>
|
||||
<InputNumber v-model:value="valueRange.end" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber v-model:value="valueRange.end" v-bind="typeRangeAttrs" />
|
||||
<span> 秒 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs">循环</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber v-model:value="valueLoop.start" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.start" v-bind="typeLoopAttrs" />
|
||||
<span> 秒开始,间隔 </span>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs" />
|
||||
<span> 秒 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
|
@ -35,25 +35,25 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { InputNumber } from 'ant-design-vue'
|
||||
import { useTabProps, useTabEmits, useTabSetup } from './useTabMixin'
|
||||
import { defineComponent } from 'vue';
|
||||
import { InputNumber } from 'ant-design-vue';
|
||||
import { useTabProps, useTabEmits, useTabSetup } from './useTabMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'SecondUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
return useTabSetup(props, context, {
|
||||
export default defineComponent({
|
||||
name: 'SecondUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
minValue: 0,
|
||||
maxValue: 59,
|
||||
valueRange: { start: 0, end: 59 },
|
||||
valueLoop: { start: 0, interval: 1 },
|
||||
})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
return useTabSetup(props, context, {
|
||||
defaultValue: '*',
|
||||
minValue: 0,
|
||||
maxValue: 59,
|
||||
valueRange: { start: 0, end: 59 },
|
||||
valueLoop: { start: 0, interval: 1 },
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -8,16 +8,16 @@
|
|||
<div class="item">
|
||||
<a-radio :value="TypeEnum.range" v-bind="beforeRadioAttrs">区间</a-radio>
|
||||
<span> 从 </span>
|
||||
<a-select v-model:value="valueRange.start" :options="weekOptions" v-bind="typeRangeSelectAttrs"/>
|
||||
<a-select v-model:value="valueRange.start" :options="weekOptions" v-bind="typeRangeSelectAttrs" />
|
||||
<span> 至 </span>
|
||||
<a-select v-model:value="valueRange.end" :options="weekOptions" v-bind="typeRangeSelectAttrs"/>
|
||||
<a-select v-model:value="valueRange.end" :options="weekOptions" v-bind="typeRangeSelectAttrs" />
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs">循环</a-radio>
|
||||
<span> 从 </span>
|
||||
<a-select v-model:value="valueLoop.start" :options="weekOptions" v-bind="typeLoopSelectAttrs"/>
|
||||
<a-select v-model:value="valueLoop.start" :options="weekOptions" v-bind="typeLoopSelectAttrs" />
|
||||
<span> 开始,间隔 </span>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber v-model:value="valueLoop.interval" v-bind="typeLoopAttrs" />
|
||||
<span> 天 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
|
@ -35,88 +35,91 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, watch, defineComponent } from 'vue'
|
||||
import { InputNumber } from 'ant-design-vue'
|
||||
import { useTabProps, useTabEmits, useTabSetup, TypeEnum } from './useTabMixin'
|
||||
import { computed, watch, defineComponent } from 'vue';
|
||||
import { InputNumber } from 'ant-design-vue';
|
||||
import { useTabProps, useTabEmits, useTabSetup, TypeEnum } from './useTabMixin';
|
||||
|
||||
const WEEK_MAP_EN = {
|
||||
'1': 'SUN',
|
||||
'2': 'MON',
|
||||
'3': 'TUE',
|
||||
'4': 'WED',
|
||||
'5': 'THU',
|
||||
'6': 'FRI',
|
||||
'7': 'SAT',
|
||||
}
|
||||
const WEEK_MAP_EN = {
|
||||
'1': 'SUN',
|
||||
'2': 'MON',
|
||||
'3': 'TUE',
|
||||
'4': 'WED',
|
||||
'5': 'THU',
|
||||
'6': 'FRI',
|
||||
'7': 'SAT',
|
||||
};
|
||||
|
||||
const WEEK_MAP_CN = {
|
||||
'1': '周日',
|
||||
'2': '周一',
|
||||
'3': '周二',
|
||||
'4': '周三',
|
||||
'5': '周四',
|
||||
'6': '周五',
|
||||
'7': '周六',
|
||||
}
|
||||
const WEEK_MAP_CN = {
|
||||
'1': '周日',
|
||||
'2': '周一',
|
||||
'3': '周二',
|
||||
'4': '周三',
|
||||
'5': '周四',
|
||||
'6': '周五',
|
||||
'7': '周六',
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
name: 'WeekUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '?',
|
||||
props: {
|
||||
day: { type: String, default: '*' },
|
||||
},
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
const disabledChoice = computed(() => {
|
||||
return (props.day && props.day !== '?') || props.disabled
|
||||
})
|
||||
const setup = useTabSetup(props, context, {
|
||||
defaultType: TypeEnum.unset,
|
||||
export default defineComponent({
|
||||
name: 'WeekUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '?',
|
||||
minValue: 1,
|
||||
maxValue: 7,
|
||||
// 0,7表示周日 1表示周一
|
||||
valueRange: { start: 1, end: 7 },
|
||||
valueLoop: { start: 2, interval: 1 },
|
||||
disabled: disabledChoice,
|
||||
})
|
||||
const weekOptions = computed(() => {
|
||||
let options: { label: string, value: number }[] = []
|
||||
for (let weekKey of Object.keys(WEEK_MAP_CN)) {
|
||||
let weekName: string = WEEK_MAP_CN[weekKey]
|
||||
options.push({
|
||||
value: Number.parseInt(weekKey),
|
||||
label: weekName,
|
||||
})
|
||||
}
|
||||
return options
|
||||
})
|
||||
props: {
|
||||
day: { type: String, default: '*' },
|
||||
},
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
const disabledChoice = computed(() => {
|
||||
return (props.day && props.day !== '?') || props.disabled;
|
||||
});
|
||||
const setup = useTabSetup(props, context, {
|
||||
defaultType: TypeEnum.unset,
|
||||
defaultValue: '?',
|
||||
minValue: 1,
|
||||
maxValue: 7,
|
||||
// 0,7表示周日 1表示周一
|
||||
valueRange: { start: 1, end: 7 },
|
||||
valueLoop: { start: 2, interval: 1 },
|
||||
disabled: disabledChoice,
|
||||
});
|
||||
const weekOptions = computed(() => {
|
||||
let options: { label: string; value: number }[] = [];
|
||||
for (let weekKey of Object.keys(WEEK_MAP_CN)) {
|
||||
let weekName: string = WEEK_MAP_CN[weekKey];
|
||||
options.push({
|
||||
value: Number.parseInt(weekKey),
|
||||
label: weekName,
|
||||
});
|
||||
}
|
||||
return options;
|
||||
});
|
||||
|
||||
const typeRangeSelectAttrs = computed(() => ({
|
||||
class: ['w80'],
|
||||
disabled: setup.typeRangeAttrs.value.disabled,
|
||||
}))
|
||||
const typeRangeSelectAttrs = computed(() => ({
|
||||
class: ['w80'],
|
||||
disabled: setup.typeRangeAttrs.value.disabled,
|
||||
}));
|
||||
|
||||
const typeLoopSelectAttrs = computed(() => ({
|
||||
class: ['w80'],
|
||||
disabled: setup.typeLoopAttrs.value.disabled,
|
||||
}))
|
||||
const typeLoopSelectAttrs = computed(() => ({
|
||||
class: ['w80'],
|
||||
disabled: setup.typeLoopAttrs.value.disabled,
|
||||
}));
|
||||
|
||||
watch(() => props.day, () => {
|
||||
setup.updateValue(disabledChoice.value ? '?' : setup.computeValue.value)
|
||||
})
|
||||
watch(
|
||||
() => props.day,
|
||||
() => {
|
||||
setup.updateValue(disabledChoice.value ? '?' : setup.computeValue.value);
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
...setup,
|
||||
weekOptions,
|
||||
typeLoopSelectAttrs,
|
||||
typeRangeSelectAttrs,
|
||||
WEEK_MAP_CN, WEEK_MAP_EN,
|
||||
}
|
||||
},
|
||||
|
||||
})
|
||||
</script>
|
||||
return {
|
||||
...setup,
|
||||
weekOptions,
|
||||
typeLoopSelectAttrs,
|
||||
typeRangeSelectAttrs,
|
||||
WEEK_MAP_CN,
|
||||
WEEK_MAP_EN,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -7,17 +7,17 @@
|
|||
<div class="item">
|
||||
<a-radio :value="TypeEnum.range" v-bind="beforeRadioAttrs">区间</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber class="w80" v-model:value="valueRange.start" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber class="w80" v-model:value="valueRange.start" v-bind="typeRangeAttrs" />
|
||||
<span> 年 至 </span>
|
||||
<InputNumber class="w80" v-model:value="valueRange.end" v-bind="typeRangeAttrs"/>
|
||||
<InputNumber class="w80" v-model:value="valueRange.end" v-bind="typeRangeAttrs" />
|
||||
<span> 年 </span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio :value="TypeEnum.loop" v-bind="beforeRadioAttrs">循环</a-radio>
|
||||
<span> 从 </span>
|
||||
<InputNumber class="w80" v-model:value="valueLoop.start" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber class="w80" v-model:value="valueLoop.start" v-bind="typeLoopAttrs" />
|
||||
<span> 年开始,间隔 </span>
|
||||
<InputNumber class="w80" v-model:value="valueLoop.interval" v-bind="typeLoopAttrs"/>
|
||||
<InputNumber class="w80" v-model:value="valueLoop.interval" v-bind="typeLoopAttrs" />
|
||||
<span> 年 </span>
|
||||
</div>
|
||||
</a-radio-group>
|
||||
|
@ -25,25 +25,25 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { InputNumber } from 'ant-design-vue'
|
||||
import { useTabProps, useTabEmits, useTabSetup } from './useTabMixin'
|
||||
import { defineComponent } from 'vue';
|
||||
import { InputNumber } from 'ant-design-vue';
|
||||
import { useTabProps, useTabEmits, useTabSetup } from './useTabMixin';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'YearUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
const nowYear = (new Date()).getFullYear()
|
||||
return useTabSetup(props, context, {
|
||||
export default defineComponent({
|
||||
name: 'YearUI',
|
||||
components: { InputNumber },
|
||||
props: useTabProps({
|
||||
defaultValue: '*',
|
||||
minValue: 0,
|
||||
valueRange: { start: nowYear, end: nowYear + 100 },
|
||||
valueLoop: { start: nowYear, interval: 1 },
|
||||
})
|
||||
},
|
||||
})
|
||||
</script>
|
||||
}),
|
||||
emits: useTabEmits(),
|
||||
setup(props, context) {
|
||||
const nowYear = new Date().getFullYear();
|
||||
return useTabSetup(props, context, {
|
||||
defaultValue: '*',
|
||||
minValue: 0,
|
||||
valueRange: { start: nowYear, end: nowYear + 100 },
|
||||
valueLoop: { start: nowYear, interval: 1 },
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// 主要用于日和星期的互斥使用
|
||||
import { computed, inject, reactive, ref, unref, watch } from 'vue'
|
||||
import { propTypes } from '/@/utils/propTypes'
|
||||
import { computed, inject, reactive, ref, unref, watch } from 'vue';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
export enum TypeEnum {
|
||||
unset = 'UNSET',
|
||||
|
@ -14,91 +14,95 @@ export enum TypeEnum {
|
|||
|
||||
// use 公共 props
|
||||
export function useTabProps(options) {
|
||||
const defaultValue = options?.defaultValue ?? '?'
|
||||
const defaultValue = options?.defaultValue ?? '?';
|
||||
return {
|
||||
value: propTypes.string.def(defaultValue),
|
||||
disabled: propTypes.bool.def(false),
|
||||
...options?.props,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// use 公共 emits
|
||||
export function useTabEmits() {
|
||||
return ['change', 'update:value']
|
||||
return ['change', 'update:value'];
|
||||
}
|
||||
|
||||
// use 公共 setup
|
||||
export function useTabSetup(props, context, options) {
|
||||
const { emit } = context
|
||||
const prefixCls = inject('prefixCls')
|
||||
const defaultValue = ref(options?.defaultValue ?? '?')
|
||||
const { emit } = context;
|
||||
const prefixCls = inject('prefixCls');
|
||||
const defaultValue = ref(options?.defaultValue ?? '?');
|
||||
// 类型
|
||||
const type = ref(options.defaultType ?? TypeEnum.every)
|
||||
const valueList = ref<any[]>([])
|
||||
const type = ref(options.defaultType ?? TypeEnum.every);
|
||||
const valueList = ref<any[]>([]);
|
||||
// 对于不同的类型,所定义的值也有所不同
|
||||
const valueRange = reactive(options.valueRange)
|
||||
const valueLoop = reactive(options.valueLoop)
|
||||
const valueWeek = reactive(options.valueWeek)
|
||||
const valueWork = ref(options.valueWork)
|
||||
const maxValue = ref(options.maxValue)
|
||||
const minValue = ref(options.minValue)
|
||||
const valueRange = reactive(options.valueRange);
|
||||
const valueLoop = reactive(options.valueLoop);
|
||||
const valueWeek = reactive(options.valueWeek);
|
||||
const valueWork = ref(options.valueWork);
|
||||
const maxValue = ref(options.maxValue);
|
||||
const minValue = ref(options.minValue);
|
||||
|
||||
// 根据不同的类型计算出的value
|
||||
const computeValue = computed(() => {
|
||||
let valueArray: any[] = []
|
||||
let valueArray: any[] = [];
|
||||
switch (type.value) {
|
||||
case TypeEnum.unset:
|
||||
valueArray.push('?')
|
||||
break
|
||||
valueArray.push('?');
|
||||
break;
|
||||
case TypeEnum.every:
|
||||
valueArray.push('*')
|
||||
break
|
||||
valueArray.push('*');
|
||||
break;
|
||||
case TypeEnum.range:
|
||||
valueArray.push(`${valueRange.start}-${valueRange.end}`)
|
||||
break
|
||||
valueArray.push(`${valueRange.start}-${valueRange.end}`);
|
||||
break;
|
||||
case TypeEnum.loop:
|
||||
valueArray.push(`${valueLoop.start}/${valueLoop.interval}`)
|
||||
break
|
||||
valueArray.push(`${valueLoop.start}/${valueLoop.interval}`);
|
||||
break;
|
||||
case TypeEnum.work:
|
||||
valueArray.push(`${valueWork.value}W`)
|
||||
break
|
||||
valueArray.push(`${valueWork.value}W`);
|
||||
break;
|
||||
case TypeEnum.last:
|
||||
valueArray.push('L')
|
||||
break
|
||||
valueArray.push('L');
|
||||
break;
|
||||
case TypeEnum.specify:
|
||||
if (valueList.value.length === 0) {
|
||||
valueList.value.push(minValue.value)
|
||||
valueList.value.push(minValue.value);
|
||||
}
|
||||
valueArray.push(valueList.value.join(','))
|
||||
break
|
||||
valueArray.push(valueList.value.join(','));
|
||||
break;
|
||||
default:
|
||||
valueArray.push(defaultValue.value)
|
||||
break
|
||||
valueArray.push(defaultValue.value);
|
||||
break;
|
||||
}
|
||||
return valueArray.length > 0 ? valueArray.join('') : defaultValue.value
|
||||
})
|
||||
return valueArray.length > 0 ? valueArray.join('') : defaultValue.value;
|
||||
});
|
||||
// 指定值范围区间,介于最小值和最大值之间
|
||||
const specifyRange = computed(() => {
|
||||
let range: number[] = []
|
||||
let range: number[] = [];
|
||||
if (maxValue.value != null) {
|
||||
for (let i = minValue.value; i <= maxValue.value; i++) {
|
||||
range.push(i)
|
||||
range.push(i);
|
||||
}
|
||||
}
|
||||
return range
|
||||
})
|
||||
return range;
|
||||
});
|
||||
|
||||
watch(() => props.value, (val) => {
|
||||
if (val !== computeValue.value) {
|
||||
parseValue(val)
|
||||
}
|
||||
}, { immediate: true })
|
||||
watch(
|
||||
() => props.value,
|
||||
(val) => {
|
||||
if (val !== computeValue.value) {
|
||||
parseValue(val);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(computeValue, (v) => updateValue(v))
|
||||
watch(computeValue, (v) => updateValue(v));
|
||||
|
||||
function updateValue(value) {
|
||||
emit('change', value)
|
||||
emit('update:value', value)
|
||||
emit('change', value);
|
||||
emit('update:value', value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,71 +111,72 @@ export function useTabSetup(props, context, options) {
|
|||
*/
|
||||
function parseValue(value) {
|
||||
if (value === computeValue.value) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (!value || value === defaultValue.value) {
|
||||
type.value = TypeEnum.every
|
||||
type.value = TypeEnum.every;
|
||||
} else if (value.indexOf('?') >= 0) {
|
||||
type.value = TypeEnum.unset
|
||||
type.value = TypeEnum.unset;
|
||||
} else if (value.indexOf('-') >= 0) {
|
||||
type.value = TypeEnum.range
|
||||
const values = value.split('-')
|
||||
type.value = TypeEnum.range;
|
||||
const values = value.split('-');
|
||||
if (values.length >= 2) {
|
||||
valueRange.start = parseInt(values[0])
|
||||
valueRange.end = parseInt(values[1])
|
||||
valueRange.start = parseInt(values[0]);
|
||||
valueRange.end = parseInt(values[1]);
|
||||
}
|
||||
} else if (value.indexOf('/') >= 0) {
|
||||
type.value = TypeEnum.loop
|
||||
const values = value.split('/')
|
||||
type.value = TypeEnum.loop;
|
||||
const values = value.split('/');
|
||||
if (values.length >= 2) {
|
||||
valueLoop.start = value[0] === '*' ? 0 : parseInt(values[0])
|
||||
valueLoop.interval = parseInt(values[1])
|
||||
valueLoop.start = value[0] === '*' ? 0 : parseInt(values[0]);
|
||||
valueLoop.interval = parseInt(values[1]);
|
||||
}
|
||||
} else if (value.indexOf('W') >= 0) {
|
||||
type.value = TypeEnum.work
|
||||
const values = value.split('W')
|
||||
type.value = TypeEnum.work;
|
||||
const values = value.split('W');
|
||||
if (!values[0] && !isNaN(values[0])) {
|
||||
valueWork.value = parseInt(values[0])
|
||||
valueWork.value = parseInt(values[0]);
|
||||
}
|
||||
} else if (value.indexOf('L') >= 0) {
|
||||
type.value = TypeEnum.last
|
||||
type.value = TypeEnum.last;
|
||||
} else if (value.indexOf(',') >= 0 || !isNaN(value)) {
|
||||
type.value = TypeEnum.specify
|
||||
valueList.value = value.split(',').map(item => parseInt(item))
|
||||
type.value = TypeEnum.specify;
|
||||
valueList.value = value.split(',').map((item) => parseInt(item));
|
||||
} else {
|
||||
type.value = TypeEnum.every
|
||||
type.value = TypeEnum.every;
|
||||
}
|
||||
} catch (e) {
|
||||
type.value = TypeEnum.every
|
||||
type.value = TypeEnum.every;
|
||||
}
|
||||
}
|
||||
|
||||
const beforeRadioAttrs = computed(() => ({
|
||||
class: ['choice'],
|
||||
disabled: props.disabled || unref(options.disabled),
|
||||
}))
|
||||
}));
|
||||
const inputNumberAttrs = computed(() => ({
|
||||
class: ['w60'],
|
||||
max: maxValue.value,
|
||||
min: minValue.value,
|
||||
precision: 0,
|
||||
}))
|
||||
}));
|
||||
const typeRangeAttrs = computed(() => ({
|
||||
disabled: type.value !== TypeEnum.range || props.disabled || unref(options.disabled),
|
||||
...inputNumberAttrs.value,
|
||||
}))
|
||||
}));
|
||||
const typeLoopAttrs = computed(() => ({
|
||||
disabled: type.value !== TypeEnum.loop || props.disabled || unref(options.disabled),
|
||||
...inputNumberAttrs.value,
|
||||
}))
|
||||
}));
|
||||
const typeSpecifyAttrs = computed(() => ({
|
||||
disabled: type.value !== TypeEnum.specify || props.disabled || unref(options.disabled),
|
||||
class: ['list-check-item'],
|
||||
}))
|
||||
}));
|
||||
|
||||
return {
|
||||
type, TypeEnum,
|
||||
type,
|
||||
TypeEnum,
|
||||
prefixCls,
|
||||
defaultValue,
|
||||
valueRange,
|
||||
|
@ -190,5 +195,5 @@ export function useTabSetup(props, context, options) {
|
|||
typeRangeAttrs,
|
||||
typeLoopAttrs,
|
||||
typeSpecifyAttrs,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,48 +1,48 @@
|
|||
import CronParser from 'cron-parser'
|
||||
import type { ValidatorRule } from 'ant-design-vue/lib/form/interface'
|
||||
import CronParser from 'cron-parser';
|
||||
import type { ValidatorRule } from 'ant-design-vue/lib/form/interface';
|
||||
|
||||
const cronRule: ValidatorRule = {
|
||||
validator({}, value) {
|
||||
// 没填写就不校验
|
||||
if (!value) {
|
||||
return Promise.resolve()
|
||||
return Promise.resolve();
|
||||
}
|
||||
const values: string[] = value.split(' ').filter(item => !!item)
|
||||
const values: string[] = value.split(' ').filter((item) => !!item);
|
||||
if (values.length > 7) {
|
||||
return Promise.reject('Cron表达式最多7项!')
|
||||
return Promise.reject('Cron表达式最多7项!');
|
||||
}
|
||||
// 检查第7项
|
||||
let val: string = value
|
||||
let val: string = value;
|
||||
if (values.length === 7) {
|
||||
const year = values[6]
|
||||
const year = values[6];
|
||||
if (year !== '*' && year !== '?') {
|
||||
let yearValues: string[] = []
|
||||
let yearValues: string[] = [];
|
||||
if (year.indexOf('-') >= 0) {
|
||||
yearValues = year.split('-')
|
||||
yearValues = year.split('-');
|
||||
} else if (year.indexOf('/')) {
|
||||
yearValues = year.split('/')
|
||||
yearValues = year.split('/');
|
||||
} else {
|
||||
yearValues = [year]
|
||||
yearValues = [year];
|
||||
}
|
||||
// 判断是否都是数字
|
||||
const checkYear = yearValues.some(item => isNaN(Number(item)))
|
||||
const checkYear = yearValues.some((item) => isNaN(Number(item)));
|
||||
if (checkYear) {
|
||||
return Promise.reject('Cron表达式参数[年]错误:' + year)
|
||||
return Promise.reject('Cron表达式参数[年]错误:' + year);
|
||||
}
|
||||
}
|
||||
// 取其中的前六项
|
||||
val = values.slice(0, 6).join(' ')
|
||||
val = values.slice(0, 6).join(' ');
|
||||
}
|
||||
// 6位 没有年
|
||||
// 5位没有秒、年
|
||||
try {
|
||||
const iter = CronParser.parseExpression(val)
|
||||
iter.next()
|
||||
return Promise.resolve()
|
||||
const iter = CronParser.parseExpression(val);
|
||||
iter.next();
|
||||
return Promise.resolve();
|
||||
} catch (e) {
|
||||
return Promise.reject('Cron表达式错误:' + e)
|
||||
return Promise.reject('Cron表达式错误:' + e);
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
export default cronRule.validator
|
||||
export default cronRule.validator;
|
||||
|
|
|
@ -1,40 +1,39 @@
|
|||
<template>
|
||||
<Tinymce v-bind="bindProps" @change="onChange"/>
|
||||
<Tinymce v-bind="bindProps" @change="onChange" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import { computed, defineComponent } from 'vue';
|
||||
|
||||
import { Tinymce } from '/@/components/Tinymce'
|
||||
import { propTypes } from '/@/utils/propTypes'
|
||||
import { Tinymce } from '/@/components/Tinymce';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JEditor',
|
||||
// 不将 attrs 的属性绑定到 html 标签上
|
||||
inheritAttrs: false,
|
||||
components: { Tinymce },
|
||||
props: {
|
||||
value: propTypes.string.def(''),
|
||||
disabled: propTypes.bool.def(false),
|
||||
},
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, { emit, attrs }) {
|
||||
// 合并 props 和 attrs
|
||||
const bindProps = computed(() => Object.assign({}, props, attrs))
|
||||
export default defineComponent({
|
||||
name: 'JEditor',
|
||||
// 不将 attrs 的属性绑定到 html 标签上
|
||||
inheritAttrs: false,
|
||||
components: { Tinymce },
|
||||
props: {
|
||||
value: propTypes.string.def(''),
|
||||
disabled: propTypes.bool.def(false),
|
||||
},
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, { emit, attrs }) {
|
||||
// 合并 props 和 attrs
|
||||
const bindProps = computed(() => Object.assign({}, props, attrs));
|
||||
|
||||
// value change 事件
|
||||
function onChange(value) {
|
||||
emit('change', value)
|
||||
emit('update:value', value)
|
||||
}
|
||||
// value change 事件
|
||||
function onChange(value) {
|
||||
emit('change', value);
|
||||
emit('update:value', value);
|
||||
}
|
||||
|
||||
return {
|
||||
bindProps,
|
||||
onChange,
|
||||
}
|
||||
},
|
||||
})
|
||||
return {
|
||||
bindProps,
|
||||
onChange,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
<template>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
<span>{{value}}</span>
|
||||
</template>
|
||||
{{ showText }}
|
||||
</a-tooltip>
|
||||
<a-tooltip placement="topLeft">
|
||||
<template #title>
|
||||
<span>{{ value }}</span>
|
||||
</template>
|
||||
{{ showText }}
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {computed} from 'vue';
|
||||
import {propTypes} from "/@/utils/propTypes";
|
||||
|
||||
const props = defineProps({
|
||||
value: propTypes.string.def(''),
|
||||
length: propTypes.number.def(25),
|
||||
});
|
||||
//显示的文本
|
||||
const showText = computed(() => props.value ? (props.value.length > props.length ? props.value.slice(0, props.length) + '...' : props.value) : props.value);
|
||||
import { computed } from 'vue';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
const props = defineProps({
|
||||
value: propTypes.string.def(''),
|
||||
length: propTypes.number.def(25),
|
||||
});
|
||||
//显示的文本
|
||||
const showText = computed(() => (props.value ? (props.value.length > props.length ? props.value.slice(0, props.length) + '...' : props.value) : props.value));
|
||||
</script>
|
||||
|
|
|
@ -1,32 +1,33 @@
|
|||
<template>
|
||||
<div class="clearfix">
|
||||
<a-upload
|
||||
:listType="listType"
|
||||
:multiple="multiple"
|
||||
:action="uploadUrl"
|
||||
:headers="headers"
|
||||
:data="{biz:bizPath}"
|
||||
v-model:fileList="uploadFileList"
|
||||
:beforeUpload="beforeUpload"
|
||||
:disabled="disabled"
|
||||
@change="handleChange"
|
||||
@preview="handlePreview">
|
||||
<div v-if="uploadVisible">
|
||||
<div v-if="listType=='picture-card'">
|
||||
<LoadingOutlined v-if="loading"/>
|
||||
<UploadOutlined v-else/>
|
||||
<div class="ant-upload-text">{{ text }}</div>
|
||||
</div>
|
||||
<a-button v-if="listType=='picture'">
|
||||
<UploadOutlined></UploadOutlined>
|
||||
{{ text }}
|
||||
</a-button>
|
||||
</div>
|
||||
</a-upload>
|
||||
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()">
|
||||
<img alt="example" style="width: 100%" :src="previewImage"/>
|
||||
</a-modal>
|
||||
</div>
|
||||
<div class="clearfix">
|
||||
<a-upload
|
||||
:listType="listType"
|
||||
:multiple="multiple"
|
||||
:action="uploadUrl"
|
||||
:headers="headers"
|
||||
:data="{ biz: bizPath }"
|
||||
v-model:fileList="uploadFileList"
|
||||
:beforeUpload="beforeUpload"
|
||||
:disabled="disabled"
|
||||
@change="handleChange"
|
||||
@preview="handlePreview"
|
||||
>
|
||||
<div v-if="uploadVisible">
|
||||
<div v-if="listType == 'picture-card'">
|
||||
<LoadingOutlined v-if="loading" />
|
||||
<UploadOutlined v-else />
|
||||
<div class="ant-upload-text">{{ text }}</div>
|
||||
</div>
|
||||
<a-button v-if="listType == 'picture'">
|
||||
<UploadOutlined></UploadOutlined>
|
||||
{{ text }}
|
||||
</a-button>
|
||||
</div>
|
||||
</a-upload>
|
||||
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()">
|
||||
<img alt="example" style="width: 100%" :src="previewImage" />
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, reactive, watchEffect, computed, unref, watch, onMounted } from 'vue';
|
||||
|
@ -46,10 +47,7 @@
|
|||
inheritAttrs: false,
|
||||
props: {
|
||||
//绑定值
|
||||
value: propTypes.oneOfType([
|
||||
propTypes.string,
|
||||
propTypes.array,
|
||||
]),
|
||||
value: propTypes.oneOfType([propTypes.string, propTypes.array]),
|
||||
//按钮文本
|
||||
listType: {
|
||||
type: String,
|
||||
|
@ -81,7 +79,7 @@
|
|||
default: 1,
|
||||
},
|
||||
},
|
||||
emits: ['options-change', 'change','update:value'],
|
||||
emits: ['options-change', 'change', 'update:value'],
|
||||
setup(props, { emit, refs }) {
|
||||
const emitData = ref<any[]>([]);
|
||||
const attrs = useAttrs();
|
||||
|
@ -114,7 +112,6 @@
|
|||
return props['fileMax'] > 1;
|
||||
});
|
||||
|
||||
|
||||
//计算是否可以继续上传
|
||||
const uploadVisible = computed(() => {
|
||||
return uploadFileList.value.length < props['fileMax'];
|
||||
|
@ -132,7 +129,7 @@
|
|||
if (initTag.value == true) {
|
||||
initFileList(val);
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -194,7 +191,7 @@
|
|||
}
|
||||
emitData.value = fileUrls.join(',');
|
||||
state.value = fileUrls.join(',');
|
||||
emit('update:value',fileUrls.join(','))
|
||||
emit('update:value', fileUrls.join(','));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -244,13 +241,13 @@
|
|||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.ant-upload-select-picture-card i {
|
||||
font-size: 32px;
|
||||
color: #999;
|
||||
}
|
||||
.ant-upload-select-picture-card i {
|
||||
font-size: 32px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.ant-upload-select-picture-card .ant-upload-text {
|
||||
margin-top: 8px;
|
||||
color: #666;
|
||||
}
|
||||
.ant-upload-select-picture-card .ant-upload-text {
|
||||
margin-top: 8px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,179 +1,179 @@
|
|||
<template>
|
||||
<div>
|
||||
<BasicModal v-bind="$attrs" @register="register" title="导入EXCEL" :width="600" @cancel="handleClose" :confirmLoading="uploading" destroyOnClose>
|
||||
<!--是否校验-->
|
||||
<div style="margin: 0 5px 1px" v-if="online">
|
||||
<span style="display: inline-block;height: 32px;line-height: 32px;vertical-align: middle;">是否开启校验:</span>
|
||||
<span style="margin-left: 6px">
|
||||
<a-switch :checked="validateStatus==1" @change="handleChangeValidateStatus" checked-children="是" un-checked-children="否" size="small"/>
|
||||
</span>
|
||||
</div>
|
||||
<!--上传-->
|
||||
<a-upload name="file" accept=".xls,.xlsx" :multiple="true" :fileList="fileList" :remove="handleRemove" :beforeUpload="beforeUpload">
|
||||
<a-button preIcon="ant-design:upload-outlined">选择导入文件</a-button>
|
||||
</a-upload>
|
||||
<!--页脚-->
|
||||
<template #footer>
|
||||
<a-button @click="handleClose">关闭</a-button>
|
||||
<a-button type="primary" @click="handleImport" :disabled="uploadDisabled" :loading="uploading">{{ uploading ? '上传中...' : '开始上传' }}</a-button>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</div>
|
||||
<div>
|
||||
<BasicModal v-bind="$attrs" @register="register" title="导入EXCEL" :width="600" @cancel="handleClose" :confirmLoading="uploading" destroyOnClose>
|
||||
<!--是否校验-->
|
||||
<div style="margin: 0 5px 1px" v-if="online">
|
||||
<span style="display: inline-block; height: 32px; line-height: 32px; vertical-align: middle">是否开启校验:</span>
|
||||
<span style="margin-left: 6px">
|
||||
<a-switch :checked="validateStatus == 1" @change="handleChangeValidateStatus" checked-children="是" un-checked-children="否" size="small" />
|
||||
</span>
|
||||
</div>
|
||||
<!--上传-->
|
||||
<a-upload name="file" accept=".xls,.xlsx" :multiple="true" :fileList="fileList" :remove="handleRemove" :beforeUpload="beforeUpload">
|
||||
<a-button preIcon="ant-design:upload-outlined">选择导入文件</a-button>
|
||||
</a-upload>
|
||||
<!--页脚-->
|
||||
<template #footer>
|
||||
<a-button @click="handleClose">关闭</a-button>
|
||||
<a-button type="primary" @click="handleImport" :disabled="uploadDisabled" :loading="uploading">{{ uploading ? '上传中...' : '开始上传' }}</a-button>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent, ref, unref, watchEffect, computed} from 'vue';
|
||||
import {BasicModal, useModalInner} from '/@/components/Modal';
|
||||
import {useAttrs} from '/@/hooks/core/useAttrs';
|
||||
import {defHttp} from '/@/utils/http/axios';
|
||||
import {useGlobSetting} from '/@/hooks/setting';
|
||||
import {useMessage} from '/@/hooks/web/useMessage';
|
||||
import { defineComponent, ref, unref, watchEffect, computed } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useGlobSetting } from '/@/hooks/setting';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JImportModal',
|
||||
components: {
|
||||
BasicModal,
|
||||
},
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false
|
||||
},
|
||||
biz: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false
|
||||
},
|
||||
//是否online导入
|
||||
online: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
export default defineComponent({
|
||||
name: 'JImportModal',
|
||||
components: {
|
||||
BasicModal,
|
||||
},
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false,
|
||||
},
|
||||
biz: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: false,
|
||||
},
|
||||
//是否online导入
|
||||
online: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
emits: ['ok', 'register'],
|
||||
setup(props, { emit, refs }) {
|
||||
const { createMessage, createWarningModal } = useMessage();
|
||||
//注册弹框
|
||||
const [register, { closeModal }] = useModalInner((data) => {
|
||||
reset(data);
|
||||
});
|
||||
const glob = useGlobSetting();
|
||||
const attrs = useAttrs();
|
||||
const uploading = ref(false);
|
||||
//文件集合
|
||||
const fileList = ref([]);
|
||||
//上传url
|
||||
const uploadAction = ref('');
|
||||
const foreignKeys = ref('');
|
||||
//校验状态
|
||||
const validateStatus = ref(0);
|
||||
const getBindValue = Object.assign({}, unref(props), unref(attrs));
|
||||
//监听url
|
||||
watchEffect(() => {
|
||||
props.url && (uploadAction.value = `${glob.uploadUrl}${props.url}`);
|
||||
});
|
||||
//按钮disabled状态
|
||||
const uploadDisabled = computed(() => !(unref(fileList).length > 0));
|
||||
|
||||
//关闭方法
|
||||
function handleClose() {
|
||||
closeModal() && reset();
|
||||
}
|
||||
|
||||
//校验状态切换
|
||||
function handleChangeValidateStatus(checked) {
|
||||
validateStatus.value = !!checked ? 1 : 0;
|
||||
}
|
||||
|
||||
//移除上传文件
|
||||
function handleRemove(file) {
|
||||
const index = unref(fileList).indexOf(file);
|
||||
const newFileList = unref(fileList).slice();
|
||||
newFileList.splice(index, 1);
|
||||
fileList.value = newFileList;
|
||||
}
|
||||
|
||||
//上传前处理
|
||||
function beforeUpload(file) {
|
||||
fileList.value = [...unref(fileList), file];
|
||||
return false;
|
||||
}
|
||||
|
||||
//文件上传
|
||||
function handleImport() {
|
||||
let { biz, online } = props;
|
||||
const formData = new FormData();
|
||||
if (biz) {
|
||||
formData.append('isSingleTableImport', biz);
|
||||
}
|
||||
if (unref(foreignKeys) && unref(foreignKeys).length > 0) {
|
||||
formData.append('foreignKeys', unref(foreignKeys));
|
||||
}
|
||||
if (!!online) {
|
||||
formData.append('validateStatus', unref(validateStatus));
|
||||
}
|
||||
unref(fileList).forEach((file) => {
|
||||
formData.append('files[]', file);
|
||||
});
|
||||
uploading.value = true;
|
||||
|
||||
//TODO 请求怎样处理的问题
|
||||
let headers = {
|
||||
'Content-Type': 'multipart/form-data;boundary = ' + new Date().getTime(),
|
||||
};
|
||||
defHttp.post({ url: props.url, params: formData, headers }, { isTransformResponse: false }).then((res) => {
|
||||
uploading.value = false;
|
||||
if (res.success) {
|
||||
if (res.code == 201) {
|
||||
errorTip(res.message, res.result);
|
||||
} else {
|
||||
createMessage.success(res.message);
|
||||
}
|
||||
},
|
||||
emits: ['ok','register'],
|
||||
setup(props, {emit, refs}) {
|
||||
const {createMessage, createWarningModal} = useMessage();
|
||||
//注册弹框
|
||||
const [register, {closeModal}] = useModalInner((data) => {
|
||||
reset(data);
|
||||
});
|
||||
const glob = useGlobSetting();
|
||||
const attrs = useAttrs();
|
||||
const uploading = ref(false);
|
||||
//文件集合
|
||||
const fileList = ref([]);
|
||||
//上传url
|
||||
const uploadAction = ref('');
|
||||
const foreignKeys = ref('');
|
||||
//校验状态
|
||||
const validateStatus = ref(0);
|
||||
const getBindValue = Object.assign({}, unref(props), unref(attrs));
|
||||
//监听url
|
||||
watchEffect(() => {
|
||||
props.url && (uploadAction.value = `${glob.uploadUrl}${props.url}`);
|
||||
});
|
||||
//按钮disabled状态
|
||||
const uploadDisabled = computed(() => !(unref(fileList).length > 0));
|
||||
handleClose();
|
||||
reset();
|
||||
emit('ok');
|
||||
} else {
|
||||
createMessage.warning(res.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//关闭方法
|
||||
function handleClose() {
|
||||
closeModal() && reset()
|
||||
}
|
||||
|
||||
//校验状态切换
|
||||
function handleChangeValidateStatus(checked) {
|
||||
validateStatus.value = !!checked ? 1 : 0;
|
||||
}
|
||||
|
||||
//移除上传文件
|
||||
function handleRemove(file) {
|
||||
const index = unref(fileList).indexOf(file);
|
||||
const newFileList = unref(fileList).slice();
|
||||
newFileList.splice(index, 1);
|
||||
fileList.value = newFileList
|
||||
}
|
||||
|
||||
//上传前处理
|
||||
function beforeUpload(file) {
|
||||
fileList.value = [...unref(fileList), file];
|
||||
return false;
|
||||
}
|
||||
|
||||
//文件上传
|
||||
function handleImport() {
|
||||
let {biz, online} = props;
|
||||
const formData = new FormData();
|
||||
if (biz) {
|
||||
formData.append('isSingleTableImport', biz);
|
||||
}
|
||||
if (unref(foreignKeys) && unref(foreignKeys).length > 0) {
|
||||
formData.append('foreignKeys', unref(foreignKeys));
|
||||
}
|
||||
if (!!online) {
|
||||
formData.append('validateStatus', unref(validateStatus));
|
||||
}
|
||||
unref(fileList).forEach((file) => {
|
||||
formData.append('files[]', file);
|
||||
});
|
||||
uploading.value = true;
|
||||
|
||||
//TODO 请求怎样处理的问题
|
||||
let headers={
|
||||
'Content-Type': 'multipart/form-data;boundary = ' + new Date().getTime()
|
||||
}
|
||||
defHttp.post({url: props.url,params:formData,headers},{isTransformResponse:false}).then((res) => {
|
||||
uploading.value = false;
|
||||
if (res.success) {
|
||||
if (res.code == 201) {
|
||||
errorTip(res.message, res.result)
|
||||
} else {
|
||||
createMessage.success(res.message)
|
||||
}
|
||||
handleClose();
|
||||
reset();
|
||||
emit('ok')
|
||||
} else {
|
||||
createMessage.warning(res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//错误信息提示
|
||||
function errorTip(tipMessage, fileUrl) {
|
||||
let href = glob.uploadUrl + fileUrl;
|
||||
createWarningModal({
|
||||
title: '导入成功,但是有错误数据!',
|
||||
centered: false,
|
||||
content: `<div>
|
||||
//错误信息提示
|
||||
function errorTip(tipMessage, fileUrl) {
|
||||
let href = glob.uploadUrl + fileUrl;
|
||||
createWarningModal({
|
||||
title: '导入成功,但是有错误数据!',
|
||||
centered: false,
|
||||
content: `<div>
|
||||
<span>${tipMessage}</span><br/>
|
||||
<span>具体详情请<a href = ${href} target="_blank"> 点击下载 </a> </span>
|
||||
</div>`
|
||||
})
|
||||
}
|
||||
</div>`,
|
||||
});
|
||||
}
|
||||
|
||||
//重置
|
||||
function reset(arg?) {
|
||||
fileList.value = [];
|
||||
uploading.value = false;
|
||||
foreignKeys.value = arg;
|
||||
validateStatus.value = 0
|
||||
}
|
||||
//重置
|
||||
function reset(arg?) {
|
||||
fileList.value = [];
|
||||
uploading.value = false;
|
||||
foreignKeys.value = arg;
|
||||
validateStatus.value = 0;
|
||||
}
|
||||
|
||||
return {
|
||||
register,
|
||||
getBindValue,
|
||||
uploadDisabled,
|
||||
fileList,
|
||||
uploading,
|
||||
validateStatus,
|
||||
handleClose,
|
||||
handleChangeValidateStatus,
|
||||
handleRemove,
|
||||
beforeUpload,
|
||||
handleImport,
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
register,
|
||||
getBindValue,
|
||||
uploadDisabled,
|
||||
fileList,
|
||||
uploading,
|
||||
validateStatus,
|
||||
handleClose,
|
||||
handleChangeValidateStatus,
|
||||
handleRemove,
|
||||
beforeUpload,
|
||||
handleImport,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,107 +1,105 @@
|
|||
<template>
|
||||
<a-input v-bind="getBindValue" v-model:value="showText" @input="backValue"></a-input>
|
||||
<a-input v-bind="getBindValue" v-model:value="showText" @input="backValue"></a-input>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {defineComponent, PropType, ref, watchEffect, unref, watch} from 'vue';
|
||||
import {useAttrs} from '/@/hooks/core/useAttrs';
|
||||
import {propTypes} from '/@/utils/propTypes';
|
||||
import {JInputTypeEnum} from '/@/enums/jeecgEnum.ts';
|
||||
import { defineComponent, PropType, ref, watchEffect, unref, watch } from 'vue';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { JInputTypeEnum } from '/@/enums/jeecgEnum.ts';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JInput',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: propTypes.string.def(''),
|
||||
type: propTypes.string.def(JInputTypeEnum.JINPUT_QUERY_LIKE),
|
||||
placeholder: propTypes.string.def(''),
|
||||
trim: propTypes.bool.def(false),
|
||||
export default defineComponent({
|
||||
name: 'JInput',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: propTypes.string.def(''),
|
||||
type: propTypes.string.def(JInputTypeEnum.JINPUT_QUERY_LIKE),
|
||||
placeholder: propTypes.string.def(''),
|
||||
trim: propTypes.bool.def(false),
|
||||
},
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, { emit }) {
|
||||
const attrs = useAttrs();
|
||||
//表单值
|
||||
const showText = ref('');
|
||||
//绑定属性
|
||||
const getBindValue = Object.assign({}, unref(props), unref(attrs));
|
||||
//监听类型变化
|
||||
watch(
|
||||
() => props.type,
|
||||
(val) => {
|
||||
val && backValue({ target: { value: unref(showText) } });
|
||||
}
|
||||
);
|
||||
//监听value变化
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
initVal();
|
||||
},
|
||||
emits: ['change','update:value'],
|
||||
setup(props, {emit}) {
|
||||
const attrs = useAttrs();
|
||||
//表单值
|
||||
const showText = ref('');
|
||||
//绑定属性
|
||||
const getBindValue = Object.assign({}, unref(props), unref(attrs));
|
||||
//监听类型变化
|
||||
watch(
|
||||
() => props.type,
|
||||
(val) => {
|
||||
val && backValue({target: {value: unref(showText)}});
|
||||
}
|
||||
);
|
||||
//监听value变化
|
||||
watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
initVal();
|
||||
},
|
||||
{immediate: true}
|
||||
);
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* 初始化数值
|
||||
*/
|
||||
function initVal() {
|
||||
if (!props.value) {
|
||||
showText.value = ''
|
||||
} else {
|
||||
let text = props.value;
|
||||
switch (props.type) {
|
||||
case JInputTypeEnum.JINPUT_QUERY_LIKE:
|
||||
//修复路由传参的值传送到jinput框被前后各截取了一位 #1336
|
||||
if (text.indexOf("*") != -1) {
|
||||
text = text.substring(1, text.length - 1);
|
||||
}
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_NE:
|
||||
text = text.substring(1);
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_GE:
|
||||
text = text.substring(2);
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_LE:
|
||||
text = text.substring(2);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
showText.value = text
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 初始化数值
|
||||
*/
|
||||
function initVal() {
|
||||
if (!props.value) {
|
||||
showText.value = '';
|
||||
} else {
|
||||
let text = props.value;
|
||||
switch (props.type) {
|
||||
case JInputTypeEnum.JINPUT_QUERY_LIKE:
|
||||
//修复路由传参的值传送到jinput框被前后各截取了一位 #1336
|
||||
if (text.indexOf('*') != -1) {
|
||||
text = text.substring(1, text.length - 1);
|
||||
}
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_NE:
|
||||
text = text.substring(1);
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_GE:
|
||||
text = text.substring(2);
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_LE:
|
||||
text = text.substring(2);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
showText.value = text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回值
|
||||
*/
|
||||
function backValue(e) {
|
||||
let text = e?.target?.value??'';
|
||||
if (text && !!props.trim) {
|
||||
text = text.trim()
|
||||
}
|
||||
switch (props.type) {
|
||||
case JInputTypeEnum.JINPUT_QUERY_LIKE:
|
||||
text = "*" + text + "*";
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_NE:
|
||||
text = "!" + text;
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_GE:
|
||||
text = ">=" + text;
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_LE:
|
||||
text = "<=" + text;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
emit("change", text)
|
||||
emit("update:value", text)
|
||||
}
|
||||
/**
|
||||
* 返回值
|
||||
*/
|
||||
function backValue(e) {
|
||||
let text = e?.target?.value ?? '';
|
||||
if (text && !!props.trim) {
|
||||
text = text.trim();
|
||||
}
|
||||
switch (props.type) {
|
||||
case JInputTypeEnum.JINPUT_QUERY_LIKE:
|
||||
text = '*' + text + '*';
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_NE:
|
||||
text = '!' + text;
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_GE:
|
||||
text = '>=' + text;
|
||||
break;
|
||||
case JInputTypeEnum.JINPUT_QUERY_LE:
|
||||
text = '<=' + text;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
emit('change', text);
|
||||
emit('update:value', text);
|
||||
}
|
||||
|
||||
return {showText, attrs, getBindValue, backValue};
|
||||
},
|
||||
});
|
||||
return { showText, attrs, getBindValue, backValue };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,122 +1,109 @@
|
|||
<template>
|
||||
<a-popover
|
||||
trigger="contextmenu"
|
||||
v-model:visible="visible"
|
||||
:overlayClassName="`${prefixCls}-popover`"
|
||||
:getPopupContainer="getPopupContainer"
|
||||
:placement="position">
|
||||
<a-popover trigger="contextmenu" v-model:visible="visible" :overlayClassName="`${prefixCls}-popover`" :getPopupContainer="getPopupContainer" :placement="position">
|
||||
<template #title>
|
||||
<span>{{ title }}</span>
|
||||
<span style="float: right" title="关闭">
|
||||
<Icon icon="ant-design:close-outlined" @click="visible = false"/>
|
||||
<Icon icon="ant-design:close-outlined" @click="visible = false" />
|
||||
</span>
|
||||
</template>
|
||||
<template #content>
|
||||
<a-textarea
|
||||
ref="textareaRef"
|
||||
:value="innerValue"
|
||||
:disabled="disabled"
|
||||
:style="textareaStyle"
|
||||
v-bind="attrs"
|
||||
@input="onInputChange"/>
|
||||
<a-textarea ref="textareaRef" :value="innerValue" :disabled="disabled" :style="textareaStyle" v-bind="attrs" @input="onInputChange" />
|
||||
</template>
|
||||
<a-input
|
||||
:class="`${prefixCls}-input`"
|
||||
:value="innerValue"
|
||||
:disabled="disabled"
|
||||
v-bind="attrs"
|
||||
@change="onInputChange">
|
||||
<a-input :class="`${prefixCls}-input`" :value="innerValue" :disabled="disabled" v-bind="attrs" @change="onInputChange">
|
||||
<template #suffix>
|
||||
<Icon icon="ant-design:fullscreen-outlined" @click.stop="onShowPopup"/>
|
||||
<Icon icon="ant-design:fullscreen-outlined" @click.stop="onShowPopup" />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
import Icon from '/@/components/Icon/src/Icon.vue'
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs'
|
||||
import { propTypes } from '/@/utils/propTypes'
|
||||
import { useDesign } from '/@/hooks/web/useDesign'
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
import Icon from '/@/components/Icon/src/Icon.vue';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
const { prefixCls } = useDesign('j-input-popup')
|
||||
const props = defineProps({
|
||||
// v-model:value
|
||||
value: propTypes.string.def(''),
|
||||
title: propTypes.string.def(''),
|
||||
// 弹出框显示位置
|
||||
position: propTypes.string.def('right'),
|
||||
width: propTypes.number.def(300),
|
||||
height: propTypes.number.def(150),
|
||||
disabled: propTypes.bool.def(false),
|
||||
// 弹出框挂载的元素ID
|
||||
popContainer: propTypes.string.def(''),
|
||||
})
|
||||
const attrs = useAttrs()
|
||||
const emit = defineEmits(['change', 'update:value'])
|
||||
const { prefixCls } = useDesign('j-input-popup');
|
||||
const props = defineProps({
|
||||
// v-model:value
|
||||
value: propTypes.string.def(''),
|
||||
title: propTypes.string.def(''),
|
||||
// 弹出框显示位置
|
||||
position: propTypes.string.def('right'),
|
||||
width: propTypes.number.def(300),
|
||||
height: propTypes.number.def(150),
|
||||
disabled: propTypes.bool.def(false),
|
||||
// 弹出框挂载的元素ID
|
||||
popContainer: propTypes.string.def(''),
|
||||
});
|
||||
const attrs = useAttrs();
|
||||
const emit = defineEmits(['change', 'update:value']);
|
||||
|
||||
const visible = ref<boolean>(false)
|
||||
const innerValue = ref<string>('')
|
||||
// textarea ref对象
|
||||
const textareaRef = ref()
|
||||
// textarea 样式
|
||||
const textareaStyle = computed(() => ({
|
||||
height: `${props.height}px`,
|
||||
width: `${props.width}px`,
|
||||
}))
|
||||
const visible = ref<boolean>(false);
|
||||
const innerValue = ref<string>('');
|
||||
// textarea ref对象
|
||||
const textareaRef = ref();
|
||||
// textarea 样式
|
||||
const textareaStyle = computed(() => ({
|
||||
height: `${props.height}px`,
|
||||
width: `${props.width}px`,
|
||||
}));
|
||||
|
||||
watch(() => props.value, (value) => {
|
||||
if (value && value.length > 0) {
|
||||
innerValue.value = value
|
||||
watch(
|
||||
() => props.value,
|
||||
(value) => {
|
||||
if (value && value.length > 0) {
|
||||
innerValue.value = value;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
function onInputChange(event) {
|
||||
innerValue.value = event.target.value;
|
||||
emitValue(innerValue.value);
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
|
||||
function onInputChange(event) {
|
||||
innerValue.value = event.target.value
|
||||
emitValue(innerValue.value)
|
||||
}
|
||||
|
||||
async function onShowPopup() {
|
||||
visible.value = true
|
||||
await nextTick()
|
||||
textareaRef.value?.focus()
|
||||
}
|
||||
|
||||
// 获取弹出框挂载的元素
|
||||
function getPopupContainer(node) {
|
||||
if (!props.popContainer) {
|
||||
return node.parentNode
|
||||
} else {
|
||||
return document.getElementById(props.popContainer)
|
||||
async function onShowPopup() {
|
||||
visible.value = true;
|
||||
await nextTick();
|
||||
textareaRef.value?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function emitValue(value) {
|
||||
emit('change', value)
|
||||
emit('update:value', value)
|
||||
}
|
||||
// 获取弹出框挂载的元素
|
||||
function getPopupContainer(node) {
|
||||
if (!props.popContainer) {
|
||||
return node.parentNode;
|
||||
} else {
|
||||
return document.getElementById(props.popContainer);
|
||||
}
|
||||
}
|
||||
|
||||
function emitValue(value) {
|
||||
emit('change', value);
|
||||
emit('update:value', value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
//noinspection LessUnresolvedVariable
|
||||
@prefix-cls: ~'@{namespace}-j-input-popup';
|
||||
//noinspection LessUnresolvedVariable
|
||||
@prefix-cls: ~'@{namespace}-j-input-popup';
|
||||
|
||||
.@{prefix-cls} {
|
||||
&-popover {
|
||||
}
|
||||
.@{prefix-cls} {
|
||||
&-popover {
|
||||
}
|
||||
|
||||
&-input {
|
||||
.app-iconify {
|
||||
cursor: pointer;
|
||||
color: #666666;
|
||||
transition: color 0.3s;
|
||||
&-input {
|
||||
.app-iconify {
|
||||
cursor: pointer;
|
||||
color: #666666;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: black;
|
||||
&:hover {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
@ -1,54 +1,57 @@
|
|||
<template>
|
||||
<MarkDown v-bind="bindProps" @change="onChange" @get="onGetVditor"/>
|
||||
<MarkDown v-bind="bindProps" @change="onChange" @get="onGetVditor" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, watch } from 'vue'
|
||||
import { MarkDown } from '/@/components/Markdown'
|
||||
import { propTypes } from '/@/utils/propTypes'
|
||||
import { computed, defineComponent, watch } from 'vue';
|
||||
import { MarkDown } from '/@/components/Markdown';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JMarkdownEditor',
|
||||
// 不将 attrs 的属性绑定到 html 标签上
|
||||
inheritAttrs: false,
|
||||
components: { MarkDown },
|
||||
props: {
|
||||
value: propTypes.string.def(''),
|
||||
disabled: propTypes.bool.def(false),
|
||||
},
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, { emit, attrs }) {
|
||||
// markdown 组件实例
|
||||
let mdRef: any = null
|
||||
// vditor 组件实例
|
||||
let vditorRef: any = null
|
||||
// 合并 props 和 attrs
|
||||
const bindProps = computed(() => Object.assign({}, props, attrs))
|
||||
export default defineComponent({
|
||||
name: 'JMarkdownEditor',
|
||||
// 不将 attrs 的属性绑定到 html 标签上
|
||||
inheritAttrs: false,
|
||||
components: { MarkDown },
|
||||
props: {
|
||||
value: propTypes.string.def(''),
|
||||
disabled: propTypes.bool.def(false),
|
||||
},
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props, { emit, attrs }) {
|
||||
// markdown 组件实例
|
||||
let mdRef: any = null;
|
||||
// vditor 组件实例
|
||||
let vditorRef: any = null;
|
||||
// 合并 props 和 attrs
|
||||
const bindProps = computed(() => Object.assign({}, props, attrs));
|
||||
|
||||
// 相当于 onMounted
|
||||
function onGetVditor(instance) {
|
||||
mdRef = instance
|
||||
vditorRef = mdRef.getVditor()
|
||||
// 相当于 onMounted
|
||||
function onGetVditor(instance) {
|
||||
mdRef = instance;
|
||||
vditorRef = mdRef.getVditor();
|
||||
|
||||
// 监听禁用,切换编辑器禁用状态
|
||||
watch(() => props.disabled, disabled => disabled ? vditorRef.disabled() : vditorRef.enable(), { immediate: true })
|
||||
}
|
||||
// 监听禁用,切换编辑器禁用状态
|
||||
watch(
|
||||
() => props.disabled,
|
||||
(disabled) => (disabled ? vditorRef.disabled() : vditorRef.enable()),
|
||||
{ immediate: true }
|
||||
);
|
||||
}
|
||||
|
||||
// value change 事件
|
||||
function onChange(value) {
|
||||
emit('change', value)
|
||||
emit('update:value', value)
|
||||
}
|
||||
// value change 事件
|
||||
function onChange(value) {
|
||||
emit('change', value);
|
||||
emit('update:value', value);
|
||||
}
|
||||
|
||||
return {
|
||||
bindProps,
|
||||
return {
|
||||
bindProps,
|
||||
|
||||
onChange,
|
||||
onGetVditor,
|
||||
}
|
||||
},
|
||||
})
|
||||
onChange,
|
||||
onGetVditor,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
<style lang="less" scoped></style>
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
<template>
|
||||
<!-- 级联下拉框 form组件 暂且只在online使用 不对外提供api -->
|
||||
<a-select :placeholder="placeholder" :value="selectedValue" @change="handleChange" allowClear style="width:100%">
|
||||
<a-select-option v-for="(item, index) in dictOptions" :key="index" :value="item.store">
|
||||
<span style="display: inline-block;width: 100%" :title=" item.label ">{{ item.label }}</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<!-- 级联下拉框 form组件 暂且只在online使用 不对外提供api -->
|
||||
<a-select :placeholder="placeholder" :value="selectedValue" @change="handleChange" allowClear style="width: 100%">
|
||||
<a-select-option v-for="(item, index) in dictOptions" :key="index" :value="item.store">
|
||||
<span style="display: inline-block; width: 100%" :title="item.label">{{ item.label }}</span>
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, watch, ref } from 'vue';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
|
||||
/**获取下拉选项*/
|
||||
const SELECT_OPTIONS_URL = '/online/cgform/api/querySelectOptions';
|
||||
|
||||
|
||||
export default defineComponent({
|
||||
name: "JOnlineSelectCascade",
|
||||
props:{
|
||||
table:{ type: String, default: '' },
|
||||
name: 'JOnlineSelectCascade',
|
||||
props: {
|
||||
table: { type: String, default: '' },
|
||||
txt: { type: String, default: '' },
|
||||
store: { type: String, default: '' },
|
||||
idField: { type: String, default: '' },
|
||||
|
@ -26,188 +26,195 @@
|
|||
pidValue: { type: String, default: '-1' },
|
||||
origin: { type: Boolean, default: false },
|
||||
condition: { type: String, default: '' },
|
||||
value:{ type: String, default: '' },
|
||||
isNumber:{ type: Boolean, default: false },
|
||||
value: { type: String, default: '' },
|
||||
isNumber: { type: Boolean, default: false },
|
||||
placeholder: { type: String, default: '请选择' },
|
||||
},
|
||||
emits: [ 'change', 'next'],
|
||||
setup(props, { emit }){
|
||||
const { createMessage: $message } = useMessage()
|
||||
emits: ['change', 'next'],
|
||||
setup(props, { emit }) {
|
||||
const { createMessage: $message } = useMessage();
|
||||
// 选中值
|
||||
const selectedValue = ref<any>('');
|
||||
// 选项数组
|
||||
const dictOptions = ref<any[]>([])
|
||||
const optionsLoad = ref(true)
|
||||
const dictOptions = ref<any[]>([]);
|
||||
const optionsLoad = ref(true);
|
||||
// 选项改变事件
|
||||
function handleChange(value) {
|
||||
console.log('handleChange', value)
|
||||
console.log('handleChange', value);
|
||||
// 这个value是 存储的值 实际还需要获取id值
|
||||
let temp = value || ''
|
||||
emit('change', temp)
|
||||
valueChangeThenEmitNext(temp)
|
||||
let temp = value || '';
|
||||
emit('change', temp);
|
||||
valueChangeThenEmitNext(temp);
|
||||
}
|
||||
|
||||
// 第一个节点 选项加载走condition
|
||||
watch(()=>props.condition, (val)=>{
|
||||
optionsLoad.value = true;
|
||||
if(val){
|
||||
loadOptions();
|
||||
}
|
||||
}, {immediate:true});
|
||||
watch(
|
||||
() => props.condition,
|
||||
(val) => {
|
||||
optionsLoad.value = true;
|
||||
if (val) {
|
||||
loadOptions();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 被联动节点 选项加载走pidValue
|
||||
watch(()=>props.pidValue, (val)=>{
|
||||
if(val === '-1'){
|
||||
dictOptions.value = []
|
||||
}else{
|
||||
loadOptions();
|
||||
watch(
|
||||
() => props.pidValue,
|
||||
(val) => {
|
||||
if (val === '-1') {
|
||||
dictOptions.value = [];
|
||||
} else {
|
||||
loadOptions();
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
// 值回显
|
||||
watch(()=>props.value, (newVal, oldVal)=>{
|
||||
console.log('值改变事件', newVal, oldVal)
|
||||
if(!newVal){
|
||||
// value不存在的时候--
|
||||
selectedValue.value = []
|
||||
if(oldVal){
|
||||
// 如果oldVal存在, 需要往上抛事件
|
||||
emit('change', '')
|
||||
emit('next', '-1')
|
||||
watch(
|
||||
() => props.value,
|
||||
(newVal, oldVal) => {
|
||||
console.log('值改变事件', newVal, oldVal);
|
||||
if (!newVal) {
|
||||
// value不存在的时候--
|
||||
selectedValue.value = [];
|
||||
if (oldVal) {
|
||||
// 如果oldVal存在, 需要往上抛事件
|
||||
emit('change', '');
|
||||
emit('next', '-1');
|
||||
}
|
||||
} else {
|
||||
// value存在的时候
|
||||
selectedValue.value = newVal;
|
||||
}
|
||||
}else{
|
||||
// value存在的时候
|
||||
selectedValue.value = newVal
|
||||
}
|
||||
if(newVal && !oldVal){
|
||||
// 有新值没有旧值 表单第一次加载赋值 需要往外抛一个事件 触发下级options的加载
|
||||
handleFirstValueSetting(newVal)
|
||||
}
|
||||
}, {immediate:true});
|
||||
|
||||
if (newVal && !oldVal) {
|
||||
// 有新值没有旧值 表单第一次加载赋值 需要往外抛一个事件 触发下级options的加载
|
||||
handleFirstValueSetting(newVal);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* 第一次加载赋值
|
||||
*/
|
||||
async function handleFirstValueSetting(value){
|
||||
if(props.idField === props.store){
|
||||
*/
|
||||
async function handleFirstValueSetting(value) {
|
||||
if (props.idField === props.store) {
|
||||
// 如果id字段就是存储字段 那么可以不用调用请求
|
||||
emit('next', value)
|
||||
}else{
|
||||
if(props.origin===true){
|
||||
emit('next', value);
|
||||
} else {
|
||||
if (props.origin === true) {
|
||||
// 如果是联动组件的第一个组件,等待options加载完后从options中取值
|
||||
await getSelfOptions()
|
||||
valueChangeThenEmitNext(value)
|
||||
}else{
|
||||
await getSelfOptions();
|
||||
valueChangeThenEmitNext(value);
|
||||
} else {
|
||||
// 如果是联动组件的后续组件,根据选中的value加载一遍数据
|
||||
let arr = await loadValueText();
|
||||
valueChangeThenEmitNext(value, arr)
|
||||
valueChangeThenEmitNext(value, arr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function loadOptions() {
|
||||
let params = getQueryParams();
|
||||
if(props.origin===true){
|
||||
params['condition'] = props.condition
|
||||
}else{
|
||||
params['pidValue'] = props.pidValue
|
||||
if (props.origin === true) {
|
||||
params['condition'] = props.condition;
|
||||
} else {
|
||||
params['pidValue'] = props.pidValue;
|
||||
}
|
||||
console.log("请求参数", params)
|
||||
dictOptions.value = []
|
||||
defHttp.get({ url: SELECT_OPTIONS_URL, params},{ isTransformResponse: false }).then(res=>{
|
||||
if(res.success){
|
||||
dictOptions.value = [...res.result]
|
||||
console.log("请求结果", res.result, dictOptions)
|
||||
}else{
|
||||
$message.warning('联动组件数据加载失败,请检查配置!')
|
||||
console.log('请求参数', params);
|
||||
dictOptions.value = [];
|
||||
defHttp.get({ url: SELECT_OPTIONS_URL, params }, { isTransformResponse: false }).then((res) => {
|
||||
if (res.success) {
|
||||
dictOptions.value = [...res.result];
|
||||
console.log('请求结果', res.result, dictOptions);
|
||||
} else {
|
||||
$message.warning('联动组件数据加载失败,请检查配置!');
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function getQueryParams(){
|
||||
|
||||
function getQueryParams() {
|
||||
let params = {
|
||||
table: props.table,
|
||||
table: props.table,
|
||||
txt: props.txt,
|
||||
key: props.store,
|
||||
idField: props.idField,
|
||||
pidField: props.pidField
|
||||
}
|
||||
pidField: props.pidField,
|
||||
};
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
function loadValueText() {
|
||||
return new Promise(resolve => {
|
||||
if(!props.value){
|
||||
selectedValue.value = []
|
||||
resolve([])
|
||||
}else{
|
||||
return new Promise((resolve) => {
|
||||
if (!props.value) {
|
||||
selectedValue.value = [];
|
||||
resolve([]);
|
||||
} else {
|
||||
let params = getQueryParams();
|
||||
if(props.isNumber === true){
|
||||
params['condition'] = `${props.store} = ${props.value}`
|
||||
}else{
|
||||
params['condition'] = `${props.store} = '${props.value}'`
|
||||
if (props.isNumber === true) {
|
||||
params['condition'] = `${props.store} = ${props.value}`;
|
||||
} else {
|
||||
params['condition'] = `${props.store} = '${props.value}'`;
|
||||
}
|
||||
defHttp.get({ url: SELECT_OPTIONS_URL, params},{ isTransformResponse: false }).then(res=>{
|
||||
if(res.success){
|
||||
resolve(res.result)
|
||||
}else{
|
||||
$message.warning('联动组件数据加载失败,请检查配置!')
|
||||
resolve([])
|
||||
defHttp.get({ url: SELECT_OPTIONS_URL, params }, { isTransformResponse: false }).then((res) => {
|
||||
if (res.success) {
|
||||
resolve(res.result);
|
||||
} else {
|
||||
$message.warning('联动组件数据加载失败,请检查配置!');
|
||||
resolve([]);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下拉选项
|
||||
* 获取下拉选项
|
||||
*/
|
||||
function getSelfOptions() {
|
||||
return new Promise((resolve) => {
|
||||
let index = 0;
|
||||
(function next(index) {
|
||||
if(index>10){
|
||||
resolve([])
|
||||
if (index > 10) {
|
||||
resolve([]);
|
||||
}
|
||||
let arr = dictOptions.value
|
||||
if (arr && arr.length>0) {
|
||||
resolve(arr)
|
||||
let arr = dictOptions.value;
|
||||
if (arr && arr.length > 0) {
|
||||
resolve(arr);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
next(index++)
|
||||
}, 300)
|
||||
next(index++);
|
||||
}, 300);
|
||||
}
|
||||
})(index)
|
||||
})
|
||||
})(index);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 值改变后 需要往外抛事件 触发下级节点的选项改变
|
||||
*/
|
||||
function valueChangeThenEmitNext(value, arr:any=[]){
|
||||
if(value && value.length>0){
|
||||
if(!arr || arr.length==0){
|
||||
arr = dictOptions.value
|
||||
function valueChangeThenEmitNext(value, arr: any = []) {
|
||||
if (value && value.length > 0) {
|
||||
if (!arr || arr.length == 0) {
|
||||
arr = dictOptions.value;
|
||||
}
|
||||
let selected = arr.filter(item=>item.store===value)
|
||||
if(selected && selected.length>0){
|
||||
let id = selected[0].id
|
||||
emit('next', id)
|
||||
let selected = arr.filter((item) => item.store === value);
|
||||
if (selected && selected.length > 0) {
|
||||
let id = selected[0].id;
|
||||
emit('next', id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
selectedValue,
|
||||
dictOptions,
|
||||
handleChange
|
||||
}
|
||||
}
|
||||
})
|
||||
handleChange,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
|
|
@ -1,142 +1,142 @@
|
|||
<!--popup组件-->
|
||||
<template>
|
||||
<div class="components-input-demo-presuffix" v-if="avalid">
|
||||
<!--输入框-->
|
||||
<a-input @click="handleOpen" v-model:value="showText" :placeholder="placeholder" readOnly v-bind="attrs">
|
||||
<template #prefix>
|
||||
<Icon icon="ant-design:cluster-outlined"></Icon>
|
||||
</template>
|
||||
<template #suffix>
|
||||
<Icon icon="ant-design:close-circle-outlined" @click="handleEmpty" title="清空" v-if="showText"></Icon>
|
||||
</template>
|
||||
</a-input>
|
||||
<!--popup弹窗-->
|
||||
<JPopupOnlReportModal @register="regModal" :code="code" :multi="multi" :sorter="sorter" :groupId="uniqGroupId" :param="param" @ok="callBack"></JPopupOnlReportModal>
|
||||
</div>
|
||||
<div class="components-input-demo-presuffix" v-if="avalid">
|
||||
<!--输入框-->
|
||||
<a-input @click="handleOpen" v-model:value="showText" :placeholder="placeholder" readOnly v-bind="attrs">
|
||||
<template #prefix>
|
||||
<Icon icon="ant-design:cluster-outlined"></Icon>
|
||||
</template>
|
||||
<template #suffix>
|
||||
<Icon icon="ant-design:close-circle-outlined" @click="handleEmpty" title="清空" v-if="showText"></Icon>
|
||||
</template>
|
||||
</a-input>
|
||||
<!--popup弹窗-->
|
||||
<JPopupOnlReportModal @register="regModal" :code="code" :multi="multi" :sorter="sorter" :groupId="uniqGroupId" :param="param" @ok="callBack"></JPopupOnlReportModal>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import JPopupOnlReportModal from './modal/JPopupOnlReportModal.vue'
|
||||
import {defineComponent, ref, reactive, onMounted, watchEffect, watch, computed, unref} from 'vue';
|
||||
import {useModal} from '/@/components/Modal';
|
||||
import {propTypes} from "/@/utils/propTypes";
|
||||
import {useAttrs} from "/@/hooks/core/useAttrs";
|
||||
import {useMessage} from '/@/hooks/web/useMessage';
|
||||
import JPopupOnlReportModal from './modal/JPopupOnlReportModal.vue';
|
||||
import { defineComponent, ref, reactive, onMounted, watchEffect, watch, computed, unref } from 'vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'JPopup',
|
||||
components: {
|
||||
JPopupOnlReportModal
|
||||
export default defineComponent({
|
||||
name: 'JPopup',
|
||||
components: {
|
||||
JPopupOnlReportModal,
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
code: propTypes.string.def(''),
|
||||
value: propTypes.string.def(''),
|
||||
sorter: propTypes.string.def(''),
|
||||
width: propTypes.number.def(1200),
|
||||
placeholder: propTypes.string.def('请选择'),
|
||||
multi: propTypes.bool.def(false),
|
||||
param: propTypes.object.def({}),
|
||||
spliter: propTypes.string.def(','),
|
||||
groupId: propTypes.string.def(''),
|
||||
formElRef: propTypes.object,
|
||||
setFieldsValue: propTypes.func,
|
||||
fieldConfig: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
emits: ['update:value', 'register'],
|
||||
setup(props, { emit, refs }) {
|
||||
const { createMessage } = useMessage();
|
||||
const attrs = useAttrs();
|
||||
//pop是否展示
|
||||
const avalid = ref(true);
|
||||
const showText = ref('');
|
||||
//注册model
|
||||
const [regModal, { openModal }] = useModal();
|
||||
//表单值
|
||||
let { groupId, code, fieldConfig } = props;
|
||||
//唯一分组groupId
|
||||
const uniqGroupId = computed(() => (groupId ? `${groupId}_${code}_${fieldConfig[0]['source']}_${fieldConfig[0]['target']}` : ''));
|
||||
/**
|
||||
* 判断popup配置项是否正确
|
||||
*/
|
||||
onMounted(() => {
|
||||
if (props.fieldConfig.length == 0) {
|
||||
createMessage.error('popup参数未正确配置!');
|
||||
avalid.value = false;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 监听value数值
|
||||
*/
|
||||
watch(
|
||||
() => props.value,
|
||||
(val) => {
|
||||
showText.value = val && val.length > 0 ? val.split(props.spliter).join(',') : '';
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
code: propTypes.string.def(''),
|
||||
value: propTypes.string.def(''),
|
||||
sorter: propTypes.string.def(''),
|
||||
width: propTypes.number.def(1200),
|
||||
placeholder: propTypes.string.def('请选择'),
|
||||
multi: propTypes.bool.def(false),
|
||||
param: propTypes.object.def({}),
|
||||
spliter: propTypes.string.def(','),
|
||||
groupId: propTypes.string.def(''),
|
||||
formElRef: propTypes.object,
|
||||
setFieldsValue: propTypes.func,
|
||||
fieldConfig: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
},
|
||||
emits: ['update:value','register'],
|
||||
setup(props, {emit, refs}) {
|
||||
const {createMessage} = useMessage();
|
||||
const attrs = useAttrs();
|
||||
//pop是否展示
|
||||
const avalid = ref(true);
|
||||
const showText = ref('');
|
||||
//注册model
|
||||
const [regModal, {openModal}] = useModal();
|
||||
//表单值
|
||||
let {groupId, code, fieldConfig} = props;
|
||||
//唯一分组groupId
|
||||
const uniqGroupId = computed(() => groupId ? `${groupId}_${code}_${fieldConfig[0]['source']}_${fieldConfig[0]['target']}` : '');
|
||||
/**
|
||||
* 判断popup配置项是否正确
|
||||
*/
|
||||
onMounted(() => {
|
||||
if (props.fieldConfig.length == 0) {
|
||||
createMessage.error('popup参数未正确配置!');
|
||||
avalid.value = false;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 监听value数值
|
||||
*/
|
||||
watch(
|
||||
() => props.value,
|
||||
(val) => {
|
||||
showText.value = val && val.length>0 ? val.split(props.spliter).join(',') : '';
|
||||
},
|
||||
{immediate: true}
|
||||
);
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
/**
|
||||
* 打开pop弹出框
|
||||
*/
|
||||
function handleOpen() {
|
||||
!props.disabled && openModal(true);
|
||||
}
|
||||
/**
|
||||
* 打开pop弹出框
|
||||
*/
|
||||
function handleOpen() {
|
||||
!props.disabled && openModal(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO 清空
|
||||
*/
|
||||
function handleEmpty() {
|
||||
showText.value = '';
|
||||
}
|
||||
/**
|
||||
* TODO 清空
|
||||
*/
|
||||
function handleEmpty() {
|
||||
showText.value = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 传值回调
|
||||
*/
|
||||
function callBack(rows) {
|
||||
let {fieldConfig} = props;
|
||||
//匹配popup设置的回调值
|
||||
let values = {};
|
||||
for (let item of fieldConfig) {
|
||||
let val = rows.map(row => row[item.source]).join(',');
|
||||
item.target.split(",").forEach(target => {
|
||||
values[target] = val;
|
||||
});
|
||||
}
|
||||
//传入表单示例方式赋值
|
||||
props.formElRef && props.formElRef.setFieldsValue(values);
|
||||
//传入赋值方法方式赋值
|
||||
props.setFieldsValue && props.setFieldsValue(values);
|
||||
}
|
||||
/**
|
||||
* 传值回调
|
||||
*/
|
||||
function callBack(rows) {
|
||||
let { fieldConfig } = props;
|
||||
//匹配popup设置的回调值
|
||||
let values = {};
|
||||
for (let item of fieldConfig) {
|
||||
let val = rows.map((row) => row[item.source]).join(',');
|
||||
item.target.split(',').forEach((target) => {
|
||||
values[target] = val;
|
||||
});
|
||||
}
|
||||
//传入表单示例方式赋值
|
||||
props.formElRef && props.formElRef.setFieldsValue(values);
|
||||
//传入赋值方法方式赋值
|
||||
props.setFieldsValue && props.setFieldsValue(values);
|
||||
}
|
||||
|
||||
return {
|
||||
showText,
|
||||
avalid,
|
||||
uniqGroupId,
|
||||
attrs,
|
||||
regModal,
|
||||
handleOpen,
|
||||
handleEmpty,
|
||||
callBack,
|
||||
};
|
||||
},
|
||||
});
|
||||
return {
|
||||
showText,
|
||||
avalid,
|
||||
uniqGroupId,
|
||||
attrs,
|
||||
regModal,
|
||||
handleOpen,
|
||||
handleEmpty,
|
||||
callBack,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.components-input-demo-presuffix .anticon-close-circle {
|
||||
cursor: pointer;
|
||||
color: #ccc;
|
||||
transition: color 0.3s;
|
||||
font-size: 12px;
|
||||
}
|
||||
.components-input-demo-presuffix .anticon-close-circle {
|
||||
cursor: pointer;
|
||||
color: #ccc;
|
||||
transition: color 0.3s;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.components-input-demo-presuffix .anticon-close-circle:hover {
|
||||
color: #f5222d;
|
||||
}
|
||||
.components-input-demo-presuffix .anticon-close-circle:hover {
|
||||
color: #f5222d;
|
||||
}
|
||||
|
||||
.components-input-demo-presuffix .anticon-close-circle:active {
|
||||
color: #666;
|
||||
}
|
||||
.components-input-demo-presuffix .anticon-close-circle:active {
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue