commit d8bd3d762462b952dbdcf34ec36bb4174a547fb4 Author: liangjiami <2249412933@qq.com> Date: Wed Jul 9 15:36:17 2025 +0800 乐企第一次提交 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..aa721d0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +# @see: http://editorconfig.org + +root = true + +[*] # 表示所有文件适用 +charset = utf-8 # 设置文件字符集为 utf-8 +end_of_line = lf # 控制换行类型(lf | cr | crlf) +insert_final_newline = true # 始终在文件末尾插入一个新行 +indent_style = space # 缩进风格(tab | space) +indent_size = 2 # 缩进大小 +max_line_length = 130 # 最大行长度 + +[*.md] # 表示仅对 md 文件适用以下规则 +max_line_length = off # 关闭最大行长度限制 +trim_trailing_whitespace = false # 关闭末尾空格修剪 diff --git a/.env b/.env new file mode 100644 index 0000000..535ed56 --- /dev/null +++ b/.env @@ -0,0 +1,11 @@ +# title +VITE_GLOB_APP_TITLE = F2B211发票管理平台 + +# 本地运行端口号 +VITE_PORT = 8080 + +# 启动时自动打开浏览器 +VITE_OPEN = true + +# 打包后是否生成包分析文件 +VITE_REPORT = true diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..64f3fe5 --- /dev/null +++ b/.env.development @@ -0,0 +1,29 @@ +ENV = 'dev' +VITE_APP_API_VERSION = "" +VITE_APP_API_BASEURL = https://dev.leqi.api.f2b211.com/v1/ +VITE_APP_SSO_LOGINURL = http://dev.uc.v3.f2b211.com/uc/login #// http://dev.uc.f2b211.com/index.php/uc/user/login.html +VITE_APP_SSO_APPID = 100905298197217281 +VITE_REDIRECT_URL = http://localhost:8080/login +#VITE_REDIRECT_URL = http://dev.leqi.f2b211.com/login #单点从定向地址 +VITE_SINGLE_URL = https://dev.uc.v3.f2b211.com/ #单点登录通知 + +# 本地环境 +VITE_USER_NODE_ENV = development + +# 公共基础路径 +VITE_PUBLIC_PATH = / + +# 打包时是否删除 console +VITE_DROP_CONSOLE = true + +# 是否开启 VitePWA +VITE_PWA = false + +# 开发环境接口地址 +VITE_API_URL = /api + +# 开发环境跨域代理,支持配置多个 +VITE_PROXY = [["/api","https://mock.mengxuegu.com/mock/629d727e6163854a32e8307e"]] +# VITE_PROXY = [["/api","https://www.fastmock.site/mock/f81e8333c1a9276214bcdbc170d9e0a0"]] +# VITE_PROXY = [["/api-easymock","https://mock.mengxuegu.com"],["/api-fastmock","https://www.fastmock.site"]] + diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..78b08e9 --- /dev/null +++ b/.env.production @@ -0,0 +1,32 @@ +ENV = 'production' +VITE_APP_API_VERSION = "" +VITE_APP_API_BASEURL = https://leqi.api.f2b211.com/v1/ +VITE_APP_SSO_LOGINURL = https://uc.v3.f2b211.com/uc/login #// http://dev.uc.f2b211.com/index.php/uc/user/login.html +VITE_APP_SSO_APPID = 100664627590856708 +#VITE_REDIRECT_URL = http://localhost:8080/login +VITE_REDIRECT_URL = http://leqi.f2b211.com/login #单点从定向地址 + +#VITE_SINGLE_URL = https://dev.uc.v3.f2b211.com/ #单点登录通知 + +# 线上环境 +VITE_USER_NODE_ENV = production + +# 公共基础路径 +VITE_PUBLIC_PATH = / + +# 是否启用 gzip 或 brotli 压缩打包,如果需要多个压缩规则,可以使用 “,” 分隔 +# Optional: gzip | brotli | none +VITE_BUILD_COMPRESS = none + +# 打包压缩后是否删除源文件 +VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false + +# 打包时是否删除 console +VITE_DROP_CONSOLE = true + +# 是否开启 VitePWA +VITE_PWA = true + +# 线上环境接口地址 +VITE_API_URL = "https://mock.mengxuegu.com/mock/629d727e6163854a32e8307e" + diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..f7b1e90 --- /dev/null +++ b/.env.test @@ -0,0 +1,29 @@ +ENV = 'test' +VITE_APP_API_VERSION = "" +VITE_APP_API_BASEURL = https://dev.leqi.f2b211.com/v1/ +VITE_APP_SSO_LOGINURL = http://dev.uc.v3.f2b211.com/uc/login #// http://dev.uc.f2b211.com/index.php/uc/user/login.html +VITE_APP_SSO_APPID = 100905298197217281 +VITE_REDIRECT_URL = http://dev.leqi.f2b211.com/adm/login #单点从定向地址 +VITE_SINGLE_URL = https://dev.uc.v3.f2b211.com/ #单点登录通知 + +# 测试环境 +VITE_USER_NODE_ENV = test + +# 公共基础路径 +VITE_PUBLIC_PATH = / + +# 是否启用 gzip 或 brotli 压缩打包,如果需要多个压缩规则,可以使用 “,” 分隔 +# Optional: gzip | brotli | none +VITE_BUILD_COMPRESS = none + +# 打包压缩后是否删除源文件 +VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false + +# 打包时是否删除 console +VITE_DROP_CONSOLE = true + +# 是否开启 VitePWA +VITE_PWA = false + +# 测试环境接口地址 +VITE_API_URL = "https://www.fastmock.site/mock/f81e8333c1a9276214bcdbc170d9e0a0" diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..0c7bd77 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,16 @@ +*.sh +node_modules +*.md +*.woff +*.ttf +.vscode +.idea +dist +/public +/docs +.husky +.local +/bin +/src/mock/* +stats.html +/src/assets diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..2de3d3d --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,66 @@ +// @see: http://eslint.cn + +module.exports = { + root: true, + env: { + browser: true, + node: true, + es6: true + }, + // 指定如何解析语法 + parser: "vue-eslint-parser", + // 优先级低于 parse 的语法解析配置 + parserOptions: { + parser: "@typescript-eslint/parser", + ecmaVersion: 2020, + sourceType: "module", + jsxPragma: "React", + ecmaFeatures: { + jsx: true + } + }, + // 继承某些已有的规则 + extends: ["plugin:vue/vue3-recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"], + /** + * "off" 或 0 ==> 关闭规则 + * "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行) + * "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错) + */ + rules: { + // eslint (http://eslint.cn/docs/rules) + "no-var": "error", // 要求使用 let 或 const 而不是 var + "no-multiple-empty-lines": ["error", { max: 1 }], // 不允许多个空行 + "prefer-const": "off", // 使用 let 关键字声明但在初始分配后从未重新分配的变量,要求使用 const + "no-use-before-define": "off", // 禁止在 函数/类/变量 定义之前使用它们 + //import.meta.env.ENV process.env.NODE_ENV + // typeScript (https://typescript-eslint.io/rules) + "@typescript-eslint/no-unused-vars": "error", + //'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', + // "@typescript-eslint/no-unused-vars": "error", // 禁止定义未使用的变量 + "@typescript-eslint/prefer-ts-expect-error": "error", // 禁止使用 @ts-ignore + "@typescript-eslint/ban-ts-comment": "error", // 禁止 @ts- 使用注释或要求在指令后进行描述 + "@typescript-eslint/no-inferrable-types": "off", // 可以轻松推断的显式类型可能会增加不必要的冗长 + "@typescript-eslint/no-namespace": "off", // 禁止使用自定义 TypeScript 模块和命名空间 + "@typescript-eslint/no-explicit-any": "off", // 禁止使用 any 类型 + "@typescript-eslint/ban-types": "off", // 禁止使用特定类型 + "@typescript-eslint/no-var-requires": "off", // 允许使用 require() 函数导入模块 + "@typescript-eslint/no-empty-function": "off", // 禁止空函数 + "@typescript-eslint/no-non-null-assertion": "off", // 不允许使用后缀运算符的非空断言(!) + + // vue (https://eslint.vuejs.org/rules) + "vue/script-setup-uses-vars": "error", // 防止 + + + + diff --git a/lint-staged.config.cjs b/lint-staged.config.cjs new file mode 100644 index 0000000..04d1d40 --- /dev/null +++ b/lint-staged.config.cjs @@ -0,0 +1,8 @@ +module.exports = { + "*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"], + "{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": ["prettier --write--parser json"], + "package.json": ["prettier --write"], + "*.vue": ["eslint --fix", "prettier --write", "stylelint --fix"], + "*.{scss,less,styl,html}": ["stylelint --fix", "prettier --write"], + "*.md": ["prettier --write"] +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..ebbf450 --- /dev/null +++ b/package.json @@ -0,0 +1,123 @@ +{ + "name": "ops_admin_ts", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "serve": "vite", + "build:dev": "vue-tsc && vite build --mode development", + "build:test": "vue-tsc && vite build --mode test", + "build:pro": "vue-tsc && vite build --mode production", + "type:check": "vue-tsc --noEmit --skipLibCheck", + "preview": "npm run build:dev && vite preview", + "lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src", + "lint:prettier": "prettier --write \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"", + "lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/", + "lint:lint-staged": "lint-staged", + "prepare": "husky install", + "release": "standard-version", + "commit": "git add -A && czg && git push" + }, + "dependencies": { + "@element-plus/icons-vue": "^2.1.0", + "@types/decimal.js": "^7.4.0", + "@vueuse/core": "^10.1.2", + "@wangeditor/editor": "^5.1.23", + "@wangeditor/editor-for-vue": "^5.1.12", + "async-validator": "^4.2.5", + "axios": "^1.4.0", + "dayjs": "^1.11.9", + "decimal": "^0.0.2", + "default-passive-events": "^2.0.0", + "driver.js": "^0.9.8", + "element-plus": "^2.3.4", + "file-saver": "^2.0.5", + "js-md5": "^0.7.3", + "jsbarcode": "^3.11.6", + "lodash-es": "^4.17.21", + "mitt": "^3.0.0", + "nprogress": "^0.2.0", + "pinia": "^2.1.3", + "pinia-plugin-persistedstate": "^3.1.0", + "print-js": "^1.6.0", + "qs": "^6.11.2", + "sortablejs": "^1.15.0", + "vue": "^3.3.4", + "vue-pdf-embed": "^1.2.1", + "vue-router": "^4.2.2", + "vuedraggable": "^4.1.0", + "vxe-table": "^4.5.0-beta.10", + "xe-utils": "^3.5.11", + "xlsx": "^0.18.5" + }, + "devDependencies": { + "@commitlint/cli": "^17.6.3", + "@commitlint/config-conventional": "^17.6.3", + "@iconify-json/ep": "^1.1.10", + "@types/file-saver": "^2.0.5", + "@types/js-md5": "^0.7.0", + "@types/nprogress": "^0.2.0", + "@types/qs": "^6.9.7", + "@types/sortablejs": "^1.15.1", + "@typescript-eslint/eslint-plugin": "^5.59.7", + "@typescript-eslint/parser": "^5.59.7", + "@vitejs/plugin-vue": "^4.2.3", + "@vitejs/plugin-vue-jsx": "^3.0.1", + "autoprefixer": "^10.4.14", + "cz-git": "^1.6.1", + "czg": "^1.6.1", + "eslint": "^8.41.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-vue": "^9.14.0", + "husky": "^8.0.3", + "lint-staged": "^13.2.2", + "postcss": "^8.4.23", + "postcss-html": "^1.5.0", + "prettier": "^2.8.8", + "qrcode": "^1.5.3", + "rollup-plugin-visualizer": "^5.9.0", + "sass": "^1.62.1", + "standard-version": "^9.5.0", + "stylelint": "^15.6.2", + "stylelint-config-html": "^1.1.0", + "stylelint-config-recess-order": "^4.0.0", + "stylelint-config-recommended-scss": "^12.0.0", + "stylelint-config-recommended-vue": "^1.4.0", + "stylelint-config-standard": "^33.0.0", + "stylelint-config-standard-scss": "^9.0.0", + "typescript": "^5.0.2", + "unplugin-auto-import": "^0.16.4", + "unplugin-icons": "^0.16.3", + "unplugin-vue-components": "^0.25.1", + "unplugin-vue-setup-extend-plus": "^1.0.0", + "vite": "^4.3.9", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-eslint": "^1.8.1", + "vite-plugin-html": "^3.2.0", + "vite-plugin-pwa": "^0.15.0", + "vite-plugin-svg-icons": "^2.0.1", + "vue-tsc": "^1.6.5" + }, + "engines": { + "node": ">=16.0.0" + }, + "browserslist": { + "production": [ + "> 1%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "config": { + "commitizen": { + "path": "node_modules/cz-git" + } + } +} diff --git a/postcss.config.cjs b/postcss.config.cjs new file mode 100644 index 0000000..5bfb8f6 --- /dev/null +++ b/postcss.config.cjs @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + autoprefixer: {} + } +}; diff --git a/public/image.png b/public/image.png new file mode 100644 index 0000000..72f6111 Binary files /dev/null and b/public/image.png differ diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..9b62435 Binary files /dev/null and b/public/logo.png differ diff --git a/public/vue.svg b/public/vue.svg new file mode 100644 index 0000000..770e9d3 --- /dev/null +++ b/public/vue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..08f9635 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,29 @@ + + + diff --git a/src/api/config/servicePort.ts b/src/api/config/servicePort.ts new file mode 100644 index 0000000..f8df42d --- /dev/null +++ b/src/api/config/servicePort.ts @@ -0,0 +1,3 @@ +// 后端微服务模块前缀 +export const PORT1 = "/api"; +export const PORT2 = "/hooks"; diff --git a/src/api/helper/axiosCancel.ts b/src/api/helper/axiosCancel.ts new file mode 100644 index 0000000..dfa60cb --- /dev/null +++ b/src/api/helper/axiosCancel.ts @@ -0,0 +1,47 @@ +// ? 暂未使用,目前使用全局 Loading 来控制重复请求 +import { CustomAxiosRequestConfig } from "../index"; +import qs from "qs"; + +// 声明一个 Map 用于存储每个请求的标识 和 取消函数 +let pendingMap = new Map(); + +// 序列化参数 +export const getPendingUrl = (config: CustomAxiosRequestConfig) => + [config.method, config.url, qs.stringify(config.data), qs.stringify(config.params)].join("&"); + +export class AxiosCanceler { + /** + * @description: 添加请求 + * @param {Object} config + * @return void + */ + addPending(config: CustomAxiosRequestConfig) { + // 在请求开始前,对之前的请求做检查取消操作 + this.removePending(config); + const url = getPendingUrl(config); + const controller = new AbortController(); + config.signal = controller.signal; + pendingMap.set(url, controller); + } + + /** + * @description: 移除请求 + * @param {Object} config + */ + removePending(config: CustomAxiosRequestConfig) { + const url = getPendingUrl(config); + // 如果在 pending 中存在当前请求标识,需要取消当前请求 + const controller = pendingMap.get(url); + controller && controller.abort(); + } + + /** + * @description: 清空所有pending + */ + removeAllPending() { + pendingMap.forEach(controller => { + controller && controller.abort(); + }); + pendingMap.clear(); + } +} diff --git a/src/api/helper/checkStatus.ts b/src/api/helper/checkStatus.ts new file mode 100644 index 0000000..79a3810 --- /dev/null +++ b/src/api/helper/checkStatus.ts @@ -0,0 +1,43 @@ +import { ElMessage } from "element-plus"; + +/** + * @description: 校验网络请求状态码 + * @param {Number} status + * @return void + */ +export const checkStatus = (status: number) => { + switch (status) { + case 400: + ElMessage.error("请求失败!请您稍后重试"); + break; + case 401: + ElMessage.error("登录失效!请您重新登录"); + break; + case 403: + ElMessage.error("当前账号无权限访问!"); + break; + case 404: + ElMessage.error("你所访问的资源不存在!"); + break; + case 405: + ElMessage.error("请求方式错误!请您稍后重试"); + break; + case 408: + ElMessage.error("请求超时!请您稍后重试"); + break; + case 500: + ElMessage.error("服务异常!"); + break; + case 502: + ElMessage.error("网关错误!"); + break; + case 503: + ElMessage.error("服务不可用!"); + break; + case 504: + ElMessage.error("网关超时!"); + break; + default: + ElMessage.error("请求失败!"); + } +}; diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 0000000..c2bafe5 --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,192 @@ +import axios, { AxiosInstance, AxiosError, AxiosRequestConfig, InternalAxiosRequestConfig, AxiosResponse } from "axios"; +//endLoading +import { showFullScreenLoading, tryHideFullScreenLoading } from "@/config/serviceLoading"; +import { usePathUrl } from "@/hooks/usePathUrl"; +import { ElMessage } from "element-plus"; +import { ResultData } from "@/api/interface"; +import { ResultEnum } from "@/enums/httpEnum"; +import { checkStatus } from "./helper/checkStatus"; +import { useUserStore } from "@/stores/modules/user"; +import router from "@/routers"; +import { useMsg } from "@/hooks/useMsg"; + +const getUcOffline = () => { + const userStore = useUserStore(); + // let httpUrl = import.meta.env.VITE_SINGLE_URL + "uc/offline"; + // fetch(httpUrl, { + // method: "POST", + // credentials: "include", + // keepalive: true, + // headers: { + // Authorization: userStore.phpToken, + // "Refresh-Authorization": userStore.refreshToken + // } + // }) + // .then((res: any) => { + // if (res.status === 200) { + // useMsg("success", "退出登录成功 !"); + // setTimeout(() => { + // location.href = usePathUrl(); + // // 2.重置用户数据 + // userStore.$reset(); + // // 3.清除 本地 + // localStorage.clear(); + // }, 800); + // } + // }) + // .catch(() => { + // useMsg("error", "退出登录失败,请稍后再试 !"); + // }); + useMsg("success", "退出登录成功 !"); + setTimeout(() => { + location.href = usePathUrl(); + // 2.重置用户数据 + userStore.$reset(); + // 3.清除 本地 + localStorage.clear(); + }, 800); +}; +// const getUcOnline = (phpToken: any, refreshToken: any) => { +// let httpUrl = import.meta.env.VITE_SINGLE_URL + "uc/online"; +// fetch(httpUrl, { +// method: "POST", +// credentials: "include", +// keepalive: true, +// headers: { +// Authorization: phpToken, +// "Refresh-Authorization": refreshToken +// } +// }); +// }; +//登出地址 +export interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig { + noLoading?: boolean; +} + +//计步器 +// let setUp: number = 0; +const config = { + // 默认地址请求地址,可在 .env.** 文件中修改 + baseURL: (import.meta.env.VITE_APP_API_BASEURL + import.meta.env.VITE_APP_API_VERSION) as string, + // 设置超时时间 + timeout: ResultEnum.TIMEOUT as number, + // 跨域时候允许携带凭证 + withCredentials: true +}; + +class RequestHttp { + service: AxiosInstance; + public constructor(config: AxiosRequestConfig) { + // instantiation + this.service = axios.create(config); + + /** + * @description 请求拦截器 + * 客户端发送请求 -> [请求拦截器] -> 服务器 + * token校验(JWT) : 接受服务器返回的 token,存储到 vuex/pinia/本地储存当中 + */ + this.service.interceptors.request.use( + (config: CustomAxiosRequestConfig) => { + const userStore = useUserStore(); + // 当前请求不需要显示 loading,在 api 服务中通过指定的第三个参数: { noLoading: true } 来控制 + config.noLoading || showFullScreenLoading(); + if (config.headers && typeof config.headers.set === "function") { + config.headers.set("authorization", userStore.newUserToken); + // config.headers.set("Refresh-Authorization", userStore.refreshToken); + } + // getUcOnline(userStore.phpToken, userStore.refreshToken); + return config; + }, + (error: AxiosError) => { + return Promise.reject(error); + } + ); + + /** + * @description 响应拦截器 + * 服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息 + */ + this.service.interceptors.response.use( + (response: AxiosResponse) => { + const { data } = response; + const userStore = useUserStore(); + // 更新token,如果接口返回新的token + if ("authorization" in response.headers && response.headers.authorization) { + let newtoken = "Bearer " + response.headers.authorization; + userStore.setToken(newtoken); + userStore.setRefreshToken(newtoken); + userStore.setPhpToken(newtoken); + } + tryHideFullScreenLoading(); + // 登陆失效 + if (data.code == 401) { + ElMessage.error(data.msg || data.message); + getUcOffline(); + return Promise.reject(data); + } + if (data.code === 504) { + ElMessage.error("请求超时!请您稍后重试"); + } + + // 全局错误信息拦截(防止下载文件的时候返回数据流,没有 code 直接报错) + if (data.code && data.code !== ResultEnum.SUCCESS) { + if (data.code == 1 && data.msg == "没有权限菜单数据") { + getUcOffline(); + } + ElMessage.error(data.msg); + return Promise.reject(data); + } + //当是200但是msg不是Success弹出错误信息 + if (data.code !== 0 && data.msg !== "success") { + ElMessage.error(data.message); + } + // 成功请求(在页面上除非特殊情况,否则不用处理失败逻辑) + return data; + }, + async (error: AxiosError) => { + // if (!setUp) { + const { response } = error; + + tryHideFullScreenLoading(); + //setUp++; + // 请求超时 && 网络错误单独判断,没有 response + if (error.message.indexOf("timeout") !== -1) ElMessage.error("请求超时!请您稍后重试"); + if (error.message.indexOf("Network Error") !== -1) ElMessage.error("网络错误!请您稍后重试"); + // 根据服务器响应的错误状态码,做不同的处理 + if (response) { + checkStatus(response.status); + if (response.status === 401) { + getUcOffline(); + } + } + // 服务器结果都没有返回(可能服务器错误可能客户端断网),断网处理:可以跳转到断网页面 + if (!window.navigator.onLine) router.replace("/500"); + return Promise.reject(error); + // } else { + // endLoading(); + // } + } + ); + } + + /** + * @description 常用请求方法封装 + */ + get(url: string, params?: object, _object = {}): Promise> { + return this.service.get(url, { params, ..._object }); + } + post(url: string, params?: object | string, _object = {}): Promise> { + return this.service.post(url, params, _object); + } + put(url: string, params?: object, _object = {}): Promise> { + return this.service.put(url, params, _object); + } + delete(url: string, params?: any, _object = {}): Promise> { + return this.service.delete(url, { params, ..._object }); + } + download(url: string, params?: object, _object = {}): Promise { + return this.service.post(url, params, { ..._object, responseType: "blob" }); + } +} + +export default new RequestHttp(config); diff --git a/src/api/interface/global.ts b/src/api/interface/global.ts new file mode 100644 index 0000000..41b21c4 --- /dev/null +++ b/src/api/interface/global.ts @@ -0,0 +1,59 @@ +// 全局模块 +export namespace Global { + //供应链 + export interface ResSupplier { + id: number; + code: string; + name: string; + disable: boolean; + } + //单位 + export interface ResUnit { + disable: boolean; + id: number; + isClosed: boolean; + name: string; + precision: number; + roundoffType: number; + } + //汇率 + export interface ResTaxRate { + disable: boolean; + id: number; + name: string; + } + //仓库 + export interface ResWarehouse { + id: number; + name: string; + code: null; + contacts: string; + contactsId: number; + useOrgId: null; + customerWarehouseTag: boolean; + tempTransferWarehouse: number; + defaultReplenishCustomer: number; + customerId: number; + stockType: number; + disable: boolean; + } + //用户 + export interface ResUserList { + id: number; + code: null; + name: string; + number: number; + disable: boolean; + } + interface ResDropDownAllItem { + id: 15756737; + level: 2; + name: "jx_cs_15_01"; + number: "123456"; + } + //物料分类 + export interface ResDropDownAll { + groupNameList: ResDropDownAllItem; + chinds: ResDropDownAllItem[]; + } +} diff --git a/src/api/interface/index.ts b/src/api/interface/index.ts new file mode 100644 index 0000000..8b43d0e --- /dev/null +++ b/src/api/interface/index.ts @@ -0,0 +1,8 @@ +import { Global } from "./global"; +import { User } from "./user"; +import { Material } from "./material"; +import { Login } from "./login"; +import { Result, ResultData } from "./result"; +import { ResPage, ReqPage } from "./page"; +import { Upload } from "./upload"; +export type { Global, User, Material, Login, ResultData, Result, ResPage, ReqPage, Upload }; diff --git a/src/api/interface/login.ts b/src/api/interface/login.ts new file mode 100644 index 0000000..2f6e360 --- /dev/null +++ b/src/api/interface/login.ts @@ -0,0 +1,61 @@ +// 登录模块 +export interface Dept { + id: number; + deptCode: string; + deptName: string; + managerId: null; +} + +export namespace Login { + //登录要传的参数 + export interface ReqLoginCode { + code: string; + } + //登录返回的参数 + interface Dept { + id: number; + deptCode: string; + deptName: string; + managerId: null; + } + export interface ResLogin { + isSuccess: boolean; + message: string; + status: number; + data: { + accessToken: { + token: string; + phpToken: string; + tokenType: string; + refreshToken: string; + expired: string; + }; + signedIn: boolean; + userInfo: { + seesionId: string; + ucId: number; + depts: Dept[]; + staffId: number; + staff_code: string; + business_code: null; + avatar: null; + closed: number; + createdAt: string; + email: null; + mobile: string; + nickname: string; + roleId: string; + signinAt: string; + updatedAt: string; + companyId: number; + companyName: string; + orgId: number; + supplierId: null; + supplierName: null; + customerId: null; + customerName: null; + identity: number; + }; + }; + } +} diff --git a/src/api/interface/material.ts b/src/api/interface/material.ts new file mode 100644 index 0000000..514938b --- /dev/null +++ b/src/api/interface/material.ts @@ -0,0 +1,88 @@ +//物料模块 +export namespace Material { + // 物料列表请求参数 + export interface ListParams { + product: string; + supplyChain: string; + is211: string; + isDisable: boolean; + supplyOrgId: string; + supplierId: string; + barCode: string; + brand: string; + orgId: number; + pageNo: number; + pageSize: number; + } + // 物料列表相应参数 + export interface ListRelust { + id: number; + isDisable: boolean; + name: string; + number: string; + documentStatus: string; + documentStatusName: string; + specifications: string; + groupId: number; + groupOne: string; + groupTwo: string; + groupThree: string; + groupFour: string; + purchasePrice: number; + cost: number; + picture: string; + materialProperty: string; + supplier: string; + supplyOrg: string; + supplyChain: string; + is211: boolean; + productLocation: string; + lifeCycle: string; + color: string; + safety: string; + barCode: string; + brand: string; + brandType: string; + productNoColor: string; + productSPU: string; + minNumber: number; + } + export interface DocumentStatus { + a: string; + b: string; + c: string; + d: string; + } + export interface Status { + documentStatus: DocumentStatus; + materialType: { [key: string]: string }; + supplyChainType: { [key: string]: string }; + productLocationType: { [key: string]: string }; + lifeCycleType: { [key: string]: string }; + brandType: { [key: string]: string }; + safetyType: { [key: string]: string }; + materialPropertyType: { [key: string]: string }; + materialBearType: { [key: string]: string }; + sendMaterialType: { [key: string]: string }; + salesPromotionType: { [key: string]: string }; + } + export interface SysMaterials { + id: number; + inputType: number; + queryField: string; + queryFieldType: string; + queryName: string; + } + export interface CommitList { + ids: number[]; + } + export interface CommitListRelust { + detailId: number; + isSuccess: boolean; + msg: string; + orderId: number; + orderNo: string; + parentOrderId: any; + parentOrderNo: any; + } +} diff --git a/src/api/interface/page.ts b/src/api/interface/page.ts new file mode 100644 index 0000000..34c425d --- /dev/null +++ b/src/api/interface/page.ts @@ -0,0 +1,15 @@ +//分页 +import { Result } from "./result"; +// 分页响应参数 +export interface ResPage extends Result { + data: { + list: T[]; + total: number; + }; +} + +// 分页请求参数 +export interface ReqPage { + pageNum: number; + pageSize: number; +} diff --git a/src/api/interface/result.ts b/src/api/interface/result.ts new file mode 100644 index 0000000..3c1591a --- /dev/null +++ b/src/api/interface/result.ts @@ -0,0 +1,11 @@ +// 请求响应参数(不包含data) +export interface Result { + isSuccess: boolean; + message: string; + status: number; +} + +// 请求响应参数(包含data) +export interface ResultData extends Result { + data: T; +} diff --git a/src/api/interface/upload.ts b/src/api/interface/upload.ts new file mode 100644 index 0000000..05e7b05 --- /dev/null +++ b/src/api/interface/upload.ts @@ -0,0 +1,6 @@ +// 文件上传模块 +export namespace Upload { + export interface ResFileUrl { + fileUrl: string; + } +} diff --git a/src/api/interface/user.ts b/src/api/interface/user.ts new file mode 100644 index 0000000..c3a31c4 --- /dev/null +++ b/src/api/interface/user.ts @@ -0,0 +1,44 @@ +// 用户管理模块 +export namespace User { + // 获取组织list + export interface ResUserOrgs { + id: number; + orgCode: string; + name: string; + orgType: string; + standardCoin: string; + standardCoinId: number; + autoDetaultStockId: number; + disable: boolean; + } + export interface ResUserDept { + id: number; + name: string; + pid: number; + managerId: null; + disable: boolean; + children: ResUserDept[]; + } + export interface ResWarehouse { + id: number; + name: string; + code: null; + contacts: string; + contactsId: number; + useOrgId: null; + customerWarehouseTag: boolean; + tempTransferWarehouse: number; + defaultReplenishCustomer: number; + customerId: number; + stockType: number; + disable: boolean; + } + //获取组织下的用户 + export interface ResUserList { + id: number; + code: null; + name: string; + number: number; + disable: boolean; + } +} diff --git a/src/api/modules/Invoice.ts b/src/api/modules/Invoice.ts new file mode 100644 index 0000000..047b27f --- /dev/null +++ b/src/api/modules/Invoice.ts @@ -0,0 +1,61 @@ +import http from "@/api"; +import { ResPage } from "@/api/interface/index"; +/** + * @name 发票列表 + */ +//发票列表 +export const getInvoiceListtApi = (params: Record) => { + return http.get>(`/invoice/index`, params); +}; +//系统字典数据接口 +export const getdictApi = (code: any) => { + return http.get>(`/sys/dict`, { code: code }); +}; +//预览发票 +export const getInvoicePreview = (serialno: string, invoiceno: string, type: Number) => { + return http.get>(`/invoice/preview/${serialno}/${invoiceno}`, { type: type }); +}; +//重开 +export const getInvoiceRedo = (id: string) => { + return http.get>(`/invoice/redo`, { id: id }); +}; +//回传 +export const getInvoiceBackfill = (id: string) => { + return http.get>(`invoice/backfill`, { id: id }); +}; +//查看失败原因 +export const getInvoicefindfailInfobyId = (id: Number) => { + return http.get>(`/invoice/${id}/view/failmsg`); +}; +//公司分页列表 +export const getCompanyList = (params: Record) => { + return http.get>(`/company/index`, params); +}; +//公司新增 +export const addCompany = (params: Record) => { + return http.post>(`/company/create`, params); +}; +//公司更新 +export const editCompany = (params: Record) => { + return http.post>(`/company/update`, params); +}; +//启用公司 +export const useCompany = (id: Number) => { + return http.get>(`/company/${id}/enable`); +}; +//禁用公司 +export const disableCompany = (id: Number) => { + return http.get>(`/company/${id}/disable`); +}; +//公司列表下拉框场景 +export const getCompanyListSelect = (params: Record) => { + return http.get>(`/company/list`, params); +}; +// 汇总确认 +export const getInvoiceConfirm = (params: Record) => { + return http.post>(`/invoice/summary/confirm`, params); +}; +//汇总取消 +export const getInvoiceCancel = (params: Record) => { + return http.post>(`/invoice/summary/cancel`, params); +}; diff --git a/src/api/modules/boxMark.ts b/src/api/modules/boxMark.ts new file mode 100644 index 0000000..b8b00ca --- /dev/null +++ b/src/api/modules/boxMark.ts @@ -0,0 +1,13 @@ +import http from "@/api"; +import { ResPage } from "@/api/interface/index"; +/** + * @name 盘点单 + */ +//盘点单列表 +export const getBoxMarkListApi = (params: Record) => { + return http.post>(`BoxMark/GetList`, params); +}; +//SysConfig/GetMaterialList +export const getMaterialListApi = (speci: any) => { + return http.get(`SysConfig/GetMaterialList?speci=${encodeURIComponent(speci)}`); +}; diff --git a/src/api/modules/deliveryAndOutbound.ts b/src/api/modules/deliveryAndOutbound.ts new file mode 100644 index 0000000..cd76e4c --- /dev/null +++ b/src/api/modules/deliveryAndOutbound.ts @@ -0,0 +1,20 @@ +import http from "@/api"; + +/** + * @name 发货出库 + */ +//出库任务列表 +export const getOutStockTaskListApi = (params: Record) => { + return http.post(`OutStockTask/GetList`, params); +}; +//出库单列表 +export const getOutStockListApi = (params: Record) => { + return http.post(`OutStock/GetList`, params); +}; +//出库单详情 +export const getDetailsApi = (id: any) => { + return http.get(`OutStock/GetInfo/${id}`); +}; +export const getTaskDetailsApi = (id: any) => { + return http.get(`OutStockTask/GetInfo/${id}`); +}; diff --git a/src/api/modules/exportList.ts b/src/api/modules/exportList.ts new file mode 100644 index 0000000..8c88c70 --- /dev/null +++ b/src/api/modules/exportList.ts @@ -0,0 +1,9 @@ +import http from "@/api"; +// 即时库存列表 +export const getListApi = (params: Record) => { + return http.post(`FileDownManager/FileDownManagerQuery`, params); +}; +//状态 +export const getStatusApi = () => { + return http.get(`FileDownManager/GetStatus`); +}; diff --git a/src/api/modules/global.ts b/src/api/modules/global.ts new file mode 100644 index 0000000..3b871b6 --- /dev/null +++ b/src/api/modules/global.ts @@ -0,0 +1,46 @@ +import http from "@/api"; + +/** + * @name 全局模块(在公司下面的数据) + */ +//获取全局单位 +export const getGlobalStatusApi = () => { + return http.get(`SysConfig/GetStatus`); +}; +//获取仓库 +export const getStockApi = () => { + return http.get(`SysConfig/GetUcStock`); +}; +//获取仓位 +export const getSubUcStockApi = (name: any) => { + return http.get(`SysConfig/GetSubUcStockByName/?name=${name}`); +}; +//获取组织 +export const getOrgApi = (name: any) => { + return http.get(`SysConfig/GetOrg/${name}`); +}; +//获取供应商 +export const getSupplierApi = (name: any) => { + return http.get(`SysConfig/GetSupplier/${name}`); +}; +//获取收货客户 +export const getCustomersApi = (name: any) => { + return http.get(`SysConfig/GetCustomers/${name}`); +}; + +//通知单点登录 +export const getUcOfflineApi = () => { + return http.post(`uc/offline`); +}; + +//全局顶部按钮操作 +//提交 +export const commitListApi = (url: string, params: any) => { + return http.post(url, params); +}; +export const getSubUcStockByNameApi = (id: any) => { + return http.get(`SysConfig/GetSubUcStockByName/?name=${id}`); +}; +export const getClineLoApi = (log: any) => { + return http.get(`ClientLog/Log/${log}`); +}; diff --git a/src/api/modules/inOtherLibraries.ts b/src/api/modules/inOtherLibraries.ts new file mode 100644 index 0000000..2169a99 --- /dev/null +++ b/src/api/modules/inOtherLibraries.ts @@ -0,0 +1,17 @@ +import http from "@/api"; +import { ResPage } from "@/api/interface/index"; +/** + * @name 其他库内操作 + */ +//移箱单列表 +export const getmovingBoxesListApi = (params: Record) => { + return http.post>(`MoveBoxRecord/GetList`, params); +}; +//出入库回退列表 +export const getInboundOutboundRollbackListApi = (params: Record) => { + return http.post>(`BackRecord/GetList`, params); +}; +//改箱列表 +export const getChangeBoxRecordListApi = (params: Record) => { + return http.post>(`ChangeBoxRecord/GetList`, params); +}; diff --git a/src/api/modules/inventory.ts b/src/api/modules/inventory.ts new file mode 100644 index 0000000..2ae3a05 --- /dev/null +++ b/src/api/modules/inventory.ts @@ -0,0 +1,9 @@ +import http from "@/api"; +import { ResPage } from "@/api/interface/index"; +/** + * @name 盘点单 + */ +//盘点单列表 +export const getTakeStockListApi = (params: Record) => { + return http.post>(`TakeStock/GetList`, params); +}; diff --git a/src/api/modules/login.ts b/src/api/modules/login.ts new file mode 100644 index 0000000..65d20c4 --- /dev/null +++ b/src/api/modules/login.ts @@ -0,0 +1,36 @@ +import { ResultData, Login } from "@/api/interface/index"; +// import authMenuList from "@/assets/json/authMenuList.json"; +import http from "@/api"; + +/** + * @name 登录模块 + */ +// 用户登录 +export const loginApi = (params: Login.ReqLoginCode) => { + return http.get>( + `/user/signin/${params.code}`, + {}, + { + noLoading: true + } + ); + // 正常 post json 请求 ==> application/json + // return http.post(PORT1 + `/login`, params, { noLoading: true }); // 控制当前请求不显示 loading + // return http.post(PORT1 + `/login`, {}, { params }); // post 请求携带 query 参数 ==> ?username=admin&password=123456 + // return http.post(PORT1 + `/login`, qs.stringify(params)); // post 请求携带表单参数 ==> application/x-www-form-urlencoded + // return http.get(PORT1 + `/login?${qs.stringify(params, { arrayFormat: "repeat" })}`); // get 请求可以携带数组等复杂参数 +}; + +// 获取菜单列表 +export const getAuthMenuListApi = () => { + return http.get(`/user/permissions`, {}, { noLoading: true }); +}; + +// 用户退出登录 +export const logoutApi = () => { + return http.get(`/user/signout`); +}; + +// export const LoginOutSingleApi = () => { +// return http.get(`/Login/LoginOutSingle`); +// }; diff --git a/src/api/modules/receiptAndWarehousing.ts b/src/api/modules/receiptAndWarehousing.ts new file mode 100644 index 0000000..e5db958 --- /dev/null +++ b/src/api/modules/receiptAndWarehousing.ts @@ -0,0 +1,20 @@ +import http from "@/api"; +import { ResPage } from "@/api/interface/index"; +/** + * @name 收货入库 + */ +//入库任务列表 +export const getInStockTaskListApi = (params: Record) => { + return http.post>(`InStockTask/GetList`, params); +}; +//入库单列表 +export const getInStockListApi = (params: Record) => { + return http.post>(`InStock/GetList`, params); +}; +//入库单详情 +export const getDetailsApi = (id: any) => { + return http.get(`InStock/GetInfo/${id}`); +}; +export const getTaskDetailsApi = (id: any) => { + return http.get(`InStockTask/GetInfo/${id}`); +}; diff --git a/src/api/modules/reportForm.ts b/src/api/modules/reportForm.ts new file mode 100644 index 0000000..eee99c9 --- /dev/null +++ b/src/api/modules/reportForm.ts @@ -0,0 +1,17 @@ +import http from "@/api"; +import { ResPage } from "@/api/interface/index"; +/** + * @name 报表 + */ +//即时库存明细 +export const getInventoryListApi = (params: Record) => { + return http.post>(`Inventory/GetList`, params); +}; +//物料收发明细 +export const getInOutistApi = (params: Record) => { + return http.post>(`Inventory/GetListInOut`, params); +}; +//箱库存查询 +export const getBoxListApi = (params: Record) => { + return http.post>(`Inventory/GetListBox`, params); +}; diff --git a/src/api/modules/sale.ts b/src/api/modules/sale.ts new file mode 100644 index 0000000..57c955e --- /dev/null +++ b/src/api/modules/sale.ts @@ -0,0 +1,49 @@ +import http from "@/api"; +import { ResPage } from "@/api/interface/index"; +/** + * @name 销售模块 + */ +//销售订单列表 +export const getListApi = (params: Record) => { + return http.post>(`SalOrder/GetList`, params); +}; + +//自定义条件Dictionary/sale +export const getDictionaryApi = () => { + return http.get(`Dictionary/sale`); +}; + +//下拉框状态 +export const getEnumApi = () => { + return http.get(`SalOrder/GetEnum`); +}; + +//详情 +export const getOrderDetailsApi = (id: any) => { + return http.post(`SalOrder/GetInfo/${id}`); +}; + +//销售退货列表 +export const getReturnListApi = (params: Record) => { + return http.post>(`ReturnStockOrder/GetList`, params); +}; +//销售退货自定义条件 +export const getRetrunDictionaryApi = () => { + return http.get(`Dictionary/RetrunOrder`); +}; +//销售退货状态 ReturnStockOrder/GetStatus +export const getRetrunStatusApi = () => { + return http.get(`ReturnStockOrder/GetStatus`); +}; +//销售退货单详情 +export const getRetrunDetailsApi = (id: any) => { + return http.get(`ReturnStockOrder/GetInfo/${id}`); +}; +// //销售出库单详情 +// export const getSalOutStockOrderApi = (id: any) => { +// return http.get(`SalOutStockOrder/GetInfo/${id}`); +// }; +// //发货通知单列表 +// export const getNoticeListApi = (params: Record) => { +// return http.post>(`DeliveryNoticeOrder/GetList`, params); +// }; diff --git a/src/api/modules/subscription.ts b/src/api/modules/subscription.ts new file mode 100644 index 0000000..7b06e3a --- /dev/null +++ b/src/api/modules/subscription.ts @@ -0,0 +1,17 @@ +import http from "@/api"; +import { ResPage } from "@/api/interface/index"; +/** + * @name 订阅 + */ +//列表 +export const getSubscriptionListApi = (params: Record) => { + return http.post>(`SubscribeNotification/GetList`, params); +}; +//詳情 +export const getDetailsApi = (id: any) => { + return http.get(`SubscribeNotification/GetInfo/${id}`); +}; +//获取客户下拉列表(纯客户信息 不包含组织信息) +export const getCustomersNoOrgApi = (id: any) => { + return http.get(`SysConfig/GetCustomersNoOrg/${id}`); +}; diff --git a/src/api/modules/upload.ts b/src/api/modules/upload.ts new file mode 100644 index 0000000..d79f0ed --- /dev/null +++ b/src/api/modules/upload.ts @@ -0,0 +1,18 @@ +import { Upload } from "@/api/interface/index"; +import { PORT1 } from "@/api/config/servicePort"; +import http from "@/api"; + +/** + * @name 文件上传模块 + */ +// 图片上传 +export const uploadImg = (formData: any) => { + //params: FormData + let url = import.meta.env.VITE_APP_API_BASEURL + import.meta.env.VITE_APP_API_VERSION + "/Upload?type=material&name="; + return http.post(url, formData); +}; + +// 视频上传 +export const uploadVideo = (params: FormData) => { + return http.post(PORT1 + `/file/upload/video`, params); +}; diff --git a/src/assets/fonto/demo.css b/src/assets/fonto/demo.css new file mode 100644 index 0000000..a67054a --- /dev/null +++ b/src/assets/fonto/demo.css @@ -0,0 +1,539 @@ +/* Logo 字体 */ +@font-face { + font-family: "iconfont logo"; + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); +} + +.logo { + font-family: "iconfont logo"; + font-size: 160px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* tabs */ +.nav-tabs { + position: relative; +} + +.nav-tabs .nav-more { + position: absolute; + right: 0; + bottom: 0; + height: 42px; + line-height: 42px; + color: #666; +} + +#tabs { + border-bottom: 1px solid #eee; +} + +#tabs li { + cursor: pointer; + width: 100px; + height: 40px; + line-height: 40px; + text-align: center; + font-size: 16px; + border-bottom: 2px solid transparent; + position: relative; + z-index: 1; + margin-bottom: -1px; + color: #666; +} + + +#tabs .active { + border-bottom-color: #f00; + color: #222; +} + +.tab-container .content { + display: none; +} + +/* 页面布局 */ +.main { + padding: 30px 100px; + width: 960px; + margin: 0 auto; +} + +.main .logo { + color: #333; + text-align: left; + margin-bottom: 30px; + line-height: 1; + height: 110px; + margin-top: -50px; + overflow: hidden; + *zoom: 1; +} + +.main .logo a { + font-size: 160px; + color: #333; +} + +.helps { + margin-top: 40px; +} + +.helps pre { + padding: 20px; + margin: 10px 0; + border: solid 1px #e7e1cd; + background-color: #fffdef; + overflow: auto; +} + +.icon_lists { + width: 100% !important; + overflow: hidden; + *zoom: 1; +} + +.icon_lists li { + width: 100px; + margin-bottom: 10px; + margin-right: 20px; + text-align: center; + list-style: none !important; + cursor: default; +} + +.icon_lists li .code-name { + line-height: 1.2; +} + +.icon_lists .icon { + display: block; + height: 100px; + line-height: 100px; + font-size: 42px; + margin: 10px auto; + color: #333; + -webkit-transition: font-size 0.25s linear, width 0.25s linear; + -moz-transition: font-size 0.25s linear, width 0.25s linear; + transition: font-size 0.25s linear, width 0.25s linear; +} + +.icon_lists .icon:hover { + font-size: 100px; +} + +.icon_lists .svg-icon { + /* 通过设置 font-size 来改变图标大小 */ + width: 1em; + /* 图标和文字相邻时,垂直对齐 */ + vertical-align: -0.15em; + /* 通过设置 color 来改变 SVG 的颜色/fill */ + fill: currentColor; + /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 + normalize.css 中也包含这行 */ + overflow: hidden; +} + +.icon_lists li .name, +.icon_lists li .code-name { + color: #666; +} + +/* markdown 样式 */ +.markdown { + color: #666; + font-size: 14px; + line-height: 1.8; +} + +.highlight { + line-height: 1.5; +} + +.markdown img { + vertical-align: middle; + max-width: 100%; +} + +.markdown h1 { + color: #404040; + font-weight: 500; + line-height: 40px; + margin-bottom: 24px; +} + +.markdown h2, +.markdown h3, +.markdown h4, +.markdown h5, +.markdown h6 { + color: #404040; + margin: 1.6em 0 0.6em 0; + font-weight: 500; + clear: both; +} + +.markdown h1 { + font-size: 28px; +} + +.markdown h2 { + font-size: 22px; +} + +.markdown h3 { + font-size: 16px; +} + +.markdown h4 { + font-size: 14px; +} + +.markdown h5 { + font-size: 12px; +} + +.markdown h6 { + font-size: 12px; +} + +.markdown hr { + height: 1px; + border: 0; + background: #e9e9e9; + margin: 16px 0; + clear: both; +} + +.markdown p { + margin: 1em 0; +} + +.markdown>p, +.markdown>blockquote, +.markdown>.highlight, +.markdown>ol, +.markdown>ul { + width: 80%; +} + +.markdown ul>li { + list-style: circle; +} + +.markdown>ul li, +.markdown blockquote ul>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown>ul li p, +.markdown>ol li p { + margin: 0.6em 0; +} + +.markdown ol>li { + list-style: decimal; +} + +.markdown>ol li, +.markdown blockquote ol>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown code { + margin: 0 3px; + padding: 0 5px; + background: #eee; + border-radius: 3px; +} + +.markdown strong, +.markdown b { + font-weight: 600; +} + +.markdown>table { + border-collapse: collapse; + border-spacing: 0px; + empty-cells: show; + border: 1px solid #e9e9e9; + width: 95%; + margin-bottom: 24px; +} + +.markdown>table th { + white-space: nowrap; + color: #333; + font-weight: 600; +} + +.markdown>table th, +.markdown>table td { + border: 1px solid #e9e9e9; + padding: 8px 16px; + text-align: left; +} + +.markdown>table th { + background: #F7F7F7; +} + +.markdown blockquote { + font-size: 90%; + color: #999; + border-left: 4px solid #e9e9e9; + padding-left: 0.8em; + margin: 1em 0; +} + +.markdown blockquote p { + margin: 0; +} + +.markdown .anchor { + opacity: 0; + transition: opacity 0.3s ease; + margin-left: 8px; +} + +.markdown .waiting { + color: #ccc; +} + +.markdown h1:hover .anchor, +.markdown h2:hover .anchor, +.markdown h3:hover .anchor, +.markdown h4:hover .anchor, +.markdown h5:hover .anchor, +.markdown h6:hover .anchor { + opacity: 1; + display: inline-block; +} + +.markdown>br, +.markdown>p>br { + clear: both; +} + + +.hljs { + display: block; + background: white; + padding: 0.5em; + color: #333333; + overflow-x: auto; +} + +.hljs-comment, +.hljs-meta { + color: #969896; +} + +.hljs-string, +.hljs-variable, +.hljs-template-variable, +.hljs-strong, +.hljs-emphasis, +.hljs-quote { + color: #df5000; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-type { + color: #a71d5d; +} + +.hljs-literal, +.hljs-symbol, +.hljs-bullet, +.hljs-attribute { + color: #0086b3; +} + +.hljs-section, +.hljs-name { + color: #63a35c; +} + +.hljs-tag { + color: #333333; +} + +.hljs-title, +.hljs-attr, +.hljs-selector-id, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #795da3; +} + +.hljs-addition { + color: #55a532; + background-color: #eaffea; +} + +.hljs-deletion { + color: #bd2c00; + background-color: #ffecec; +} + +.hljs-link { + text-decoration: underline; +} + +/* 代码高亮 */ +/* PrismJS 1.15.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre)>code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre)>code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} diff --git a/src/assets/fonto/demo_index.html b/src/assets/fonto/demo_index.html new file mode 100644 index 0000000..c118b0d --- /dev/null +++ b/src/assets/fonto/demo_index.html @@ -0,0 +1,1612 @@ + + + + + iconfont Demo + + + + + + + + + + + + + +
+

+ + +

+ +
+
+
    + +
  • + +
    发货出库
    +
    &#xe670;
    +
  • + +
  • + +
    收货入库
    +
    &#xe671;
    +
  • + +
  • + +
    其他库内操作
    +
    &#xe672;
    +
  • + +
  • + +
    盘点
    +
    &#xe673;
    +
  • + +
  • + +
    报表
    +
    &#xe674;
    +
  • + +
  • + +
    收起icon
    +
    &#xe66e;
    +
  • + +
  • + +
    展开icon
    +
    &#xe66a;
    +
  • + +
  • + +
    克隆
    +
    &#xe66b;
    +
  • + +
  • + +
    保存
    +
    &#xe66c;
    +
  • + +
  • + +
    日历icon
    +
    &#xe66d;
    +
  • + +
  • + +
    添加
    +
    &#xe65e;
    +
  • + +
  • + +
    复制
    +
    &#xe65d;
    +
  • + +
  • + +
    关闭
    +
    &#xe65b;
    +
  • + +
  • + +
    编辑
    +
    &#xe65a;
    +
  • + +
  • + +
    税务管理
    +
    &#xe649;
    +
  • + +
  • + +
    成本管理
    +
    &#xe645;
    +
  • + +
  • + +
    应收款管理
    +
    &#xe642;
    +
  • + +
  • + +
    资金管理
    +
    &#xe643;
    +
  • + +
  • + +
    费用管理
    +
    &#xe644;
    +
  • + +
  • + +
    出纳管理
    +
    &#xe646;
    +
  • + +
  • + +
    资产管理
    +
    &#xe647;
    +
  • + +
  • + +
    总账
    +
    &#xe648;
    +
  • + +
  • + +
    应付款管理
    +
    &#xe64a;
    +
  • + +
  • + +
    财务
    +
    &#xe641;
    +
  • + +
  • + +
    导出
    +
    &#xe63f;
    +
  • + +
  • + +
    人民币
    +
    &#xe63b;
    +
  • + +
  • + +
    下载为空
    +
    &#xe63a;
    +
  • + +
  • + +
    删除
    +
    &#xe639;
    +
  • + +
  • + +
    导出
    +
    &#xe636;
    +
  • + +
  • + +
    下单
    +
    &#xe637;
    +
  • + +
  • + +
    批量
    +
    &#xe638;
    +
  • + +
  • + +
    折线图
    +
    &#xe635;
    +
  • + +
  • + +
    更多
    +
    &#xe631;
    +
  • + +
  • + +
    成功
    +
    &#xe630;
    +
  • + +
  • + +
    示警
    +
    &#xe62f;
    +
  • + +
  • + +
    信息
    +
    &#xe62e;
    +
  • + +
  • + +
    任务为空
    +
    &#xe62d;
    +
  • + +
  • + +
    浏览记录为空
    +
    &#xe62c;
    +
  • + +
  • + +
    清除
    +
    &#xe62b;
    +
  • + +
  • + +
    左边
    +
    &#xe629;
    +
  • + +
  • + +
    右边
    +
    &#xe62a;
    +
  • + +
  • + +
    选中
    +
    &#xe628;
    +
  • + +
  • + +
    双箭头收起-上
    +
    &#xe626;
    +
  • + +
  • + +
    双箭头展开-下
    +
    &#xe627;
    +
  • + +
  • + +
    刷新
    +
    &#xe625;
    +
  • + +
  • + +
    添加
    +
    &#xe624;
    +
  • + +
  • + +
    保存
    +
    &#xe623;
    +
  • + +
  • + +
    右-展开更多
    +
    &#xe61d;
    +
  • + +
  • + +
    左-展开更多
    +
    &#xe61e;
    +
  • + +
  • + +
    下-展开
    +
    &#xe61f;
    +
  • + +
  • + +
    关闭
    +
    &#xe620;
    +
  • + +
  • + +
    报表
    +
    &#xe612;
    +
  • + +
  • + +
    采购
    +
    &#xe613;
    +
  • + +
  • + +
    仓库
    +
    &#xe614;
    +
  • + +
  • + +
    生产
    +
    &#xe615;
    +
  • + +
  • + +
    销售
    +
    &#xe616;
    +
  • + +
  • + +
    条码
    +
    &#xe617;
    +
  • + +
  • + +
    物料
    +
    &#xe618;
    +
  • + +
  • + +
    委外
    +
    &#xe619;
    +
  • + +
  • + +
    供应商
    +
    &#xe61a;
    +
  • + +
  • + +
    设置
    +
    &#xe61b;
    +
  • + +
  • + +
    211
    +
    &#xe61c;
    +
  • + +
+
+

Unicode 引用

+
+ +

Unicode 是字体在网页端最原始的应用方式,特点是:

+
    +
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • +
  • 默认情况下不支持多色,直接添加多色图标会自动去色。
  • +
+
+

注意:新版 iconfont 支持两种方式引用多色图标:SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)

+
+

Unicode 使用步骤如下:

+

第一步:拷贝项目下面生成的 @font-face

+
@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.woff2?t=1700032659797') format('woff2'),
+       url('iconfont.woff?t=1700032659797') format('woff'),
+       url('iconfont.ttf?t=1700032659797') format('truetype');
+}
+
+

第二步:定义使用 iconfont 的样式

+
.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+

第三步:挑选相应图标并获取字体编码,应用于页面

+
+<span class="iconfont">&#x33;</span>
+
+
+

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    + 发货出库 +
    +
    .icon-fahuochuku +
    +
  • + +
  • + +
    + 收货入库 +
    +
    .icon-shouhuoruku +
    +
  • + +
  • + +
    + 其他库内操作 +
    +
    .icon-qitakuneicaozuo +
    +
  • + +
  • + +
    + 盘点 +
    +
    .icon-pandian +
    +
  • + +
  • + +
    + 报表 +
    +
    .icon-baobiao1 +
    +
  • + +
  • + +
    + 收起icon +
    +
    .icon-shouqiicon +
    +
  • + +
  • + +
    + 展开icon +
    +
    .icon-zhankaiicon +
    +
  • + +
  • + +
    + 克隆 +
    +
    .icon-kelong +
    +
  • + +
  • + +
    + 保存 +
    +
    .icon-baocun1 +
    +
  • + +
  • + +
    + 日历icon +
    +
    .icon-riliicon +
    +
  • + +
  • + +
    + 添加 +
    +
    .icon-tianjia1 +
    +
  • + +
  • + +
    + 复制 +
    +
    .icon-fuzhi +
    +
  • + +
  • + +
    + 关闭 +
    +
    .icon-guanbi1 +
    +
  • + +
  • + +
    + 编辑 +
    +
    .icon-bianji1 +
    +
  • + +
  • + +
    + 税务管理 +
    +
    .icon-shuiwuguanli +
    +
  • + +
  • + +
    + 成本管理 +
    +
    .icon-chengbenguanli +
    +
  • + +
  • + +
    + 应收款管理 +
    +
    .icon-yingshoukuanguanli +
    +
  • + +
  • + +
    + 资金管理 +
    +
    .icon-zijinguanli +
    +
  • + +
  • + +
    + 费用管理 +
    +
    .icon-feiyongguanli +
    +
  • + +
  • + +
    + 出纳管理 +
    +
    .icon-chunaguanli +
    +
  • + +
  • + +
    + 资产管理 +
    +
    .icon-zichanguanli +
    +
  • + +
  • + +
    + 总账 +
    +
    .icon-zongzhang +
    +
  • + +
  • + +
    + 应付款管理 +
    +
    .icon-yingfukuanguanli +
    +
  • + +
  • + +
    + 财务 +
    +
    .icon-caiwu +
    +
  • + +
  • + +
    + 导出 +
    +
    .icon-daochu1 +
    +
  • + +
  • + +
    + 人民币 +
    +
    .icon-renminbi +
    +
  • + +
  • + +
    + 下载为空 +
    +
    .icon-xiazaiweikong +
    +
  • + +
  • + +
    + 删除 +
    +
    .icon-shanchu +
    +
  • + +
  • + +
    + 导出 +
    +
    .icon-daochu +
    +
  • + +
  • + +
    + 下单 +
    +
    .icon-xiadan +
    +
  • + +
  • + +
    + 批量 +
    +
    .icon-piliang +
    +
  • + +
  • + +
    + 折线图 +
    +
    .icon-zhexiantu +
    +
  • + +
  • + +
    + 更多 +
    +
    .icon-gengduo +
    +
  • + +
  • + +
    + 成功 +
    +
    .icon-chenggong +
    +
  • + +
  • + +
    + 示警 +
    +
    .icon-shijing +
    +
  • + +
  • + +
    + 信息 +
    +
    .icon-xinxi +
    +
  • + +
  • + +
    + 任务为空 +
    +
    .icon-renwuweikong +
    +
  • + +
  • + +
    + 浏览记录为空 +
    +
    .icon-liulanjiluweikong +
    +
  • + +
  • + +
    + 清除 +
    +
    .icon-qingchu +
    +
  • + +
  • + +
    + 左边 +
    +
    .icon-zuobian +
    +
  • + +
  • + +
    + 右边 +
    +
    .icon-youbian +
    +
  • + +
  • + +
    + 选中 +
    +
    .icon-xuanzhong +
    +
  • + +
  • + +
    + 双箭头收起-上 +
    +
    .icon-shuangjiantoushouqi-shang +
    +
  • + +
  • + +
    + 双箭头展开-下 +
    +
    .icon-shuangjiantouzhankai-xia +
    +
  • + +
  • + +
    + 刷新 +
    +
    .icon-shuaxin +
    +
  • + +
  • + +
    + 添加 +
    +
    .icon-tianjia +
    +
  • + +
  • + +
    + 保存 +
    +
    .icon-baocun +
    +
  • + +
  • + +
    + 右-展开更多 +
    +
    .icon-you-zhankaigengduo +
    +
  • + +
  • + +
    + 左-展开更多 +
    +
    .icon-zuo-zhankaigengduo +
    +
  • + +
  • + +
    + 下-展开 +
    +
    .icon-xia-zhankai +
    +
  • + +
  • + +
    + 关闭 +
    +
    .icon-guanbi +
    +
  • + +
  • + +
    + 报表 +
    +
    .icon-baobiao +
    +
  • + +
  • + +
    + 采购 +
    +
    .icon-caigou +
    +
  • + +
  • + +
    + 仓库 +
    +
    .icon-cangku +
    +
  • + +
  • + +
    + 生产 +
    +
    .icon-shengchan +
    +
  • + +
  • + +
    + 销售 +
    +
    .icon-xiaoshou +
    +
  • + +
  • + +
    + 条码 +
    +
    .icon-tiaoma +
    +
  • + +
  • + +
    + 物料 +
    +
    .icon-wuliao +
    +
  • + +
  • + +
    + 委外 +
    +
    .icon-weiwai +
    +
  • + +
  • + +
    + 供应商 +
    +
    .icon-gongyingshang +
    +
  • + +
  • + +
    + 设置 +
    +
    .icon-shezhi +
    +
  • + +
  • + +
    + 211 +
    +
    .icon-a-211 +
    +
  • + +
+
+

font-class 引用

+
+ +

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

+

与 Unicode 使用方式相比,具有如下特点:

+
    +
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • +
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 fontclass 代码:

+
<link rel="stylesheet" href="./iconfont.css">
+
+

第二步:挑选相应图标并获取类名,应用于页面:

+
<span class="iconfont icon-xxx"></span>
+
+
+

" + iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    发货出库
    +
    #icon-fahuochuku
    +
  • + +
  • + +
    收货入库
    +
    #icon-shouhuoruku
    +
  • + +
  • + +
    其他库内操作
    +
    #icon-qitakuneicaozuo
    +
  • + +
  • + +
    盘点
    +
    #icon-pandian
    +
  • + +
  • + +
    报表
    +
    #icon-baobiao1
    +
  • + +
  • + +
    收起icon
    +
    #icon-shouqiicon
    +
  • + +
  • + +
    展开icon
    +
    #icon-zhankaiicon
    +
  • + +
  • + +
    克隆
    +
    #icon-kelong
    +
  • + +
  • + +
    保存
    +
    #icon-baocun1
    +
  • + +
  • + +
    日历icon
    +
    #icon-riliicon
    +
  • + +
  • + +
    添加
    +
    #icon-tianjia1
    +
  • + +
  • + +
    复制
    +
    #icon-fuzhi
    +
  • + +
  • + +
    关闭
    +
    #icon-guanbi1
    +
  • + +
  • + +
    编辑
    +
    #icon-bianji1
    +
  • + +
  • + +
    税务管理
    +
    #icon-shuiwuguanli
    +
  • + +
  • + +
    成本管理
    +
    #icon-chengbenguanli
    +
  • + +
  • + +
    应收款管理
    +
    #icon-yingshoukuanguanli
    +
  • + +
  • + +
    资金管理
    +
    #icon-zijinguanli
    +
  • + +
  • + +
    费用管理
    +
    #icon-feiyongguanli
    +
  • + +
  • + +
    出纳管理
    +
    #icon-chunaguanli
    +
  • + +
  • + +
    资产管理
    +
    #icon-zichanguanli
    +
  • + +
  • + +
    总账
    +
    #icon-zongzhang
    +
  • + +
  • + +
    应付款管理
    +
    #icon-yingfukuanguanli
    +
  • + +
  • + +
    财务
    +
    #icon-caiwu
    +
  • + +
  • + +
    导出
    +
    #icon-daochu1
    +
  • + +
  • + +
    人民币
    +
    #icon-renminbi
    +
  • + +
  • + +
    下载为空
    +
    #icon-xiazaiweikong
    +
  • + +
  • + +
    删除
    +
    #icon-shanchu
    +
  • + +
  • + +
    导出
    +
    #icon-daochu
    +
  • + +
  • + +
    下单
    +
    #icon-xiadan
    +
  • + +
  • + +
    批量
    +
    #icon-piliang
    +
  • + +
  • + +
    折线图
    +
    #icon-zhexiantu
    +
  • + +
  • + +
    更多
    +
    #icon-gengduo
    +
  • + +
  • + +
    成功
    +
    #icon-chenggong
    +
  • + +
  • + +
    示警
    +
    #icon-shijing
    +
  • + +
  • + +
    信息
    +
    #icon-xinxi
    +
  • + +
  • + +
    任务为空
    +
    #icon-renwuweikong
    +
  • + +
  • + +
    浏览记录为空
    +
    #icon-liulanjiluweikong
    +
  • + +
  • + +
    清除
    +
    #icon-qingchu
    +
  • + +
  • + +
    左边
    +
    #icon-zuobian
    +
  • + +
  • + +
    右边
    +
    #icon-youbian
    +
  • + +
  • + +
    选中
    +
    #icon-xuanzhong
    +
  • + +
  • + +
    双箭头收起-上
    +
    #icon-shuangjiantoushouqi-shang
    +
  • + +
  • + +
    双箭头展开-下
    +
    #icon-shuangjiantouzhankai-xia
    +
  • + +
  • + +
    刷新
    +
    #icon-shuaxin
    +
  • + +
  • + +
    添加
    +
    #icon-tianjia
    +
  • + +
  • + +
    保存
    +
    #icon-baocun
    +
  • + +
  • + +
    右-展开更多
    +
    #icon-you-zhankaigengduo
    +
  • + +
  • + +
    左-展开更多
    +
    #icon-zuo-zhankaigengduo
    +
  • + +
  • + +
    下-展开
    +
    #icon-xia-zhankai
    +
  • + +
  • + +
    关闭
    +
    #icon-guanbi
    +
  • + +
  • + +
    报表
    +
    #icon-baobiao
    +
  • + +
  • + +
    采购
    +
    #icon-caigou
    +
  • + +
  • + +
    仓库
    +
    #icon-cangku
    +
  • + +
  • + +
    生产
    +
    #icon-shengchan
    +
  • + +
  • + +
    销售
    +
    #icon-xiaoshou
    +
  • + +
  • + +
    条码
    +
    #icon-tiaoma
    +
  • + +
  • + +
    物料
    +
    #icon-wuliao
    +
  • + +
  • + +
    委外
    +
    #icon-weiwai
    +
  • + +
  • + +
    供应商
    +
    #icon-gongyingshang
    +
  • + +
  • + +
    设置
    +
    #icon-shezhi
    +
  • + +
  • + +
    211
    +
    #icon-a-211
    +
  • + +
+
+

Symbol 引用

+
+ +

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 + 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

+
    +
  • 支持多色图标了,不再受单色限制。
  • +
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • +
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • +
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 symbol 代码:

+
<script src="./iconfont.js"></script>
+
+

第二步:加入通用 CSS 代码(引入一次就行):

+
<style>
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>
+
+

第三步:挑选相应图标并获取类名,应用于页面:

+
<svg class="icon" aria-hidden="true">
+  <use xlink:href="#icon-xxx"></use>
+</svg>
+
+
+
+ +
+
+ + + diff --git a/src/assets/fonto/iconfont.css b/src/assets/fonto/iconfont.css new file mode 100644 index 0000000..185a98d --- /dev/null +++ b/src/assets/fonto/iconfont.css @@ -0,0 +1,263 @@ +@font-face { + font-family: "iconfont"; /* Project id 2863944 */ + src: url('iconfont.woff2?t=1700032659797') format('woff2'), + url('iconfont.woff?t=1700032659797') format('woff'), + url('iconfont.ttf?t=1700032659797') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-fahuochuku:before { + content: "\e670"; +} + +.icon-shouhuoruku:before { + content: "\e671"; +} + +.icon-qitakuneicaozuo:before { + content: "\e672"; +} + +.icon-pandian:before { + content: "\e673"; +} + +.icon-baobiao1:before { + content: "\e674"; +} + +.icon-shouqiicon:before { + content: "\e66e"; +} + +.icon-zhankaiicon:before { + content: "\e66a"; +} + +.icon-kelong:before { + content: "\e66b"; +} + +.icon-baocun1:before { + content: "\e66c"; +} + +.icon-riliicon:before { + content: "\e66d"; +} + +.icon-tianjia1:before { + content: "\e65e"; +} + +.icon-fuzhi:before { + content: "\e65d"; +} + +.icon-guanbi1:before { + content: "\e65b"; +} + +.icon-bianji1:before { + content: "\e65a"; +} + +.icon-shuiwuguanli:before { + content: "\e649"; +} + +.icon-chengbenguanli:before { + content: "\e645"; +} + +.icon-yingshoukuanguanli:before { + content: "\e642"; +} + +.icon-zijinguanli:before { + content: "\e643"; +} + +.icon-feiyongguanli:before { + content: "\e644"; +} + +.icon-chunaguanli:before { + content: "\e646"; +} + +.icon-zichanguanli:before { + content: "\e647"; +} + +.icon-zongzhang:before { + content: "\e648"; +} + +.icon-yingfukuanguanli:before { + content: "\e64a"; +} + +.icon-caiwu:before { + content: "\e641"; +} + +.icon-daochu1:before { + content: "\e63f"; +} + +.icon-renminbi:before { + content: "\e63b"; +} + +.icon-xiazaiweikong:before { + content: "\e63a"; +} + +.icon-shanchu:before { + content: "\e639"; +} + +.icon-daochu:before { + content: "\e636"; +} + +.icon-xiadan:before { + content: "\e637"; +} + +.icon-piliang:before { + content: "\e638"; +} + +.icon-zhexiantu:before { + content: "\e635"; +} + +.icon-gengduo:before { + content: "\e631"; +} + +.icon-chenggong:before { + content: "\e630"; +} + +.icon-shijing:before { + content: "\e62f"; +} + +.icon-xinxi:before { + content: "\e62e"; +} + +.icon-renwuweikong:before { + content: "\e62d"; +} + +.icon-liulanjiluweikong:before { + content: "\e62c"; +} + +.icon-qingchu:before { + content: "\e62b"; +} + +.icon-zuobian:before { + content: "\e629"; +} + +.icon-youbian:before { + content: "\e62a"; +} + +.icon-xuanzhong:before { + content: "\e628"; +} + +.icon-shuangjiantoushouqi-shang:before { + content: "\e626"; +} + +.icon-shuangjiantouzhankai-xia:before { + content: "\e627"; +} + +.icon-shuaxin:before { + content: "\e625"; +} + +.icon-tianjia:before { + content: "\e624"; +} + +.icon-baocun:before { + content: "\e623"; +} + +.icon-you-zhankaigengduo:before { + content: "\e61d"; +} + +.icon-zuo-zhankaigengduo:before { + content: "\e61e"; +} + +.icon-xia-zhankai:before { + content: "\e61f"; +} + +.icon-guanbi:before { + content: "\e620"; +} + +.icon-baobiao:before { + content: "\e612"; +} + +.icon-caigou:before { + content: "\e613"; +} + +.icon-cangku:before { + content: "\e614"; +} + +.icon-shengchan:before { + content: "\e615"; +} + +.icon-xiaoshou:before { + content: "\e616"; +} + +.icon-tiaoma:before { + content: "\e617"; +} + +.icon-wuliao:before { + content: "\e618"; +} + +.icon-weiwai:before { + content: "\e619"; +} + +.icon-gongyingshang:before { + content: "\e61a"; +} + +.icon-shezhi:before { + content: "\e61b"; +} + +.icon-a-211:before { + content: "\e61c"; +} + diff --git a/src/assets/fonto/iconfont.js b/src/assets/fonto/iconfont.js new file mode 100644 index 0000000..cb3a0ce --- /dev/null +++ b/src/assets/fonto/iconfont.js @@ -0,0 +1 @@ +window._iconfont_svg_string_2863944='',function(c){var h=(h=document.getElementsByTagName("script"))[h.length-1],a=h.getAttribute("data-injectcss"),h=h.getAttribute("data-disable-injectsvg");if(!h){var l,t,i,v,p,o=function(h,a){a.parentNode.insertBefore(h,a)};if(a&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(h){console&&console.log(h)}}l=function(){var h,a=document.createElement("div");a.innerHTML=c._iconfont_svg_string_2863944,(a=a.getElementsByTagName("svg")[0])&&(a.setAttribute("aria-hidden","true"),a.style.position="absolute",a.style.width=0,a.style.height=0,a.style.overflow="hidden",a=a,(h=document.body).firstChild?o(a,h.firstChild):h.appendChild(a))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(l,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),l()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(i=l,v=c.document,p=!1,d(),v.onreadystatechange=function(){"complete"==v.readyState&&(v.onreadystatechange=null,z())})}function z(){p||(p=!0,i())}function d(){try{v.documentElement.doScroll("left")}catch(h){return void setTimeout(d,50)}z()}}(window); \ No newline at end of file diff --git a/src/assets/fonto/iconfont.json b/src/assets/fonto/iconfont.json new file mode 100644 index 0000000..1f7674c --- /dev/null +++ b/src/assets/fonto/iconfont.json @@ -0,0 +1,443 @@ +{ + "id": "2863944", + "name": "OPS", + "font_family": "iconfont", + "css_prefix_text": "icon-", + "description": "", + "glyphs": [ + { + "icon_id": "38127193", + "name": "发货出库", + "font_class": "fahuochuku", + "unicode": "e670", + "unicode_decimal": 58992 + }, + { + "icon_id": "38127192", + "name": "收货入库", + "font_class": "shouhuoruku", + "unicode": "e671", + "unicode_decimal": 58993 + }, + { + "icon_id": "38127191", + "name": "其他库内操作", + "font_class": "qitakuneicaozuo", + "unicode": "e672", + "unicode_decimal": 58994 + }, + { + "icon_id": "38127190", + "name": "盘点", + "font_class": "pandian", + "unicode": "e673", + "unicode_decimal": 58995 + }, + { + "icon_id": "38127189", + "name": "报表", + "font_class": "baobiao1", + "unicode": "e674", + "unicode_decimal": 58996 + }, + { + "icon_id": "36084927", + "name": "收起icon", + "font_class": "shouqiicon", + "unicode": "e66e", + "unicode_decimal": 58990 + }, + { + "icon_id": "36084853", + "name": "展开icon", + "font_class": "zhankaiicon", + "unicode": "e66a", + "unicode_decimal": 58986 + }, + { + "icon_id": "36084854", + "name": "克隆", + "font_class": "kelong", + "unicode": "e66b", + "unicode_decimal": 58987 + }, + { + "icon_id": "36084855", + "name": "保存", + "font_class": "baocun1", + "unicode": "e66c", + "unicode_decimal": 58988 + }, + { + "icon_id": "36084856", + "name": "日历icon", + "font_class": "riliicon", + "unicode": "e66d", + "unicode_decimal": 58989 + }, + { + "icon_id": "32937331", + "name": "添加", + "font_class": "tianjia1", + "unicode": "e65e", + "unicode_decimal": 58974 + }, + { + "icon_id": "32936674", + "name": "复制", + "font_class": "fuzhi", + "unicode": "e65d", + "unicode_decimal": 58973 + }, + { + "icon_id": "31372064", + "name": "关闭", + "font_class": "guanbi1", + "unicode": "e65b", + "unicode_decimal": 58971 + }, + { + "icon_id": "31254227", + "name": "编辑", + "font_class": "bianji1", + "unicode": "e65a", + "unicode_decimal": 58970 + }, + { + "icon_id": "28767114", + "name": "税务管理", + "font_class": "shuiwuguanli", + "unicode": "e649", + "unicode_decimal": 58953 + }, + { + "icon_id": "28758569", + "name": "成本管理", + "font_class": "chengbenguanli", + "unicode": "e645", + "unicode_decimal": 58949 + }, + { + "icon_id": "28756346", + "name": "应收款管理", + "font_class": "yingshoukuanguanli", + "unicode": "e642", + "unicode_decimal": 58946 + }, + { + "icon_id": "28756347", + "name": "资金管理", + "font_class": "zijinguanli", + "unicode": "e643", + "unicode_decimal": 58947 + }, + { + "icon_id": "28756349", + "name": "费用管理", + "font_class": "feiyongguanli", + "unicode": "e644", + "unicode_decimal": 58948 + }, + { + "icon_id": "28756351", + "name": "出纳管理", + "font_class": "chunaguanli", + "unicode": "e646", + "unicode_decimal": 58950 + }, + { + "icon_id": "28756352", + "name": "资产管理", + "font_class": "zichanguanli", + "unicode": "e647", + "unicode_decimal": 58951 + }, + { + "icon_id": "28756353", + "name": "总账", + "font_class": "zongzhang", + "unicode": "e648", + "unicode_decimal": 58952 + }, + { + "icon_id": "28756355", + "name": "应付款管理", + "font_class": "yingfukuanguanli", + "unicode": "e64a", + "unicode_decimal": 58954 + }, + { + "icon_id": "28442176", + "name": "财务", + "font_class": "caiwu", + "unicode": "e641", + "unicode_decimal": 58945 + }, + { + "icon_id": "28373960", + "name": "导出", + "font_class": "daochu1", + "unicode": "e63f", + "unicode_decimal": 58943 + }, + { + "icon_id": "28043356", + "name": "人民币", + "font_class": "renminbi", + "unicode": "e63b", + "unicode_decimal": 58939 + }, + { + "icon_id": "27909200", + "name": "下载为空", + "font_class": "xiazaiweikong", + "unicode": "e63a", + "unicode_decimal": 58938 + }, + { + "icon_id": "26973680", + "name": "删除", + "font_class": "shanchu", + "unicode": "e639", + "unicode_decimal": 58937 + }, + { + "icon_id": "26955368", + "name": "导出", + "font_class": "daochu", + "unicode": "e636", + "unicode_decimal": 58934 + }, + { + "icon_id": "26955369", + "name": "下单", + "font_class": "xiadan", + "unicode": "e637", + "unicode_decimal": 58935 + }, + { + "icon_id": "26955370", + "name": "批量", + "font_class": "piliang", + "unicode": "e638", + "unicode_decimal": 58936 + }, + { + "icon_id": "26954331", + "name": "折线图", + "font_class": "zhexiantu", + "unicode": "e635", + "unicode_decimal": 58933 + }, + { + "icon_id": "25254824", + "name": "更多", + "font_class": "gengduo", + "unicode": "e631", + "unicode_decimal": 58929 + }, + { + "icon_id": "25181240", + "name": "成功", + "font_class": "chenggong", + "unicode": "e630", + "unicode_decimal": 58928 + }, + { + "icon_id": "25181198", + "name": "示警", + "font_class": "shijing", + "unicode": "e62f", + "unicode_decimal": 58927 + }, + { + "icon_id": "25181181", + "name": "信息", + "font_class": "xinxi", + "unicode": "e62e", + "unicode_decimal": 58926 + }, + { + "icon_id": "25176785", + "name": "任务为空", + "font_class": "renwuweikong", + "unicode": "e62d", + "unicode_decimal": 58925 + }, + { + "icon_id": "25176783", + "name": "浏览记录为空", + "font_class": "liulanjiluweikong", + "unicode": "e62c", + "unicode_decimal": 58924 + }, + { + "icon_id": "25162308", + "name": "清除", + "font_class": "qingchu", + "unicode": "e62b", + "unicode_decimal": 58923 + }, + { + "icon_id": "25148507", + "name": "左边", + "font_class": "zuobian", + "unicode": "e629", + "unicode_decimal": 58921 + }, + { + "icon_id": "25148508", + "name": "右边", + "font_class": "youbian", + "unicode": "e62a", + "unicode_decimal": 58922 + }, + { + "icon_id": "25100884", + "name": "选中", + "font_class": "xuanzhong", + "unicode": "e628", + "unicode_decimal": 58920 + }, + { + "icon_id": "25097364", + "name": "双箭头收起-上", + "font_class": "shuangjiantoushouqi-shang", + "unicode": "e626", + "unicode_decimal": 58918 + }, + { + "icon_id": "25097365", + "name": "双箭头展开-下", + "font_class": "shuangjiantouzhankai-xia", + "unicode": "e627", + "unicode_decimal": 58919 + }, + { + "icon_id": "25097087", + "name": "刷新", + "font_class": "shuaxin", + "unicode": "e625", + "unicode_decimal": 58917 + }, + { + "icon_id": "25097062", + "name": "添加", + "font_class": "tianjia", + "unicode": "e624", + "unicode_decimal": 58916 + }, + { + "icon_id": "25097053", + "name": "保存", + "font_class": "baocun", + "unicode": "e623", + "unicode_decimal": 58915 + }, + { + "icon_id": "24910721", + "name": "右-展开更多", + "font_class": "you-zhankaigengduo", + "unicode": "e61d", + "unicode_decimal": 58909 + }, + { + "icon_id": "24910731", + "name": "左-展开更多", + "font_class": "zuo-zhankaigengduo", + "unicode": "e61e", + "unicode_decimal": 58910 + }, + { + "icon_id": "24910740", + "name": "下-展开", + "font_class": "xia-zhankai", + "unicode": "e61f", + "unicode_decimal": 58911 + }, + { + "icon_id": "24910742", + "name": "关闭", + "font_class": "guanbi", + "unicode": "e620", + "unicode_decimal": 58912 + }, + { + "icon_id": "24903722", + "name": "报表", + "font_class": "baobiao", + "unicode": "e612", + "unicode_decimal": 58898 + }, + { + "icon_id": "24903723", + "name": "采购", + "font_class": "caigou", + "unicode": "e613", + "unicode_decimal": 58899 + }, + { + "icon_id": "24903733", + "name": "仓库", + "font_class": "cangku", + "unicode": "e614", + "unicode_decimal": 58900 + }, + { + "icon_id": "24903735", + "name": "生产", + "font_class": "shengchan", + "unicode": "e615", + "unicode_decimal": 58901 + }, + { + "icon_id": "24903736", + "name": "销售", + "font_class": "xiaoshou", + "unicode": "e616", + "unicode_decimal": 58902 + }, + { + "icon_id": "24903737", + "name": "条码", + "font_class": "tiaoma", + "unicode": "e617", + "unicode_decimal": 58903 + }, + { + "icon_id": "24903738", + "name": "物料", + "font_class": "wuliao", + "unicode": "e618", + "unicode_decimal": 58904 + }, + { + "icon_id": "24903739", + "name": "委外", + "font_class": "weiwai", + "unicode": "e619", + "unicode_decimal": 58905 + }, + { + "icon_id": "24903740", + "name": "供应商", + "font_class": "gongyingshang", + "unicode": "e61a", + "unicode_decimal": 58906 + }, + { + "icon_id": "24903741", + "name": "设置", + "font_class": "shezhi", + "unicode": "e61b", + "unicode_decimal": 58907 + }, + { + "icon_id": "24903806", + "name": "211", + "font_class": "a-211", + "unicode": "e61c", + "unicode_decimal": 58908 + } + ] +} diff --git a/src/assets/fonto/iconfont.ttf b/src/assets/fonto/iconfont.ttf new file mode 100644 index 0000000..2a711c3 Binary files /dev/null and b/src/assets/fonto/iconfont.ttf differ diff --git a/src/assets/fonto/iconfont.woff b/src/assets/fonto/iconfont.woff new file mode 100644 index 0000000..36d3026 Binary files /dev/null and b/src/assets/fonto/iconfont.woff differ diff --git a/src/assets/fonto/iconfont.woff2 b/src/assets/fonto/iconfont.woff2 new file mode 100644 index 0000000..16e60b8 Binary files /dev/null and b/src/assets/fonto/iconfont.woff2 differ diff --git a/src/assets/fonts/DIN.otf b/src/assets/fonts/DIN.otf new file mode 100644 index 0000000..3296d1e Binary files /dev/null and b/src/assets/fonts/DIN.otf differ diff --git a/src/assets/fonts/MetroDF.ttf b/src/assets/fonts/MetroDF.ttf new file mode 100644 index 0000000..9d31af4 Binary files /dev/null and b/src/assets/fonts/MetroDF.ttf differ diff --git a/src/assets/fonts/YouSheBiaoTiHei.ttf b/src/assets/fonts/YouSheBiaoTiHei.ttf new file mode 100644 index 0000000..3729151 Binary files /dev/null and b/src/assets/fonts/YouSheBiaoTiHei.ttf differ diff --git a/src/assets/fonts/font.scss b/src/assets/fonts/font.scss new file mode 100644 index 0000000..d08cf8c --- /dev/null +++ b/src/assets/fonts/font.scss @@ -0,0 +1,14 @@ +@font-face { + font-family: YouSheBiaoTiHei; + src: url("./YouSheBiaoTiHei.ttf"); +} + +@font-face { + font-family: MetroDF; + src: url("./MetroDF.ttf"); +} + +@font-face { + font-family: DIN; + src: url("./DIN.Otf"); +} diff --git a/src/assets/iconfont/iconfont.scss b/src/assets/iconfont/iconfont.scss new file mode 100644 index 0000000..24d0aaa --- /dev/null +++ b/src/assets/iconfont/iconfont.scss @@ -0,0 +1,38 @@ +@font-face { + font-family: iconfont; /* Project id 2667653 */ + src: url("iconfont.ttf?t=1663324025864") format("truetype"); +} +.iconfont { + font-family: iconfont !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + cursor: pointer; +} +.icon-xiaoxi::before { + font-size: 21.2px; + content: "\e61f"; +} +.icon-zhuti::before { + font-size: 22.4px; + content: "\e638"; +} +.icon-sousuo::before { + content: "\e611"; +} +.icon-contentright::before { + content: "\e8c9"; +} +.icon-contentleft::before { + content: "\e8ca"; +} +.icon-fangda::before { + content: "\e826"; +} +.icon-suoxiao::before { + content: "\e641"; +} +.icon-zhongyingwen::before { + content: "\e8cb"; +} diff --git a/src/assets/iconfont/iconfont.ttf b/src/assets/iconfont/iconfont.ttf new file mode 100644 index 0000000..75c0c87 Binary files /dev/null and b/src/assets/iconfont/iconfont.ttf differ diff --git a/src/assets/icons/xianxingdaoyu.svg b/src/assets/icons/xianxingdaoyu.svg new file mode 100644 index 0000000..edfac8d --- /dev/null +++ b/src/assets/icons/xianxingdaoyu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/xianxingdiqiu.svg b/src/assets/icons/xianxingdiqiu.svg new file mode 100644 index 0000000..e13cb00 --- /dev/null +++ b/src/assets/icons/xianxingdiqiu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/xianxingditu.svg b/src/assets/icons/xianxingditu.svg new file mode 100644 index 0000000..ef1bdda --- /dev/null +++ b/src/assets/icons/xianxingditu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/xianxingfanchuan.svg b/src/assets/icons/xianxingfanchuan.svg new file mode 100644 index 0000000..2c2da28 --- /dev/null +++ b/src/assets/icons/xianxingfanchuan.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/xianxingfeiji.svg b/src/assets/icons/xianxingfeiji.svg new file mode 100644 index 0000000..e4d9a87 --- /dev/null +++ b/src/assets/icons/xianxingfeiji.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/xianxinglvhangriji.svg b/src/assets/icons/xianxinglvhangriji.svg new file mode 100644 index 0000000..2e1e47d --- /dev/null +++ b/src/assets/icons/xianxinglvhangriji.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/xianxingtianqiyubao.svg b/src/assets/icons/xianxingtianqiyubao.svg new file mode 100644 index 0000000..3283580 --- /dev/null +++ b/src/assets/icons/xianxingtianqiyubao.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/xianxingxiangjipaizhao.svg b/src/assets/icons/xianxingxiangjipaizhao.svg new file mode 100644 index 0000000..93ff9f5 --- /dev/null +++ b/src/assets/icons/xianxingxiangjipaizhao.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/xianxingxiarilengyin.svg b/src/assets/icons/xianxingxiarilengyin.svg new file mode 100644 index 0000000..87132d1 --- /dev/null +++ b/src/assets/icons/xianxingxiarilengyin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/xianxingyoulun.svg b/src/assets/icons/xianxingyoulun.svg new file mode 100644 index 0000000..487e1ee --- /dev/null +++ b/src/assets/icons/xianxingyoulun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/xianxingzijiayou.svg b/src/assets/icons/xianxingzijiayou.svg new file mode 100644 index 0000000..449c610 --- /dev/null +++ b/src/assets/icons/xianxingzijiayou.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/images/403.png b/src/assets/images/403.png new file mode 100644 index 0000000..0c5ec7c Binary files /dev/null and b/src/assets/images/403.png differ diff --git a/src/assets/images/404.png b/src/assets/images/404.png new file mode 100644 index 0000000..2333586 Binary files /dev/null and b/src/assets/images/404.png differ diff --git a/src/assets/images/500.png b/src/assets/images/500.png new file mode 100644 index 0000000..6f3b6bf Binary files /dev/null and b/src/assets/images/500.png differ diff --git a/src/assets/images/login_bg.svg b/src/assets/images/login_bg.svg new file mode 100644 index 0000000..0a9514b --- /dev/null +++ b/src/assets/images/login_bg.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/login_left.png b/src/assets/images/login_left.png new file mode 100644 index 0000000..e9ebc11 Binary files /dev/null and b/src/assets/images/login_left.png differ diff --git a/src/assets/images/login_left1.png b/src/assets/images/login_left1.png new file mode 100644 index 0000000..eaaf3ab Binary files /dev/null and b/src/assets/images/login_left1.png differ diff --git a/src/assets/images/login_left2.png b/src/assets/images/login_left2.png new file mode 100644 index 0000000..0398053 Binary files /dev/null and b/src/assets/images/login_left2.png differ diff --git a/src/assets/images/login_left3.png b/src/assets/images/login_left3.png new file mode 100644 index 0000000..58e6e74 Binary files /dev/null and b/src/assets/images/login_left3.png differ diff --git a/src/assets/images/login_left4.png b/src/assets/images/login_left4.png new file mode 100644 index 0000000..051299d Binary files /dev/null and b/src/assets/images/login_left4.png differ diff --git a/src/assets/images/login_left5.png b/src/assets/images/login_left5.png new file mode 100644 index 0000000..7d9d430 Binary files /dev/null and b/src/assets/images/login_left5.png differ diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png new file mode 100644 index 0000000..9b62435 Binary files /dev/null and b/src/assets/images/logo.png differ diff --git a/src/assets/images/logo.svg b/src/assets/images/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/src/assets/images/logo.svg @@ -0,0 +1 @@ + diff --git a/src/assets/images/msg01.png b/src/assets/images/msg01.png new file mode 100644 index 0000000..6ecca0d Binary files /dev/null and b/src/assets/images/msg01.png differ diff --git a/src/assets/images/msg02.png b/src/assets/images/msg02.png new file mode 100644 index 0000000..52c890a Binary files /dev/null and b/src/assets/images/msg02.png differ diff --git a/src/assets/images/msg03.png b/src/assets/images/msg03.png new file mode 100644 index 0000000..389512f Binary files /dev/null and b/src/assets/images/msg03.png differ diff --git a/src/assets/images/msg04.png b/src/assets/images/msg04.png new file mode 100644 index 0000000..6868f74 Binary files /dev/null and b/src/assets/images/msg04.png differ diff --git a/src/assets/images/msg05.png b/src/assets/images/msg05.png new file mode 100644 index 0000000..f375ab0 Binary files /dev/null and b/src/assets/images/msg05.png differ diff --git a/src/assets/images/notData.png b/src/assets/images/notData.png new file mode 100644 index 0000000..c579a78 Binary files /dev/null and b/src/assets/images/notData.png differ diff --git a/src/assets/images/reviewed_ico.png b/src/assets/images/reviewed_ico.png new file mode 100644 index 0000000..facdf1f Binary files /dev/null and b/src/assets/images/reviewed_ico.png differ diff --git a/src/assets/images/welcome.png b/src/assets/images/welcome.png new file mode 100644 index 0000000..df138ab Binary files /dev/null and b/src/assets/images/welcome.png differ diff --git a/src/assets/json/authButtonList.json b/src/assets/json/authButtonList.json new file mode 100644 index 0000000..24257b6 --- /dev/null +++ b/src/assets/json/authButtonList.json @@ -0,0 +1,8 @@ +{ + "code": 200, + "data": { + "useProTable": ["add", "batchAdd", "export", "batchDelete", "status"], + "authButton": ["add", "edit", "delete", "import", "export"] + }, + "msg": "成功" +} diff --git a/src/assets/json/authMenuList.json b/src/assets/json/authMenuList.json new file mode 100644 index 0000000..93cf3e7 --- /dev/null +++ b/src/assets/json/authMenuList.json @@ -0,0 +1,464 @@ +{ + "code": 200, + "data": [ + { + "path": "/index", + "name": "home", + "component": "/home/index", + "hidden": true, + "children":[ + + ], + "meta": { + "icon": "", + "title": "首页", + "isKeepAlive": true + } + }, + { + "id": 105, + "name": "receiptAndWarehousing", + "path": "/receiptAndWarehousing", + "component": "/receiptAndWarehousing", + "icon": "", + "redirect": "", + "hidden": false, + "children":[{ + "id": 106, + "name": "receiptAndWarehousing", + "path": "/receiptAndWarehousing", + "component": "/receiptAndWarehousing", + "icon": "", + "redirect": "", + "hidden": false, + "children": [ + { + "id": 106, + "name": "ofInboundInstructionsList", + "path": "/receiptAndWarehousing/ofInboundInstructionsList/index", + "component": "/receiptAndWarehousing/ofInboundInstructionsList/index", + "hidden": false, + "children":[], + "meta": { + "title": "入库任务列表", + "icon": "", + "isKeepAlive": true + } + }, + { + "id": 107, + "pid": 105, + "module":11, + "name": "warehouseReceiptList", + "path": "/receiptAndWarehousing/warehouseReceiptList/index", + "component": "/receiptAndWarehousing/warehouseReceiptList/index", + "hidden": false, + "children":[], + "meta": { + "title": "入库单列表", + "icon": "", + "isKeepAlive": true + } + }, + { + "id": 108, + "name": "warehouseReceiptListDetails", + "path": "/receiptAndWarehousing/warehouseReceiptList/details", + "component": "/receiptAndWarehousing/warehouseReceiptList/details", + "hidden": true, + "children":[], + "meta": { + "title": "入库单详情", + "icon": "", + "isKeepAlive": true + } + } + ], + "meta": { + "title": "收货入库", + "icon": "icon-shouhuoruku" + } + }], + + "meta": { + "title": "入库", + "icon": "icon-shouhuoruku" + } + }, + { + "id": 115, + "name": "deliveryAndOutbound", + "path": "/deliveryAndOutbound", + "component": "/deliveryAndOutbound", + "icon": "icon-fahuochuku", + "redirect": "", + "hidden": false, + "children":[ + { + "id": 1151, + "name": "deliveryAndOutbound", + "path": "/deliveryAndOutbound", + "component": "/deliveryAndOutbound", + "icon": "icon-fahuochuku", + "redirect": "", + "hidden": false, + "meta": { + "title": "发货出库", + "icon": "icon-fahuochuku" + }, + "children": [ + { + "id": 1162, + "name": "outboundTaskList", + "path": "/deliveryAndOutbound/outboundTaskList/index", + "component": "/deliveryAndOutbound/outboundTaskList/index", + "hidden": false, + "children":[], + "meta": { + "title": "出库任务列表", + "icon": "", + "isKeepAlive": true + } + }, + { + "id": 118, + "name": "outboundOrderListDetails", + "path": "/deliveryAndOutbound/outboundOrderList/details", + "component": "/deliveryAndOutbound/outboundOrderList/details", + "hidden": true, + "children":[], + "meta": { + "title": "出库单详情", + "icon": "", + "isKeepAlive": true + } + }, + { + "id": 117, + "name": "outboundOrderList", + "path": "/deliveryAndOutbound/outboundOrderList/index", + "component": "/deliveryAndOutbound/outboundOrderList/index", + "hidden": false, + "children":[], + "meta": { + "title": "出库单列表", + "icon": "", + "isKeepAlive": true + } + } + ] + } + ], + "meta": { + "title": "出库", + "icon": "icon-fahuochuku" + } + }, + { + "id": 125, + "name": "inventory", + "path": "/inventory", + "component": "/inventory", + "icon": "icon-pandian", + "redirect": "", + "hidden": false, + "children":[ + { + "id": 1261, + "name": "inventory", + "path": "/inventory", + "component": "/inventory", + "icon": "icon-pandian", + "redirect": "", + "hidden": false, + "children": [ + { + "id": 1262, + "name": "inventoryList", + "path": "/inventory/inventoryList/index", + "component": "/inventory/inventoryList/index", + "hidden": false, + "children":[], + "meta": { + "title": "盘点列表", + "icon": "", + "isKeepAlive": true + } + } + ], + "meta": { + "title": "盘点管理", + "icon": "icon-pandian" + } + } + ], + "meta": { + "title": "盘点", + "icon": "icon-pandian" + } + }, + { + "id": 135, + "name": "reportForm", + "path": "/reportForm", + "component": "/reportForm", + "icon": "icon-baobiao1", + "redirect": "", + "hidden": false, + "children":[ + { + "id": 1361, + "name": "reportForm", + "path": "/reportForm", + "component": "/reportForm", + "icon": "icon-baobiao1", + "redirect": "", + "hidden": false, + "meta": { + "title": "报表管理", + "icon": "icon-baobiao1" + }, + "children": [ + { + "id": 1362, + "name": "immediately", + "path": "/reportForm/immediately/index", + "component": "/reportForm/immediately/index", + "hidden": false, + "children":[], + "meta": { + "title": "即时库存明细", + + "icon": "", + "isKeepAlive": true + } + }, + { + "id": 137, + "name": "material", + "path": "/reportForm/material/index", + "component": "/reportForm/material/index", + "hidden": false, + "children":[], + "meta": { + "title": "物料收发明细", + "icon": "", + "isKeepAlive": true + } + }, + { + "id": 138, + "name": "boxStorage", + "path": "/reportForm/boxStorage/index", + "component": "/reportForm/boxStorage/index", + "hidden": false, + "children":[], + "meta": { + "title": "箱库存查询", + "icon": "", + "isKeepAlive": true + } + } + ] + } + ], + "meta": { + "title": "报表", + "icon": "icon-baobiao1" + } + }, + { + "id": 145, + "name": "inOtherLibraries", + "path": "/inOtherLibraries", + "component": "/inOtherLibraries", + "icon": "icon-qitakuneicaozuo", + "redirect": "", + "hidden": false, + "children":[ + { + "id": 1451, + "name": "inOtherLibraries", + "path": "/inOtherLibraries", + "component": "/inOtherLibraries", + "icon": "icon-qitakuneicaozuo", + "redirect": "", + "hidden": false, + "meta": { + "title": "其他库内操作", + "icon": "icon-qitakuneicaozuo" + }, + "children": [ + { + "id": 1461, + "name": "movingBoxesList", + "path": "/inOtherLibraries/movingBoxesList/index", + "component": "/inOtherLibraries/movingBoxesList/index", + "hidden": false, + "children":[], + "meta": { + "title": "移箱列表", + "icon": "", + "isKeepAlive": true + } + }, + { + "id": 1462, + "name": "boxModificationsList", + "path": "/inOtherLibraries/boxModificationsList/index", + "component": "/inOtherLibraries/boxModificationsList/index", + "hidden": false, + "children":[], + "meta": { + "title": "改箱列表", + "icon": "", + "isKeepAlive": true + } + }, + { + "id": 1483, + "name": "inboundOutboundRollbackList", + "path": "/inOtherLibraries/inboundOutboundRollbackList/index", + "component": "/inOtherLibraries/inboundOutboundRollbackList/index", + "hidden": false, + "children":[], + "meta": { + "title": "出入库回退列表", + "icon": "", + "isKeepAlive": true + } + } + ] + } + ], + "meta": { + "title": "其他", + "icon": "icon-qitakuneicaozuo" + } + }, + { + "id": 146, + "name": "setUp", + "path": "/setUp", + "component": "/setUp", + "icon": "icon-shezhi", + "redirect": "", + "hidden": false, + "children":[ + { + "id": 14612, + "name": "setUp", + "path": "/setUp", + "component": "/setUp", + "icon": "icon-qitakuneicaozuo", + "redirect": "", + "hidden": false, + "meta": { + "title": "箱唛管理", + "icon": "icon-qitakuneicaozuo" + }, + "children": [ + { + "id": 146111, + "name": "boxMark", + "path": "/setUp/boxMark/index", + "component": "/setUp/boxMark/index", + "hidden": false, + "children":[], + "meta": { + "title": "箱唛列表", + "icon": "", + "isKeepAlive": true + } + }, + { + "id": 146133, + "name": "boxMarkDetails", + "path": "/setUp/boxMark/details", + "component": "/setUp/boxMark/details", + "hidden": true, + "children":[], + "meta": { + "title": "新增箱唛", + "icon": "", + "isKeepAlive": false + } + } + ] + } + ], + + "meta": { + "title": "设置", + "icon": "icon-shezhi" + } + }, + { + "id": 422, + "pid": 0, + "module": 9, + "title": "导出", + "name": "export", + "path": "/export", + "component": "/export", + "icon": "icon-daochu1", + "redirect": "", + "sort": 77, + "type": 1, + "hidden": false, + "closed": false, + "disable": false, + "children":[ + { + "id": 422, + "pid": 0, + "module": 9, + "title": "导出管理", + "name": "export", + "path": "/export", + "component": "/export", + "icon": "icon-daochu1", + "redirect": "", + "sort": 77, + "type": 1, + "hidden": false, + "closed": false, + "disable": false, + "meta": { + "title": "导出管理", + "icon": "icon-daochu1" + }, + "children": [ + { + "id": 424, + "pid": 423, + "module": 9, + "title": "导出列表", + "name": "exportList", + "path": "/export/list/index", + "component": "/export/list/index", + "icon": "", + "redirect": "", + "sort": 1, + "type": 1, + "hidden": false, + "closed": false, + "disable": false, + "children": [], + "meta": { + "title": "导出列表", + "icon": "" + } + } + ] + } + ], + + "meta": { + "title": "导出", + "icon": "icon-daochu1" + } + } + ], + "msg": "成功" +} diff --git a/src/auto-import.d.ts b/src/auto-import.d.ts new file mode 100644 index 0000000..4ac1182 --- /dev/null +++ b/src/auto-import.d.ts @@ -0,0 +1,69 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-auto-import +export {} +declare global { + const EffectScope: typeof import('vue')['EffectScope'] + const computed: typeof import('vue')['computed'] + const createApp: typeof import('vue')['createApp'] + const customRef: typeof import('vue')['customRef'] + const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] + const defineComponent: typeof import('vue')['defineComponent'] + const effectScope: typeof import('vue')['effectScope'] + const getCurrentInstance: typeof import('vue')['getCurrentInstance'] + const getCurrentScope: typeof import('vue')['getCurrentScope'] + const h: typeof import('vue')['h'] + const inject: typeof import('vue')['inject'] + const isProxy: typeof import('vue')['isProxy'] + const isReactive: typeof import('vue')['isReactive'] + const isReadonly: typeof import('vue')['isReadonly'] + const isRef: typeof import('vue')['isRef'] + const markRaw: typeof import('vue')['markRaw'] + const nextTick: typeof import('vue')['nextTick'] + const onActivated: typeof import('vue')['onActivated'] + const onBeforeMount: typeof import('vue')['onBeforeMount'] + const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'] + const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'] + const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] + const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] + const onDeactivated: typeof import('vue')['onDeactivated'] + const onErrorCaptured: typeof import('vue')['onErrorCaptured'] + const onMounted: typeof import('vue')['onMounted'] + const onRenderTracked: typeof import('vue')['onRenderTracked'] + const onRenderTriggered: typeof import('vue')['onRenderTriggered'] + const onScopeDispose: typeof import('vue')['onScopeDispose'] + const onServerPrefetch: typeof import('vue')['onServerPrefetch'] + const onUnmounted: typeof import('vue')['onUnmounted'] + const onUpdated: typeof import('vue')['onUpdated'] + const provide: typeof import('vue')['provide'] + const reactive: typeof import('vue')['reactive'] + const readonly: typeof import('vue')['readonly'] + const ref: typeof import('vue')['ref'] + const resolveComponent: typeof import('vue')['resolveComponent'] + const shallowReactive: typeof import('vue')['shallowReactive'] + const shallowReadonly: typeof import('vue')['shallowReadonly'] + const shallowRef: typeof import('vue')['shallowRef'] + const toRaw: typeof import('vue')['toRaw'] + const toRef: typeof import('vue')['toRef'] + const toRefs: typeof import('vue')['toRefs'] + const toValue: typeof import('vue')['toValue'] + const triggerRef: typeof import('vue')['triggerRef'] + const unref: typeof import('vue')['unref'] + const useAttrs: typeof import('vue')['useAttrs'] + const useCssModule: typeof import('vue')['useCssModule'] + const useCssVars: typeof import('vue')['useCssVars'] + const useLink: typeof import('vue-router')['useLink'] + const useRoute: typeof import('vue-router')['useRoute'] + const useRouter: typeof import('vue-router')['useRouter'] + const useSlots: typeof import('vue')['useSlots'] + const watch: typeof import('vue')['watch'] + const watchEffect: typeof import('vue')['watchEffect'] + const watchPostEffect: typeof import('vue')['watchPostEffect'] + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] +} +// for type re-export +declare global { + // @ts-ignore + export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode } from 'vue' +} diff --git a/src/components.d.ts b/src/components.d.ts new file mode 100644 index 0000000..d60c430 --- /dev/null +++ b/src/components.d.ts @@ -0,0 +1,83 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +declare module 'vue' { + export interface GlobalComponents { + 403: typeof import('./components/ErrorMessage/403.vue')['default'] + 404: typeof import('./components/ErrorMessage/404.vue')['default'] + 500: typeof import('./components/ErrorMessage/500.vue')['default'] + Add: typeof import('./components/DetailsBtns/components/Add.vue')['default'] + ColSetting: typeof import('./components/ProTable/components/ColSetting.vue')['default'] + Del: typeof import('./components/ListBtns/components/Del.vue')['default'] + DetailsBtns: typeof import('./components/DetailsBtns/index.vue')['default'] + DetailsSearch: typeof import('./components/DetailsSearch/index.vue')['default'] + ElAside: typeof import('element-plus/es')['ElAside'] + ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete'] + ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] + ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] + ElButton: typeof import('element-plus/es')['ElButton'] + ElContainer: typeof import('element-plus/es')['ElContainer'] + ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] + ElDialog: typeof import('element-plus/es')['ElDialog'] + ElDrawer: typeof import('element-plus/es')['ElDrawer'] + ElDropdown: typeof import('element-plus/es')['ElDropdown'] + ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] + ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] + ElForm: typeof import('element-plus/es')['ElForm'] + ElFormItem: typeof import('element-plus/es')['ElFormItem'] + ElHeader: typeof import('element-plus/es')['ElHeader'] + ElIcon: typeof import('element-plus/es')['ElIcon'] + ElInput: typeof import('element-plus/es')['ElInput'] + ElMain: typeof import('element-plus/es')['ElMain'] + ElMenu: typeof import('element-plus/es')['ElMenu'] + ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] + ElOption: typeof import('element-plus/es')['ElOption'] + ElPagination: typeof import('element-plus/es')['ElPagination'] + ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] + ElSelect: typeof import('element-plus/es')['ElSelect'] + ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] + ElSwitch: typeof import('element-plus/es')['ElSwitch'] + ElTable: typeof import('element-plus/es')['ElTable'] + ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] + ElTabPane: typeof import('element-plus/es')['ElTabPane'] + ElTabs: typeof import('element-plus/es')['ElTabs'] + ElTag: typeof import('element-plus/es')['ElTag'] + ElTooltip: typeof import('element-plus/es')['ElTooltip'] + Export: typeof import('./components/ListBtns/components/Export.vue')['default'] + ExprotSelect: typeof import('./components/ListBtns/components/ExprotSelect.vue')['default'] + FullScreenDialog: typeof import('./components/Dialog/FullScreenDialog.vue')['default'] + Generate: typeof import('./components/DetailsBtns/components/Generate.vue')['default'] + Grid: typeof import('./components/Grid/index.vue')['default'] + GridItem: typeof import('./components/Grid/components/GridItem.vue')['default'] + IEpArrowDown: typeof import('~icons/ep/arrow-down')['default'] + IEpCircleClose: typeof import('~icons/ep/circle-close')['default'] + IEpFolderDelete: typeof import('~icons/ep/folder-delete')['default'] + IEpFullScreen: typeof import('~icons/ep/full-screen')['default'] + IEpRefresh: typeof import('~icons/ep/refresh')['default'] + IEpRemove: typeof import('~icons/ep/remove')['default'] + IEpSearch: typeof import('~icons/ep/search')['default'] + IEpSwitchButton: typeof import('~icons/ep/switch-button')['default'] + ImportExcel: typeof import('./components/ImportExcel/index.vue')['default'] + ListBtns: typeof import('./components/ListBtns/index.vue')['default'] + ListResultDig: typeof import('./components/ListResultDig/index.vue')['default'] + Loading: typeof import('./components/Loading/index.vue')['default'] + Merge: typeof import('./components/ListBtns/components/Merge.vue')['default'] + NoToVoid: typeof import('./components/ListBtns/components/noToVoid.vue')['default'] + Pagination: typeof import('./components/ProTable/components/Pagination.vue')['default'] + Print: typeof import('./components/DetailsBtns/components/Print.vue')['default'] + ProTable: typeof import('./components/ProTable/index.vue')['default'] + Refresh: typeof import('./components/ListBtns/components/Refresh.vue')['default'] + Retransmission: typeof import('./components/ListBtns/components/Retransmission.vue')['default'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + Search: typeof import('./components/Search/index.vue')['default'] + Submit: typeof import('./components/DetailsBtns/components/Submit.vue')['default'] + Switch: typeof import('./components/DetailsBtns/components/Switch.vue')['default'] + TableColumn: typeof import('./components/ProTable/components/TableColumn.vue')['default'] + ToVoid: typeof import('./components/ListBtns/components/ToVoid.vue')['default'] + } +} diff --git a/src/components/DetailsBtns/components/Add.vue b/src/components/DetailsBtns/components/Add.vue new file mode 100644 index 0000000..19d6939 --- /dev/null +++ b/src/components/DetailsBtns/components/Add.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/src/components/DetailsBtns/components/Generate.vue b/src/components/DetailsBtns/components/Generate.vue new file mode 100644 index 0000000..c823bf8 --- /dev/null +++ b/src/components/DetailsBtns/components/Generate.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/src/components/DetailsBtns/components/Print.vue b/src/components/DetailsBtns/components/Print.vue new file mode 100644 index 0000000..843e7c6 --- /dev/null +++ b/src/components/DetailsBtns/components/Print.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/src/components/DetailsBtns/components/Submit.vue b/src/components/DetailsBtns/components/Submit.vue new file mode 100644 index 0000000..298f49e --- /dev/null +++ b/src/components/DetailsBtns/components/Submit.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/src/components/DetailsBtns/components/Switch.vue b/src/components/DetailsBtns/components/Switch.vue new file mode 100644 index 0000000..27e939c --- /dev/null +++ b/src/components/DetailsBtns/components/Switch.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/src/components/DetailsBtns/constant/index.ts b/src/components/DetailsBtns/constant/index.ts new file mode 100644 index 0000000..b3526fe --- /dev/null +++ b/src/components/DetailsBtns/constant/index.ts @@ -0,0 +1,4 @@ +// 路由跳转映射表 +export const OPENS: Record = { + mateList: "/material/list/details" +}; diff --git a/src/components/DetailsBtns/index.scss b/src/components/DetailsBtns/index.scss new file mode 100644 index 0000000..bf67782 --- /dev/null +++ b/src/components/DetailsBtns/index.scss @@ -0,0 +1,120 @@ +.add-btn-box { + display: flex; + align-items: center; + justify-content: center; + width: 76px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: #ffffff; + cursor: pointer; + background: #4178d5; + border-radius: 6px; +} +.add-btn-box:hover { + background: rgb(65 120 213 / 60%); +} +.clone-btn-box { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 76px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: rgb(31 31 31 / 100%); + cursor: pointer; + background: #ffffff; + border-radius: 6px; +} +.common-btn-box1 { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 56px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: #ffffff; + cursor: pointer; + background: #4178d5; + border-radius: 6px; +} +.reset-btn-box { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 56px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: rgb(31 31 31 / 100%); + cursor: pointer; + background: #ffffff; + border-radius: 6px; +} +.reset-btn-box:hover { + color: #ffffff; + background: #4178d5; + border: 1px solid rgb(65 120 213 / 30%); +} +.clone-btn-box:hover { + color: #ffffff; + background: #4178d5; + border: 1px solid rgb(65 120 213 / 30%); +} +.common-btn-box { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 56px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: rgb(31 31 31 / 100%); + cursor: pointer; + background: #ffffff; + border-radius: 6px; +} +.common-btn-box2 { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 56px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: #999999; + cursor: not-allowed; + background: #ffffff; + border-radius: 6px; +} +.common-btn-box:hover { + color: #ffffff; + background: #4178d5; + border: 1px solid rgb(65 120 213 / 30%); +} +.operate-btn-box { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 76px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: rgb(31 31 31 / 100%); + cursor: pointer; + background: #ffffff; + border-radius: 6px; +} +.operate-btn-box:hover { + color: #ffffff; + background: #4178d5; + border: 1px solid rgb(65 120 213 / 30%); +} diff --git a/src/components/DetailsBtns/index.vue b/src/components/DetailsBtns/index.vue new file mode 100644 index 0000000..db674ab --- /dev/null +++ b/src/components/DetailsBtns/index.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/src/components/DetailsSearch/index.vue b/src/components/DetailsSearch/index.vue new file mode 100644 index 0000000..67107da --- /dev/null +++ b/src/components/DetailsSearch/index.vue @@ -0,0 +1,408 @@ + + + + diff --git a/src/components/DetailsSearch/interface/index.ts b/src/components/DetailsSearch/interface/index.ts new file mode 100644 index 0000000..007db22 --- /dev/null +++ b/src/components/DetailsSearch/interface/index.ts @@ -0,0 +1,52 @@ +export interface formDataIProps { + reg?: any; + prop?: string; + label?: string; + isShow?: boolean; + maxLength?: any; + value?: any; //默认值 + bomList?: any; + placeholder?: string; + labelWidth?: string; + class?: string; + urlType?: string; + rules?: any; + error?: string; + showMessage?: boolean; + inlineMessage?: boolean; + size?: string; + style?: string; + autosize?: any; + inputWidth?: string; + brIndex?: number; + optionProps?: any; + rgx?: any; + isTxt?: any; + type: + | "input" + | "textarea" + | "select" + | "datetimepicker" + | "date" + | "daterange" + | "radio" + | "checked" + | "cascader" + | "selectRemote" + | "selectRemote1" + | "selectRemote2" + | "selectRemote3" + | "customCondition"; + options?: any; + startPlaceholder?: string; + endPlaceholder?: string; + defaultTime?: any; + radios?: any; + checkeds?: any; + isCopy?: boolean; + required?: boolean; + disabled?: boolean; + formClass?: string; + isNumber?: boolean; + ruleForm?: any; +} diff --git a/src/components/Dialog/FullScreenDialog.vue b/src/components/Dialog/FullScreenDialog.vue new file mode 100644 index 0000000..d032632 --- /dev/null +++ b/src/components/Dialog/FullScreenDialog.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/src/components/ErrorMessage/403.vue b/src/components/ErrorMessage/403.vue new file mode 100644 index 0000000..4bb1874 --- /dev/null +++ b/src/components/ErrorMessage/403.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/src/components/ErrorMessage/404.vue b/src/components/ErrorMessage/404.vue new file mode 100644 index 0000000..cd1fa93 --- /dev/null +++ b/src/components/ErrorMessage/404.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/src/components/ErrorMessage/500.vue b/src/components/ErrorMessage/500.vue new file mode 100644 index 0000000..5899d26 --- /dev/null +++ b/src/components/ErrorMessage/500.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/src/components/ErrorMessage/index.scss b/src/components/ErrorMessage/index.scss new file mode 100644 index 0000000..4fc4aa5 --- /dev/null +++ b/src/components/ErrorMessage/index.scss @@ -0,0 +1,32 @@ +.not-container { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + .not-img { + margin-right: 120px; + } + .not-detail { + display: flex; + flex-direction: column; + h2, + h4 { + padding: 0; + margin: 0; + } + h2 { + font-size: 60px; + color: var(--el-text-color-primary); + } + h4 { + margin: 30px 0 20px; + font-size: 19px; + font-weight: normal; + color: var(--el-text-color-regular); + } + .el-button { + width: 100px; + } + } +} diff --git a/src/components/Grid/components/GridItem.vue b/src/components/Grid/components/GridItem.vue new file mode 100644 index 0000000..570fa30 --- /dev/null +++ b/src/components/Grid/components/GridItem.vue @@ -0,0 +1,68 @@ + + diff --git a/src/components/Grid/index.vue b/src/components/Grid/index.vue new file mode 100644 index 0000000..8793ee5 --- /dev/null +++ b/src/components/Grid/index.vue @@ -0,0 +1,167 @@ + + + diff --git a/src/components/Grid/interface/index.ts b/src/components/Grid/interface/index.ts new file mode 100644 index 0000000..31a74b4 --- /dev/null +++ b/src/components/Grid/interface/index.ts @@ -0,0 +1,6 @@ +export type BreakPoint = "xs" | "sm" | "md" | "lg" | "xl"; + +export type Responsive = { + span?: number; + offset?: number; +}; diff --git a/src/components/ImportExcel/index.scss b/src/components/ImportExcel/index.scss new file mode 100644 index 0000000..33de5c5 --- /dev/null +++ b/src/components/ImportExcel/index.scss @@ -0,0 +1,3 @@ +.upload { + width: 80%; +} diff --git a/src/components/ImportExcel/index.vue b/src/components/ImportExcel/index.vue new file mode 100644 index 0000000..1c7e38d --- /dev/null +++ b/src/components/ImportExcel/index.vue @@ -0,0 +1,151 @@ + + + + diff --git a/src/components/ListBtns/components/Add.vue b/src/components/ListBtns/components/Add.vue new file mode 100644 index 0000000..e6bbe1a --- /dev/null +++ b/src/components/ListBtns/components/Add.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/src/components/ListBtns/components/Del.vue b/src/components/ListBtns/components/Del.vue new file mode 100644 index 0000000..6970a3e --- /dev/null +++ b/src/components/ListBtns/components/Del.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/src/components/ListBtns/components/Export.vue b/src/components/ListBtns/components/Export.vue new file mode 100644 index 0000000..5de9b6d --- /dev/null +++ b/src/components/ListBtns/components/Export.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/src/components/ListBtns/components/ExprotSelect.vue b/src/components/ListBtns/components/ExprotSelect.vue new file mode 100644 index 0000000..ef7e33a --- /dev/null +++ b/src/components/ListBtns/components/ExprotSelect.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/src/components/ListBtns/components/Merge.vue b/src/components/ListBtns/components/Merge.vue new file mode 100644 index 0000000..5abd8a4 --- /dev/null +++ b/src/components/ListBtns/components/Merge.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/src/components/ListBtns/components/Print.vue b/src/components/ListBtns/components/Print.vue new file mode 100644 index 0000000..4308de7 --- /dev/null +++ b/src/components/ListBtns/components/Print.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/src/components/ListBtns/components/Refresh.vue b/src/components/ListBtns/components/Refresh.vue new file mode 100644 index 0000000..1fe9c5c --- /dev/null +++ b/src/components/ListBtns/components/Refresh.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/src/components/ListBtns/components/Retransmission.vue b/src/components/ListBtns/components/Retransmission.vue new file mode 100644 index 0000000..cb8e7ee --- /dev/null +++ b/src/components/ListBtns/components/Retransmission.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/src/components/ListBtns/components/Switch.vue b/src/components/ListBtns/components/Switch.vue new file mode 100644 index 0000000..06d5698 --- /dev/null +++ b/src/components/ListBtns/components/Switch.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/src/components/ListBtns/components/ToVoid.vue b/src/components/ListBtns/components/ToVoid.vue new file mode 100644 index 0000000..a977848 --- /dev/null +++ b/src/components/ListBtns/components/ToVoid.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/src/components/ListBtns/components/noToVoid.vue b/src/components/ListBtns/components/noToVoid.vue new file mode 100644 index 0000000..bb55d4d --- /dev/null +++ b/src/components/ListBtns/components/noToVoid.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/src/components/ListBtns/constant/index.ts b/src/components/ListBtns/constant/index.ts new file mode 100644 index 0000000..b3526fe --- /dev/null +++ b/src/components/ListBtns/constant/index.ts @@ -0,0 +1,4 @@ +// 路由跳转映射表 +export const OPENS: Record = { + mateList: "/material/list/details" +}; diff --git a/src/components/ListBtns/index.scss b/src/components/ListBtns/index.scss new file mode 100644 index 0000000..51d20cc --- /dev/null +++ b/src/components/ListBtns/index.scss @@ -0,0 +1,106 @@ +.add-btn-box { + display: flex; + align-items: center; + justify-content: center; + width: 76px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: #ffffff; + cursor: pointer; + background: #4178d5; + border-radius: 6px; +} +.add-btn-box:hover { + background: rgb(65 120 213 / 60%); +} +.clone-btn-box { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 76px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: rgb(31 31 31 / 100%); + cursor: pointer; + background: #ffffff; + border-radius: 6px; +} +.common-btn-box1 { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 56px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: #ffffff; + cursor: pointer; + background: #4178d5; + border-radius: 6px; +} +.reset-btn-box { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 56px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: rgb(31 31 31 / 100%); + cursor: pointer; + background: #ffffff; + border-radius: 6px; +} +.reset-btn-box:hover { + color: #ffffff; + background: #4178d5; + border: 1px solid rgb(65 120 213 / 30%); +} +.clone-btn-box:hover { + color: #ffffff; + background: #4178d5; + border: 1px solid rgb(65 120 213 / 30%); +} +.common-btn-box { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 56px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: rgb(31 31 31 / 100%); + cursor: pointer; + background: #ffffff; + border-radius: 6px; +} +.common-btn-box:hover { + color: #ffffff; + background: #4178d5; + border: 1px solid rgb(65 120 213 / 30%); +} +.operate-btn-box { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + width: 76px; + height: 30px; + margin-right: 12px; + line-height: 1; + color: rgb(31 31 31 / 100%); + cursor: pointer; + background: #ffffff; + border-radius: 6px; +} +.operate-btn-box:hover { + color: #ffffff; + background: #4178d5; + border: 1px solid rgb(65 120 213 / 30%); +} diff --git a/src/components/ListBtns/index.vue b/src/components/ListBtns/index.vue new file mode 100644 index 0000000..543c518 --- /dev/null +++ b/src/components/ListBtns/index.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/src/components/ListResultDig/index.vue b/src/components/ListResultDig/index.vue new file mode 100644 index 0000000..be11843 --- /dev/null +++ b/src/components/ListResultDig/index.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/src/components/Loading/index.scss b/src/components/Loading/index.scss new file mode 100644 index 0000000..cce5561 --- /dev/null +++ b/src/components/Loading/index.scss @@ -0,0 +1,67 @@ +.loading-box { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + .loading-wrap { + display: flex; + align-items: center; + justify-content: center; + padding: 98px; + } +} +.dot { + position: relative; + box-sizing: border-box; + display: inline-block; + width: 32px; + height: 32px; + font-size: 32px; + transform: rotate(45deg); + animation: ant-rotate 1.2s infinite linear; +} +.dot i { + position: absolute; + display: block; + width: 14px; + height: 14px; + background-color: var(--el-color-primary); + border-radius: 100%; + opacity: 0.3; + transform: scale(0.75); + transform-origin: 50% 50%; + animation: ant-spin-move 1s infinite linear alternate; +} +.dot i:nth-child(1) { + top: 0; + left: 0; +} +.dot i:nth-child(2) { + top: 0; + right: 0; + animation-delay: 0.4s; +} +.dot i:nth-child(3) { + right: 0; + bottom: 0; + animation-delay: 0.8s; +} +.dot i:nth-child(4) { + bottom: 0; + left: 0; + animation-delay: 1.2s; +} + +@keyframes ant-rotate { + to { + transform: rotate(405deg); + } +} + +@keyframes ant-spin-move { + to { + opacity: 1; + } +} diff --git a/src/components/Loading/index.vue b/src/components/Loading/index.vue new file mode 100644 index 0000000..e411f04 --- /dev/null +++ b/src/components/Loading/index.vue @@ -0,0 +1,13 @@ + + + + + diff --git a/src/components/ProTable/components/ColSetting.vue b/src/components/ProTable/components/ColSetting.vue new file mode 100644 index 0000000..8e68034 --- /dev/null +++ b/src/components/ProTable/components/ColSetting.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/src/components/ProTable/components/Pagination.vue b/src/components/ProTable/components/Pagination.vue new file mode 100644 index 0000000..ec5d368 --- /dev/null +++ b/src/components/ProTable/components/Pagination.vue @@ -0,0 +1,51 @@ + + + + diff --git a/src/components/ProTable/components/TableColumn.vue b/src/components/ProTable/components/TableColumn.vue new file mode 100644 index 0000000..a0c6e44 --- /dev/null +++ b/src/components/ProTable/components/TableColumn.vue @@ -0,0 +1,58 @@ + + + diff --git a/src/components/ProTable/index.vue b/src/components/ProTable/index.vue new file mode 100644 index 0000000..de298ac --- /dev/null +++ b/src/components/ProTable/index.vue @@ -0,0 +1,201 @@ + + + diff --git a/src/components/ProTable/interface/index.ts b/src/components/ProTable/interface/index.ts new file mode 100644 index 0000000..d0dfbc4 --- /dev/null +++ b/src/components/ProTable/interface/index.ts @@ -0,0 +1,80 @@ +import { VNode, ComponentPublicInstance } from "vue"; +import { BreakPoint, Responsive } from "@/components/Grid/interface"; +import { TableColumnCtx } from "element-plus/es/components/table/src/table-column/defaults"; +import { ProTableProps } from "@/components/ProTable/index.vue"; +import ProTable from "@/components/ProTable/index.vue"; + +export interface EnumProps { + label?: string; // 选项框显示的文字 + value?: string | number | boolean | any[]; // 选项框值 + disabled?: boolean; // 是否禁用此选项 + tagType?: string; // 当 tag 为 true 时,此选择会指定 tag 显示类型 + children?: EnumProps[]; // 为树形选择时,可以通过 children 属性指定子选项 + [key: string]: any; +} + +export type TypeProps = "index" | "selection" | "expand"; + +export type SearchType = + | "input" + | "input-number" + | "select" + | "select-v2" + | "tree-select" + | "cascader" + | "date-picker" + | "time-picker" + | "time-select" + | "switch" + | "slider"; + +export type SearchRenderScope = { + searchParam: { [key: string]: any }; + placeholder: string; + clearable: boolean; + options: EnumProps[]; + data: EnumProps[]; +}; + +export type SearchProps = { + el?: SearchType; // 当前项搜索框的类型 + props?: any; // 搜索项参数,根据 element plus 官方文档来传递,该属性所有值会透传到组件 + key?: string; // 当搜索项 key 不为 prop 属性时,可通过 key 指定 + order?: number; // 搜索项排序(从大到小) + span?: number; // 搜索项所占用的列数,默认为1列 + offset?: number; // 搜索字段左侧偏移列数 + defaultValue?: string | number | boolean | any[]; // 搜索项默认值 + render?: (scope: SearchRenderScope) => VNode; // 自定义搜索内容渲染(tsx语法) +} & Partial>; + +export type FieldNamesProps = { + label: string; + value: string; + children?: string; +}; + +export type RenderScope = { + row: T; + $index: number; + column: TableColumnCtx; + [key: string]: any; +}; + +export type HeaderRenderScope = { + $index: number; + column: TableColumnCtx; + [key: string]: any; +}; + +export interface ColumnProps extends Partial, "children" | "renderCell" | "renderHeader">> { + tag?: boolean; // 是否是标签展示 + isShow?: boolean; // 是否显示在表格当中 + enum?: EnumProps[] | ((params?: any) => Promise); // 枚举类型(字典) + isFilterEnum?: boolean; // 当前单元格值是否根据 enum 格式化(示例:enum 只作为搜索项数据) + fieldNames?: FieldNamesProps; // 指定 label && value && children 的 key 值 + headerRender?: (scope: HeaderRenderScope) => VNode; // 自定义表头内容渲染(tsx语法) + render?: (scope: RenderScope) => VNode | string; // 自定义单元格内容渲染(tsx语法) + _children?: ColumnProps[]; // 多级表头 +} + +export type ProTableInstance = Omit, keyof ComponentPublicInstance | keyof ProTableProps>; diff --git a/src/components/Search/index.scss b/src/components/Search/index.scss new file mode 100644 index 0000000..45e5851 --- /dev/null +++ b/src/components/Search/index.scss @@ -0,0 +1,32 @@ +.search-box { + display: flex; + min-width: 1280px; + padding: 16px; + background: #ffffff; + .el-form-item--default { + margin-bottom: 8px; + } + .form-box { + .form-item { + width: 300px; + height: 32px; + margin-right: 8px; + .form-item-select { + width: 240px; + } + .el-input__wrapper { + width: 178px; + } + } + } + .btn-box { + display: flex; + flex: 1; + justify-content: flex-end; + } + .copyBtn { + display: flex; + align-items: center; + justify-content: center; + } +} diff --git a/src/components/Search/index.vue b/src/components/Search/index.vue new file mode 100644 index 0000000..57b9a9a --- /dev/null +++ b/src/components/Search/index.vue @@ -0,0 +1,320 @@ + + + + diff --git a/src/components/Search/interface/index.ts b/src/components/Search/interface/index.ts new file mode 100644 index 0000000..d4f00f7 --- /dev/null +++ b/src/components/Search/interface/index.ts @@ -0,0 +1,48 @@ +export interface formDataIProps { + reg?: any; + prop?: string; + label?: string; + isShow?: boolean; + value?: any; //默认值 + bomList?: any; + placeholder?: string; + labelWidth?: string; + rules?: any; + error?: string; + showMessage?: boolean; + inlineMessage?: boolean; + size?: string; + style?: string; + inputWidth?: string; + brIndex?: number; + optionProps?: any; + rgx?: any; + type: + | "input" + | "inputs" + | "textarea" + | "select" + | "datetimepicker" + | "date" + | "daterange" + | "radio" + | "checked" + | "cascader" + | "selectRemote" + | "customCondition" + | "customCondition1" + | "customCondition2"; + options?: any; + startPlaceholder?: string; + endPlaceholder?: string; + defaultTime?: any; + radios?: any; + checkeds?: any; + isCopy?: boolean; + required?: boolean; + disabled?: boolean; + txt?: string; + formClass?: string; + isNumber?: boolean; + ruleForm?: any; +} diff --git a/src/config/index.ts b/src/config/index.ts new file mode 100644 index 0000000..a371f59 --- /dev/null +++ b/src/config/index.ts @@ -0,0 +1,13 @@ +// ? 全局默认配置项 + +// 首页地址(默认) +export const HOME_URL: string = "/index"; + +// 登录页地址(默认) +export const LOGIN_URL: string = "/login"; + +// 默认主题颜色 rgba(65, 120, 213, 1) 009688 +export const DEFAULT_PRIMARY: string = "#4178D5"; + +// 路由白名单地址(必须是本地存在的路由 staticRouter.ts 中) +export const ROUTER_WHITE_LIST: string[] = ["/500"]; diff --git a/src/config/nprogress.ts b/src/config/nprogress.ts new file mode 100644 index 0000000..a1697ef --- /dev/null +++ b/src/config/nprogress.ts @@ -0,0 +1,12 @@ +import NProgress from "nprogress"; +import "nprogress/nprogress.css"; + +NProgress.configure({ + easing: "ease", // 动画方式 + speed: 500, // 递增进度条的速度 + showSpinner: true, // 是否显示加载ico + trickleSpeed: 200, // 自动递增间隔 + minimum: 0.3 // 初始化时的最小百分比 +}); + +export default NProgress; diff --git a/src/config/piniaPersist.ts b/src/config/piniaPersist.ts new file mode 100644 index 0000000..7240392 --- /dev/null +++ b/src/config/piniaPersist.ts @@ -0,0 +1,19 @@ +import { PersistedStateOptions } from "pinia-plugin-persistedstate"; + +/** + * @description pinia 持久化参数配置 + * @param {String} key 存储到持久化的 name + * @param {Array} paths 需要持久化的 state name + * @return persist + * */ +const piniaPersistConfig = (key: string, paths?: string[]) => { + const persist: PersistedStateOptions = { + key, + storage: localStorage, + // storage: sessionStorage, + paths + }; + return persist; +}; + +export default piniaPersistConfig; diff --git a/src/config/serviceLoading.ts b/src/config/serviceLoading.ts new file mode 100644 index 0000000..5886957 --- /dev/null +++ b/src/config/serviceLoading.ts @@ -0,0 +1,45 @@ +import { ElLoading } from "element-plus"; + +/* 全局请求 loading */ +let loadingInstance: ReturnType; + +/** + * @description 开启 Loading + * */ +const startLoading = () => { + loadingInstance = ElLoading.service({ + fullscreen: true, + lock: true, + text: "Loading", + background: "rgba(0, 0, 0, 0.7)" + }); +}; + +/** + * @description 结束 Loading + * */ +export const endLoading = () => { + loadingInstance.close(); +}; + +/** + * @description 显示全屏加载 + * */ +let needLoadingRequestCount = 0; +export const showFullScreenLoading = () => { + if (needLoadingRequestCount === 0) { + startLoading(); + } + needLoadingRequestCount++; +}; + +/** + * @description 隐藏全屏加载 + * */ +export const tryHideFullScreenLoading = () => { + if (needLoadingRequestCount <= 0) return; + needLoadingRequestCount--; + if (needLoadingRequestCount === 0) { + endLoading(); + } +}; diff --git a/src/directives/index.ts b/src/directives/index.ts new file mode 100644 index 0000000..6fad9bf --- /dev/null +++ b/src/directives/index.ts @@ -0,0 +1,27 @@ +import { App, Directive } from "vue"; + +import copy from "./modules/copy"; +import waterMarker from "./modules/waterMarker"; +import draggable from "./modules/draggable"; +import debounce from "./modules/debounce"; +import throttle from "./modules/throttle"; +import longpress from "./modules/longpress"; + +const directivesList: { [key: string]: Directive } = { + copy, + waterMarker, + draggable, + debounce, + throttle, + longpress +}; + +const directives = { + install: function (app: App) { + Object.keys(directivesList).forEach(key => { + app.directive(key, directivesList[key]); + }); + } +}; + +export default directives; diff --git a/src/directives/modules/copy.ts b/src/directives/modules/copy.ts new file mode 100644 index 0000000..207d00a --- /dev/null +++ b/src/directives/modules/copy.ts @@ -0,0 +1,38 @@ +/** + * v-copy + * 复制某个值至剪贴板 + * 接收参数:string类型/Ref类型/Reactive类型 + */ +import type { Directive, DirectiveBinding } from "vue"; +import { ElMessage } from "element-plus"; +interface ElType extends HTMLElement { + copyData: string | number; + __handleClick__: any; +} +const copy: Directive = { + mounted(el: ElType, binding: DirectiveBinding) { + el.copyData = binding.value; + el.addEventListener("click", handleClick); + }, + updated(el: ElType, binding: DirectiveBinding) { + el.copyData = binding.value; + }, + beforeUnmount(el: ElType) { + el.removeEventListener("click", el.__handleClick__); + } +}; + +function handleClick(this: any) { + const input = document.createElement("input"); + input.value = this.copyData.toLocaleString(); + document.body.appendChild(input); + input.select(); + document.execCommand("Copy"); + document.body.removeChild(input); + ElMessage({ + type: "success", + message: "复制成功" + }); +} + +export default copy; diff --git a/src/directives/modules/debounce.ts b/src/directives/modules/debounce.ts new file mode 100644 index 0000000..b060aa0 --- /dev/null +++ b/src/directives/modules/debounce.ts @@ -0,0 +1,31 @@ +/** + * v-debounce + * 按钮防抖指令,可自行扩展至input + * 接收参数:function类型 + */ +import type { Directive, DirectiveBinding } from "vue"; +interface ElType extends HTMLElement { + __handleClick__: () => any; +} +const debounce: Directive = { + mounted(el: ElType, binding: DirectiveBinding) { + if (typeof binding.value !== "function") { + throw "callback must be a function"; + } + let timer: NodeJS.Timeout | null = null; + el.__handleClick__ = function () { + if (timer) { + clearInterval(timer); + } + timer = setTimeout(() => { + binding.value(); + }, 800); + }; + el.addEventListener("click", el.__handleClick__); + }, + beforeUnmount(el: ElType) { + el.removeEventListener("click", el.__handleClick__); + } +}; + +export default debounce; diff --git a/src/directives/modules/draggable.ts b/src/directives/modules/draggable.ts new file mode 100644 index 0000000..66163e3 --- /dev/null +++ b/src/directives/modules/draggable.ts @@ -0,0 +1,49 @@ +/* + 需求:实现一个拖拽指令,可在父元素区域任意拖拽元素。 + + 思路: + 1、设置需要拖拽的元素为absolute,其父元素为relative。 + 2、鼠标按下(onmousedown)时记录目标元素当前的 left 和 top 值。 + 3、鼠标移动(onmousemove)时计算每次移动的横向距离和纵向距离的变化值,并改变元素的 left 和 top 值 + 4、鼠标松开(onmouseup)时完成一次拖拽 + + 使用:在 Dom 上加上 v-draggable 即可 +
+*/ +import type { Directive } from "vue"; +interface ElType extends HTMLElement { + parentNode: any; +} +const draggable: Directive = { + mounted: function (el: ElType) { + el.style.cursor = "move"; + el.style.position = "absolute"; + el.onmousedown = function (e) { + let disX = e.pageX - el.offsetLeft; + let disY = e.pageY - el.offsetTop; + document.onmousemove = function (e) { + let x = e.pageX - disX; + let y = e.pageY - disY; + let maxX = el.parentNode.offsetWidth - el.offsetWidth; + let maxY = el.parentNode.offsetHeight - el.offsetHeight; + if (x < 0) { + x = 0; + } else if (x > maxX) { + x = maxX; + } + + if (y < 0) { + y = 0; + } else if (y > maxY) { + y = maxY; + } + el.style.left = x + "px"; + el.style.top = y + "px"; + }; + document.onmouseup = function () { + document.onmousemove = document.onmouseup = null; + }; + }; + } +}; +export default draggable; diff --git a/src/directives/modules/longpress.ts b/src/directives/modules/longpress.ts new file mode 100644 index 0000000..f733c57 --- /dev/null +++ b/src/directives/modules/longpress.ts @@ -0,0 +1,49 @@ +/** + * v-longpress + * 长按指令,长按时触发事件 + */ +import type { Directive, DirectiveBinding } from "vue"; + +const directive: Directive = { + mounted(el: HTMLElement, binding: DirectiveBinding) { + if (typeof binding.value !== "function") { + throw "callback must be a function"; + } + // 定义变量 + let pressTimer: any = null; + // 创建计时器( 2秒后执行函数 ) + const start = (e: any) => { + if (e.button) { + if (e.type === "click" && e.button !== 0) { + return; + } + } + if (pressTimer === null) { + pressTimer = setTimeout(() => { + handler(e); + }, 1000); + } + }; + // 取消计时器 + const cancel = () => { + if (pressTimer !== null) { + clearTimeout(pressTimer); + pressTimer = null; + } + }; + // 运行函数 + const handler = (e: MouseEvent | TouchEvent) => { + binding.value(e); + }; + // 添加事件监听器 + el.addEventListener("mousedown", start); + el.addEventListener("touchstart", start); + // 取消计时器 + el.addEventListener("click", cancel); + el.addEventListener("mouseout", cancel); + el.addEventListener("touchend", cancel); + el.addEventListener("touchcancel", cancel); + } +}; + +export default directive; diff --git a/src/directives/modules/throttle.ts b/src/directives/modules/throttle.ts new file mode 100644 index 0000000..f91bd7a --- /dev/null +++ b/src/directives/modules/throttle.ts @@ -0,0 +1,41 @@ +/* + 需求:防止按钮在短时间内被多次点击,使用节流函数限制规定时间内只能点击一次。 + + 思路: + 1、第一次点击,立即调用方法并禁用按钮,等延迟结束再次激活按钮 + 2、将需要触发的方法绑定在指令上 + + 使用:给 Dom 加上 v-throttle 及回调函数即可 + +*/ +import type { Directive, DirectiveBinding } from "vue"; +interface ElType extends HTMLElement { + __handleClick__: () => any; + disabled: boolean; +} +const throttle: Directive = { + mounted(el: ElType, binding: DirectiveBinding) { + if (typeof binding.value !== "function") { + throw "callback must be a function"; + } + let timer: NodeJS.Timeout | null = null; + el.__handleClick__ = function () { + if (timer) { + clearTimeout(timer); + } + if (!el.disabled) { + el.disabled = true; + binding.value(); + timer = setTimeout(() => { + el.disabled = false; + }, 1000); + } + }; + el.addEventListener("click", el.__handleClick__); + }, + beforeUnmount(el: ElType) { + el.removeEventListener("click", el.__handleClick__); + } +}; + +export default throttle; diff --git a/src/directives/modules/waterMarker.ts b/src/directives/modules/waterMarker.ts new file mode 100644 index 0000000..94165e9 --- /dev/null +++ b/src/directives/modules/waterMarker.ts @@ -0,0 +1,36 @@ +/* + 需求:给整个页面添加背景水印。 + + 思路: + 1、使用 canvas 特性生成 base64 格式的图片文件,设置其字体大小,颜色等。 + 2、将其设置为背景图片,从而实现页面或组件水印效果 + + 使用:设置水印文案,颜色,字体大小即可 +
+*/ + +import type { Directive, DirectiveBinding } from "vue"; +const addWaterMarker: Directive = (str: string, parentNode: any, font: any, textColor: string) => { + // 水印文字,父元素,字体,文字颜色 + let can: HTMLCanvasElement = document.createElement("canvas"); + parentNode.appendChild(can); + can.width = 205; + can.height = 140; + can.style.display = "none"; + let cans = can.getContext("2d") as CanvasRenderingContext2D; + cans.rotate((-20 * Math.PI) / 180); + cans.font = font || "16px Microsoft JhengHei"; + cans.fillStyle = textColor || "rgba(180, 180, 180, 0.3)"; + cans.textAlign = "left"; + cans.textBaseline = "Middle" as CanvasTextBaseline; + cans.fillText(str, can.width / 10, can.height / 2); + parentNode.style.backgroundImage = "url(" + can.toDataURL("image/png") + ")"; +}; + +const waterMarker = { + mounted(el: DirectiveBinding, binding: DirectiveBinding) { + addWaterMarker(binding.value.text, el, binding.value.font, binding.value.textColor); + } +}; + +export default waterMarker; diff --git a/src/enums/httpEnum.ts b/src/enums/httpEnum.ts new file mode 100644 index 0000000..dd782cf --- /dev/null +++ b/src/enums/httpEnum.ts @@ -0,0 +1,35 @@ +/** + * @description:请求配置 + */ +export enum ResultEnum { + SUCCESS = 200, + ERROR = 500, + OVERDUE = 401, + TIMEOUT = 300000, + TYPE = "success" +} + +/** + * @description:请求方法 + */ +export enum RequestEnum { + GET = "GET", + POST = "POST", + PATCH = "PATCH", + PUT = "PUT", + DELETE = "DELETE" +} + +/** + * @description:常用的 contentTyp 类型 + */ +export enum ContentTypeEnum { + // json + JSON = "application/json;charset=UTF-8", + // text + TEXT = "text/plain;charset=UTF-8", + // form-data 一般配合qs + FORM_URLENCODED = "application/x-www-form-urlencoded;charset=UTF-8", + // form-data 上传 + FORM_DATA = "multipart/form-data;charset=UTF-8" +} diff --git a/src/hooks/interface/index.ts b/src/hooks/interface/index.ts new file mode 100644 index 0000000..e599b5e --- /dev/null +++ b/src/hooks/interface/index.ts @@ -0,0 +1,25 @@ +export namespace Table { + export interface Pageable { + page: number; + size: number; + total: number; + } + export interface StateProps { + tableData: any[]; + pageable: Pageable; + searchParams: any; + searchInitParam: any; + totalQty: any; + icon?: { + [key: string]: any; + }; + } +} + +export namespace HandleData { + export type MessageType = "" | "success" | "warning" | "info" | "error"; +} + +export namespace Theme { + export type GreyOrWeakType = "grey" | "weak"; +} diff --git a/src/hooks/useDateSort.ts b/src/hooks/useDateSort.ts new file mode 100644 index 0000000..9c4abb1 --- /dev/null +++ b/src/hooks/useDateSort.ts @@ -0,0 +1,14 @@ +export const useDateSort = (property: any, bol: any) => { + //property是你需要排序传入的key,bol为true时是升序,false为降序 + return function (a: any, b: any) { + let value1 = a[property]; + let value2 = b[property]; + if (bol) { + // 升序 + return Date.parse(value1) - Date.parse(value2); + } else { + // 降序 + return Date.parse(value2) - Date.parse(value1); + } + }; +}; diff --git a/src/hooks/useDecimal.ts b/src/hooks/useDecimal.ts new file mode 100644 index 0000000..dd0f5b3 --- /dev/null +++ b/src/hooks/useDecimal.ts @@ -0,0 +1,12 @@ +/** + * @description 精度处理 + * @param data 数据源 + * @param type Decimal方法 + * @param typeData mul | div| add | sub 方法参数 的数据 + * @return returnData {number} + * */ +import { Decimal } from "decimal.js"; +export const useDecimal = (data: number, type?: "mul" | "div" | "add" | "sub", typeData?: number) => { + let returnData = type && typeData ? new Decimal(data)[type](typeData).toNumber() : new Decimal(data).toNumber(); + return returnData; +}; diff --git a/src/hooks/useDownload.ts b/src/hooks/useDownload.ts new file mode 100644 index 0000000..c8fd01a --- /dev/null +++ b/src/hooks/useDownload.ts @@ -0,0 +1,44 @@ +import { ElNotification } from "element-plus"; + +/** + * @description 接收数据流生成 blob,创建链接,下载文件 + * @param {Function} api 导出表格的api方法 (必传) + * @param {String} tempName 导出的文件名 (必传) + * @param {Object} params 导出的参数 (默认{}) + * @param {Boolean} isNotify 是否有导出消息提示 (默认为 true) + * @param {String} fileType 导出的文件格式 (默认为.xlsx) + * */ +export const useDownload = async ( + api: (param: any) => Promise, + tempName: string, + params: any = {}, + isNotify: boolean = true, + fileType: string = ".xlsx" +) => { + if (isNotify) { + ElNotification({ + title: "温馨提示", + message: "如果数据庞大会导致下载缓慢哦,请您耐心等待!", + type: "info", + duration: 3000 + }); + } + try { + const res = await api(params); + const blob = new Blob([res]); + // 兼容 edge 不支持 createObjectURL 方法 + if ("msSaveOrOpenBlob" in navigator) return window.navigator.msSaveOrOpenBlob(blob, tempName + fileType); + const blobUrl = window.URL.createObjectURL(blob); + const exportFile = document.createElement("a"); + exportFile.style.display = "none"; + exportFile.download = `${tempName}${fileType}`; + exportFile.href = blobUrl; + document.body.appendChild(exportFile); + exportFile.click(); + // 去除下载对 url 的影响 + document.body.removeChild(exportFile); + window.URL.revokeObjectURL(blobUrl); + } catch (error) { + console.log(error); + } +}; diff --git a/src/hooks/useFilter.ts b/src/hooks/useFilter.ts new file mode 100644 index 0000000..93d318a --- /dev/null +++ b/src/hooks/useFilter.ts @@ -0,0 +1,9 @@ +import { cloneDeep } from "lodash-es"; + +export const useFilter = (datas: any) => { + const target = cloneDeep(datas); + const returnTarget = target.filter((item: any) => { + return !item.disable; + }); + return returnTarget; +}; diff --git a/src/hooks/useHandleData.ts b/src/hooks/useHandleData.ts new file mode 100644 index 0000000..080f732 --- /dev/null +++ b/src/hooks/useHandleData.ts @@ -0,0 +1,34 @@ +import { ElMessageBox, ElMessage } from "element-plus"; +import { HandleData } from "./interface"; + +/** + * @description 操作单条数据信息 (二次确认【删除、禁用、启用、重置密码】) + * @param {Function} api 操作数据接口的api方法 (必传) + * @param {Object} params 携带的操作数据参数 {id,params} (必传) + * @param {String} message 提示信息 (必传) + * @param {String} confirmType icon类型 (不必传,默认为 warning) + * @returns {Promise} + */ +export const useHandleData = ( + api: (params: any) => Promise, + params: any = {}, + message: string, + confirmType: HandleData.MessageType = "warning" +) => { + return new Promise((resolve, reject) => { + ElMessageBox.confirm(`是否${message}?`, "温馨提示", { + confirmButtonText: "确定", + cancelButtonText: "取消", + type: confirmType, + draggable: true + }).then(async () => { + const res = await api(params); + if (!res) return reject(false); + ElMessage({ + type: "success", + message: `${message}成功!` + }); + resolve(true); + }); + }); +}; diff --git a/src/hooks/useMsg.ts b/src/hooks/useMsg.ts new file mode 100644 index 0000000..50d51d8 --- /dev/null +++ b/src/hooks/useMsg.ts @@ -0,0 +1,10 @@ +import { ElMessage } from "element-plus"; + +export const useMsg = (type: any = "success", msg: string, duration?: number, showClose?: boolean) => { + ElMessage({ + showClose: showClose ? showClose : false, + message: msg, + type: type, + duration: duration ? duration : 3000 + }); +}; diff --git a/src/hooks/useOnline.ts b/src/hooks/useOnline.ts new file mode 100644 index 0000000..65554da --- /dev/null +++ b/src/hooks/useOnline.ts @@ -0,0 +1,27 @@ +import { ref, onMounted, onUnmounted } from "vue"; + +/** + * @description 网络是否可用 + * */ +export const useOnline = () => { + const online = ref(true); + const showStatus = (val: any) => { + online.value = typeof val == "boolean" ? val : val.target.online; + }; + // 在页面加载后,设置正确的网络状态 + navigator.onLine ? showStatus(true) : showStatus(false); + + onMounted(() => { + // 开始监听网络状态的变化 + window.addEventListener("online", showStatus); + window.addEventListener("offline", showStatus); + }); + + onUnmounted(() => { + // 移除监听网络状态的变化 + window.removeEventListener("online", showStatus); + window.removeEventListener("offline", showStatus); + }); + + return { online }; +}; diff --git a/src/hooks/usePathUrl.ts b/src/hooks/usePathUrl.ts new file mode 100644 index 0000000..ff3c796 --- /dev/null +++ b/src/hooks/usePathUrl.ts @@ -0,0 +1,6 @@ +export const usePathUrl = () => { + const PATH_URL = `${import.meta.env.VITE_APP_SSO_LOGINURL}?client_id=${ + import.meta.env.VITE_APP_SSO_APPID + }&redirect_uri=${encodeURIComponent(import.meta.env.VITE_REDIRECT_URL)}&response_type=code`; + return PATH_URL; +}; diff --git a/src/hooks/useSearch.ts b/src/hooks/useSearch.ts new file mode 100644 index 0000000..d19e009 --- /dev/null +++ b/src/hooks/useSearch.ts @@ -0,0 +1,96 @@ +import { cloneDeep } from "lodash-es"; +export const useSearchInfoArray = (target: any[]): any => { + //深拷贝一份,不影响源数据 + let targetClone: any[] = cloneDeep(target); + let returnTarget: any[] = []; + //如果是数组 + if (Array.isArray(targetClone) && targetClone.length) { + targetClone.forEach(item => { + let obj = { + value: item.id, + label: item.name, + ...item + }; + returnTarget.push(obj); + }); + } + return returnTarget; +}; +export const useSearchCodeInfoArray = (target: any[]): any => { + //深拷贝一份,不影响源数据 + let targetClone: any[] = cloneDeep(target); + let returnTarget: any[] = []; + //如果是数组 + if (Array.isArray(targetClone) && targetClone.length) { + targetClone.forEach(item => { + let obj = { + value: item.code, + label: item.name, + ...item + }; + returnTarget.push(obj); + }); + } + return returnTarget; +}; +export const useSearchInfoObject = (target: Record): any => { + //深拷贝一份,不影响源数据 + let targetClone: Record = cloneDeep(target); + let returnTarget: any[] = []; + if (Array.isArray(targetClone) && targetClone.length) { + targetClone.forEach(item => { + let obj = { + value: item.id, + label: item.name, + ...item + }; + returnTarget.push(obj); + }); + return returnTarget; + } + //如果是对象 + if (Object.prototype.toString.call(target) === "[object Object]") { + for (let key in targetClone) { + let obj: Record = { + value: isNaN(parseInt(key)) ? key : parseInt(key), //是字符串数字就转为数组 + label: targetClone[key] + }; + returnTarget.push(obj); + } + } + + return returnTarget; +}; + +//search配置项添加数据 +export const useSetSearchData = (target: any[], data: Record) => { + let targetClone = cloneDeep(target); + let length = targetClone.length; + //如果是数组 + if (Array.isArray(targetClone) && length) { + for (let i = 0; i < length; i++) { + let item = targetClone[i]; + if (data[item.prop] || data[item.label]) { + item.options = data[item.prop] || data[item.label]; + } + } + } + return targetClone; +}; +export const useSearchStockCodeInfoArray = (target: any[]): any => { + //深拷贝一份,不影响源数据 + let targetClone: any[] = cloneDeep(target); + let returnTarget: any[] = []; + //如果是数组 + if (Array.isArray(targetClone) && targetClone.length) { + targetClone.forEach(item => { + let obj = { + value: item.code, + label: item.name, + ...item + }; + returnTarget.push(obj); + }); + } + return returnTarget; +}; diff --git a/src/hooks/useSelection.ts b/src/hooks/useSelection.ts new file mode 100644 index 0000000..0a71fce --- /dev/null +++ b/src/hooks/useSelection.ts @@ -0,0 +1,40 @@ +import { ref, computed } from "vue"; +import $Bus from "@/utils/mittBus"; + +/** + * @description 表格多选数据操作 + * @param {String} rowKey 当表格可以多选时,所指定的 id + * */ +export const useSelection = (rowKey: string = "id") => { + const isSelected = ref(false); + const selectedList = ref<{ [key: string]: any }[]>([]); + + // 当前选中的所有 ids 数组 + const selectedListIds = computed((): string[] => { + let ids: string[] = []; + selectedList.value.forEach(item => ids.push(item[rowKey])); + return ids; + }); + + /** + * @description 多选操作 + * @param {Array} rowArr 当前选择的所有数据 + * @return void + */ + const selectionChange = (rowArr: { [key: string]: any }[]) => { + rowArr.length ? (isSelected.value = true) : (isSelected.value = false); + selectedList.value = rowArr; + + $Bus.emit("getSelectCumData", { + selectedList: selectedList.value, + ids: selectedListIds.value + }); + }; + + return { + isSelected, + selectedList, + selectedListIds, + selectionChange + }; +}; diff --git a/src/hooks/useTable.ts b/src/hooks/useTable.ts new file mode 100644 index 0000000..997ed99 --- /dev/null +++ b/src/hooks/useTable.ts @@ -0,0 +1,150 @@ +import { Table } from "./interface"; +import { reactive, computed, toRefs } from "vue"; +// import { cloneDeep } from "lodash-es"; +// import $Bus from "@/utils/mittBus"; +// import { cloneDeep } from "lodash-es"; +/** + * @description table 页面操作方法封装 + * @param {Function} api 获取表格数据 api 方法 (必传) + * @param {Object} initParam 获取数据初始化参数 (非必传,默认为{}) + * @param {Boolean} isPageable 是否有分页 (非必传,默认为true) + * @param {Function} dataCallBack 对后台返回的数据进行处理的方法 (非必传) + * */ +export const useTable = ( + ruleForm: any, + routeName: any, + api?: (params: any) => Promise, + initParam: object = {}, + isPageable: boolean = true, + dataCallBack?: (data: any) => any, + requestError?: (error: any) => void, + clearSelection?: () => void +) => { + const state = reactive({ + // 表格数据 + tableData: [], + // 分页数据 + pageable: { + // 当前页数 + page: 1, + // 每页显示条数 + size: 20, + // 总条数 + total: 0 + }, + searchParams: ruleForm, + // 初始化默认的查询参数 + searchInitParam: initParam, + totalQty: 0 + }); + + /** + * @description 分页查询参数(只包括分页和表格字段排序,其他排序方式可自行配置) + * */ + const pageParam = computed({ + get: () => { + return { + page: state.pageable.page, + size: state.pageable.size + }; + }, + set: (newVal: any) => { + console.log("我是分页更新之后的值", newVal); + } + }); + const noExprotTimeDate = (params: any) => { + if (params.time) { + params.createBeginDate = params.time[0]; + params.createEndDate = params.time[1]; + } + }; + const exportTimeDate = (params: any) => { + if (params.time) { + params.beginDate = params.time[0]; + params.endDate = params.time[1]; + } else { + params.beginDate = ""; + params.endDate = ""; + } + }; + const getTableList = async (params: Record = state.searchInitParam) => { + state.tableData = []; + if (!api) return; + try { + //置空复选框 + clearSelection && clearSelection(); + routeName === "exportList" ? exportTimeDate(params) : noExprotTimeDate(params); + // 先把初始化参数和分页参数放到总参数里面 + let { data } = await api({ ...params, ...pageParam.value }); + + dataCallBack && (data = dataCallBack(data)); + //表格赋值 + state.tableData = []; + state.tableData = data.data; + // 解构后台返回的分页数据 (如果有分页更新分页信息) + if (isPageable) { + let total = data.total; + updatePageable({ page: state.pageable.page, size: state.pageable.size, total }); + } + } catch (error) { + requestError && requestError(error); + } + }; + + /** + * @description 更新分页信息 + * @param {Object} pageable 后台返回的分页数据 + * @return void + * */ + const updatePageable = (pageable: Table.Pageable) => { + Object.assign(state.pageable, pageable); + }; + /** + * @description 日期格式修改 + * @param {data} 原始搜索条件 + * @return void + * */ + const setDateData = (data: any) => { + const redata = JSON.parse(JSON.stringify(data)); + if (redata.issue_date && redata.issue_date.length == 2) { + redata.issue_date = redata.issue_date.join(","); + } + console.log(redata); + return redata; + }; + /** + * @description 每页条数改变 + * @param {Number} val 当前条数 + * @return void + * */ + const handleSizeChange = (val: number) => { + state.pageable.size = val; + getTableList(setDateData(state.searchParams)); + }; + + /** + * @description 当前页改变 + * @param {Number} val 当前页 + * @return void + * */ + const handleCurrentChange = (val: number) => { + state.pageable.page = val; + getTableList(setDateData(state.searchParams)); + }; + /** + * @description 重置页码 + * @return void + * */ + const initPage = (params: Record) => { + state.pageable.size = 50; + state.pageable.page = 1; + getTableList(params); + }; + return { + ...toRefs(state), + getTableList, + handleSizeChange, + handleCurrentChange, + initPage + }; +}; diff --git a/src/hooks/useTheme.ts b/src/hooks/useTheme.ts new file mode 100644 index 0000000..e783e6b --- /dev/null +++ b/src/hooks/useTheme.ts @@ -0,0 +1,87 @@ +import { storeToRefs } from "pinia"; +import { Theme } from "./interface"; +import { ElMessage } from "element-plus"; +import { DEFAULT_PRIMARY } from "@/config"; +import { useGlobalStore } from "@/stores/modules/global"; +import { getLightColor, getDarkColor } from "@/utils/color"; +import { asideTheme, AsideThemeType } from "@/styles/theme/aside"; + +/** + * @description 全局主题 hooks + * */ +export const useTheme = () => { + const globalStore = useGlobalStore(); + const { primary, isDark, isGrey, isWeak, asideInverted, layout } = storeToRefs(globalStore); + + // 切换暗黑模式 ==> 并带修改主题颜色、侧边栏颜色 + const switchDark = () => { + const html = document.documentElement as HTMLElement; + if (isDark.value) html.setAttribute("class", "dark"); + else html.setAttribute("class", ""); + changePrimary(primary.value); + setAsideTheme(); + }; + + // 修改主题颜色 + const changePrimary = (val: string | null) => { + if (!val) { + val = DEFAULT_PRIMARY; + ElMessage({ type: "success", message: `主题颜色已重置为 ${DEFAULT_PRIMARY}` }); + } + // 计算主题颜色变化 + document.documentElement.style.setProperty("--el-color-primary", val); + document.documentElement.style.setProperty( + "--el-color-primary-dark-2", + isDark.value ? `${getLightColor(val, 0.2)}` : `${getDarkColor(val, 0.3)}` + ); + for (let i = 1; i <= 9; i++) { + const primaryColor = isDark.value ? `${getDarkColor(val, i / 10)}` : `${getLightColor(val, i / 10)}`; + document.documentElement.style.setProperty(`--el-color-primary-light-${i}`, primaryColor); + } + globalStore.setGlobalState("primary", val); + }; + + // 灰色和弱色切换 + const changeGreyOrWeak = (type: Theme.GreyOrWeakType, value: boolean) => { + const body = document.body as HTMLElement; + if (!value) return body.removeAttribute("style"); + const styles: Record = { + grey: "filter: grayscale(1)", + weak: "filter: invert(80%)" + }; + body.setAttribute("style", styles[type]); + const propName = type === "grey" ? "isWeak" : "isGrey"; + globalStore.setGlobalState(propName, false); + }; + + // 设置侧边栏样式 ==> light、inverted、dark + const setAsideTheme = () => { + // 默认所有侧边栏为 light 模式 + let type: AsideThemeType = "light"; + // 侧边栏反转色目前只支持在 vertical、classic 布局模式下生效 || transverse 布局下菜单栏默认为 inverted 模式 + if ((["vertical", "classic"].includes(layout.value) && asideInverted.value) || layout.value == "transverse") { + type = "inverted"; + } + // 侧边栏 dark 模式 + if (isDark.value) type = "dark"; + const theme = asideTheme[type!]; + for (const [key, value] of Object.entries(theme)) { + document.documentElement.style.setProperty(key, value); + } + }; + + // init theme + const initTheme = () => { + switchDark(); + if (isGrey.value) changeGreyOrWeak("grey", true); + if (isWeak.value) changeGreyOrWeak("weak", true); + }; + + return { + initTheme, + switchDark, + changePrimary, + changeGreyOrWeak, + setAsideTheme + }; +}; diff --git a/src/hooks/useTime.ts b/src/hooks/useTime.ts new file mode 100644 index 0000000..9bcbcd6 --- /dev/null +++ b/src/hooks/useTime.ts @@ -0,0 +1,41 @@ +import { ref } from "vue"; + +/** + * @description 获取本地时间 + */ +export const useTime = () => { + const year = ref(0); // 年份 + const month = ref(0); // 月份 + const week = ref(""); // 星期几 + const day = ref(0); // 天数 + const hour = ref(0); // 小时 + const minute = ref(0); // 分钟 + const second = ref(0); // 秒 + const nowTime = ref(""); // 当前时间 + const specificDate = ref(""); // 年月日 + // 更新时间 + const updateTime = () => { + const date = new Date(); + year.value = date.getFullYear(); + month.value = date.getMonth() + 1; + + week.value = "日一二三四五六".charAt(date.getDay()); + day.value = date.getDate(); + hour.value = + (date.getHours() + "")?.padStart(2, "0") || + new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 }).format(date.getHours()); + minute.value = + (date.getMinutes() + "")?.padStart(2, "0") || + new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 }).format(date.getMinutes()); + second.value = + (date.getSeconds() + "")?.padStart(2, "0") || + new Intl.NumberFormat(undefined, { minimumIntegerDigits: 2 }).format(date.getSeconds()); + nowTime.value = `${year.value}年${month.value}月${day.value} ${hour.value}:${minute.value}:${second.value}`; + + specificDate.value = year.value + "-" + month.value + "-" + day.value; + }; + + updateTime(); + console.log(year, month, day, hour, minute, second, week, nowTime, specificDate.value); + return { year, month, day, hour, minute, second, week, nowTime, specificDate }; +}; diff --git a/src/hooks/useValidateInput.ts b/src/hooks/useValidateInput.ts new file mode 100644 index 0000000..43b8f23 --- /dev/null +++ b/src/hooks/useValidateInput.ts @@ -0,0 +1,15 @@ +import { cloneDeep } from "lodash-es"; +//只能输入数字和小数点,否则为0 +export const useValidateInput = (value: any) => { + let valueClone = cloneDeep(value) + ""; + //只能输入1-9和小数点,并且第一位不能为小数点 + let replaceValue = valueClone + .replace(/^\.+/g, "0.") + .replace(/[^\d^\\.]+/g, "") + .replace(".", "$#$") + .replace(/\./g, "") + .replace("$#$", "."); + //禁止输入多个小数点 + let resultValue = replaceValue.replace(/^(\\-)*(\d+)\.(\d\d\d\d\d\d\d\d\d\d).*$/, "$1$2.$3"); + return resultValue; +}; diff --git a/src/layouts/LayoutClassic/index.scss b/src/layouts/LayoutClassic/index.scss new file mode 100644 index 0000000..cff9267 --- /dev/null +++ b/src/layouts/LayoutClassic/index.scss @@ -0,0 +1,83 @@ +.el-container { + width: 100%; + height: 100%; + :deep(.el-header) { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: space-between; + height: 55px; + padding: 0 15px 0 0; + background-color: #191a20; + border-bottom: 1px solid #414243; + .header-lf { + display: flex; + align-items: center; + overflow: hidden; + white-space: nowrap; + .logo { + flex-shrink: 0; + width: 210px; + margin-right: 16px; + .logo-img { + width: 28px; + object-fit: contain; + margin-right: 6px; + } + .logo-text { + font-size: 18px; + font-weight: bold; + color: #dadada; + white-space: nowrap; + } + } + .tool-bar-lf { + .collapse-icon { + color: #e5eaf3; + } + .el-breadcrumb__inner.is-link { + color: #e5eaf3; + &:hover { + color: var(--el-color-primary); + } + } + .el-breadcrumb__item:last-child .el-breadcrumb__inner, + .el-breadcrumb__item:last-child .el-breadcrumb__inner:hover { + color: #cfd3dc; + } + } + } + .header-ri { + .tool-bar-ri { + .toolBar-icon, + .username { + color: #e5eaf3; + } + } + } + } + .classic-content { + display: flex; + height: calc(100% - 55px); + :deep(.el-aside) { + width: auto; + background-color: var(--el-menu-bg-color); + border-right: 1px solid var(--el-border-color-light); + .aside-box { + display: flex; + flex-direction: column; + height: 100%; + transition: width 0.3s ease; + .el-menu { + width: 100%; + overflow-x: hidden; + border-right: none; + } + } + } + .classic-main { + display: flex; + flex-direction: column; + } + } +} diff --git a/src/layouts/LayoutClassic/index.vue b/src/layouts/LayoutClassic/index.vue new file mode 100644 index 0000000..1c73e65 --- /dev/null +++ b/src/layouts/LayoutClassic/index.vue @@ -0,0 +1,59 @@ + + + + + + diff --git a/src/layouts/LayoutColumns/index.scss b/src/layouts/LayoutColumns/index.scss new file mode 100644 index 0000000..eecedd9 --- /dev/null +++ b/src/layouts/LayoutColumns/index.scss @@ -0,0 +1,106 @@ +.el-container { + width: 100%; + height: 100%; + .aside-split { + display: flex; + flex-direction: column; + flex-shrink: 0; + width: 70px; + height: 100%; + background-color: #191a20; + border-right: 1px solid var(--el-border-color-light); + .logo { + box-sizing: border-box; + height: 55px; + border-bottom: 1px solid #282a35; + .logo-img { + width: 32px; + object-fit: contain; + } + } + .el-scrollbar { + height: calc(100% - 55px); + .split-list { + flex: 1; + .split-item { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 70px; + cursor: pointer; + transition: all 0.3s ease; + &:hover { + background-color: #292b35; + } + .el-icon { + font-size: 21px; + } + .title { + margin-top: 6px; + font-size: 12px; + } + .el-icon, + .title { + color: #e5eaf3; + } + } + .split-active { + background-color: var(--el-color-primary) !important; + .el-icon, + .title { + color: #ffffff !important; + } + } + } + } + } + .not-aside { + width: 0 !important; + border-right: none !important; + } + .el-aside { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + background-color: var(--el-menu-bg-color); + border-right: 1px solid var(--el-border-color-light); + transition: width 0.3s ease; + .el-scrollbar { + height: calc(100% - 55px); + .el-menu { + width: 100%; + overflow-x: hidden; + border-right: none; + } + } + .logo { + box-sizing: border-box; + height: 55px; + border-bottom: 1px solid var(--el-border-color-light); + .logo-text { + font-size: 18px; + font-weight: bold; + color: var(--el-menu-text-color); + white-space: nowrap; + } + } + } + .el-header { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: space-between; + height: 55px; + padding: 0 15px; + background-color: #ffffff; + border-bottom: 1px solid var(--el-border-color-light); + :deep(.tool-bar-ri) { + .toolBar-icon, + .username { + color: var(--el-text-color-primary); + } + } + } +} diff --git a/src/layouts/LayoutColumns/index.vue b/src/layouts/LayoutColumns/index.vue new file mode 100644 index 0000000..043a98d --- /dev/null +++ b/src/layouts/LayoutColumns/index.vue @@ -0,0 +1,100 @@ + + + + + + diff --git a/src/layouts/LayoutTransverse/index.scss b/src/layouts/LayoutTransverse/index.scss new file mode 100644 index 0000000..5a5688e --- /dev/null +++ b/src/layouts/LayoutTransverse/index.scss @@ -0,0 +1,56 @@ +.el-container { + width: 100%; + height: 100%; + :deep(.el-header) { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: space-between; + height: 55px; + padding: 0 15px 0 0; + background-color: #191a20; + border-bottom: 1px solid var(--el-border-color-light); + .logo { + width: 210px; + margin-right: 30px; + .logo-img { + width: 28px; + object-fit: contain; + margin-right: 6px; + } + .logo-text { + font-size: 18px; + font-weight: bold; + color: #dadada; + white-space: nowrap; + } + } + .el-menu { + flex: 1; + height: 100%; + overflow: hidden; + border-bottom: none; + .el-sub-menu__hide-arrow { + width: 65px; + height: 55px; + } + .is-active { + background-color: var(--el-color-primary) !important; + border-bottom-color: var(--el-color-primary) !important; + &::before { + width: 0; + } + .el-sub-menu__title { + background-color: var(--el-color-primary) !important; + border-bottom-color: var(--el-color-primary) !important; + } + } + } + .tool-bar-ri { + .toolBar-icon, + .username { + color: #e5eaf3; + } + } + } +} diff --git a/src/layouts/LayoutTransverse/index.vue b/src/layouts/LayoutTransverse/index.vue new file mode 100644 index 0000000..a7a3411 --- /dev/null +++ b/src/layouts/LayoutTransverse/index.vue @@ -0,0 +1,64 @@ + + + + + + diff --git a/src/layouts/LayoutVertical/index.scss b/src/layouts/LayoutVertical/index.scss new file mode 100644 index 0000000..d452f94 --- /dev/null +++ b/src/layouts/LayoutVertical/index.scss @@ -0,0 +1,54 @@ +.el-container { + width: 100%; + height: 100%; + :deep(.el-aside) { + width: auto; + background-color: var(--el-menu-bg-color); + border-right: 1px solid var(--el-border-color-light); + .aside-box { + display: flex; + flex-direction: column; + height: 100%; + transition: width 0.3s ease; + .el-scrollbar { + height: calc(100% - 55px); + .el-menu { + width: 100%; + overflow-x: hidden; + border-right: none; + } + } + .logo { + box-sizing: border-box; + height: 55px; + .logo-img { + width: 28px; + object-fit: contain; + margin-right: 6px; + } + .logo-text { + font-size: 14px; + font-weight: bold; + color: var(--el-logo-text-color); + white-space: nowrap; + } + } + } + } + .el-header { + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: space-between; + height: 55px; + padding: 0 5px 0 30px; + background-color: var(--el-bg-color); + border-bottom: 1px solid var(--el-border-color-light); + :deep(.tool-bar-ri) { + .toolBar-icon, + .username { + color: var(--el-text-color-primary); + } + } + } +} diff --git a/src/layouts/LayoutVertical/index.vue b/src/layouts/LayoutVertical/index.vue new file mode 100644 index 0000000..a45c91c --- /dev/null +++ b/src/layouts/LayoutVertical/index.vue @@ -0,0 +1,57 @@ + + + + + + diff --git a/src/layouts/components/Header/ToolBarLeft.vue b/src/layouts/components/Header/ToolBarLeft.vue new file mode 100644 index 0000000..900558d --- /dev/null +++ b/src/layouts/components/Header/ToolBarLeft.vue @@ -0,0 +1,23 @@ + + + + + diff --git a/src/layouts/components/Header/ToolBarRight.vue b/src/layouts/components/Header/ToolBarRight.vue new file mode 100644 index 0000000..86113ff --- /dev/null +++ b/src/layouts/components/Header/ToolBarRight.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/src/layouts/components/Header/components/Avatar.vue b/src/layouts/components/Header/components/Avatar.vue new file mode 100644 index 0000000..d9b8b7b --- /dev/null +++ b/src/layouts/components/Header/components/Avatar.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/src/layouts/components/Header/components/Breadcrumb.vue b/src/layouts/components/Header/components/Breadcrumb.vue new file mode 100644 index 0000000..caf1619 --- /dev/null +++ b/src/layouts/components/Header/components/Breadcrumb.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/src/layouts/components/Header/components/CollapseIcon.vue b/src/layouts/components/Header/components/CollapseIcon.vue new file mode 100644 index 0000000..e9b0c6f --- /dev/null +++ b/src/layouts/components/Header/components/CollapseIcon.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/src/layouts/components/Header/components/Fullscreen.vue b/src/layouts/components/Header/components/Fullscreen.vue new file mode 100644 index 0000000..b18c036 --- /dev/null +++ b/src/layouts/components/Header/components/Fullscreen.vue @@ -0,0 +1,10 @@ + + + diff --git a/src/layouts/components/Header/components/SearchMenu.vue b/src/layouts/components/Header/components/SearchMenu.vue new file mode 100644 index 0000000..e3a4f61 --- /dev/null +++ b/src/layouts/components/Header/components/SearchMenu.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/src/layouts/components/Main/components/Maximize.vue b/src/layouts/components/Main/components/Maximize.vue new file mode 100644 index 0000000..4c6ec27 --- /dev/null +++ b/src/layouts/components/Main/components/Maximize.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/layouts/components/Main/index.scss b/src/layouts/components/Main/index.scss new file mode 100644 index 0000000..a9300b7 --- /dev/null +++ b/src/layouts/components/Main/index.scss @@ -0,0 +1,10 @@ +.el-main { + box-sizing: border-box; + padding: 16px; + overflow-x: hidden; + background-color: var(--el-bg-color-page); +} +.el-footer { + height: auto; + padding: 0; +} diff --git a/src/layouts/components/Main/index.vue b/src/layouts/components/Main/index.vue new file mode 100644 index 0000000..b22c48e --- /dev/null +++ b/src/layouts/components/Main/index.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/src/layouts/components/Menu/SubMenu.vue b/src/layouts/components/Menu/SubMenu.vue new file mode 100644 index 0000000..d83f873 --- /dev/null +++ b/src/layouts/components/Menu/SubMenu.vue @@ -0,0 +1,51 @@ + + + + diff --git a/src/layouts/components/Menu/components/lv1.vue b/src/layouts/components/Menu/components/lv1.vue new file mode 100644 index 0000000..eeef4f1 --- /dev/null +++ b/src/layouts/components/Menu/components/lv1.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/src/layouts/components/Menu/components/lv2.vue b/src/layouts/components/Menu/components/lv2.vue new file mode 100644 index 0000000..33a0f5c --- /dev/null +++ b/src/layouts/components/Menu/components/lv2.vue @@ -0,0 +1,105 @@ + + + + diff --git a/src/layouts/components/Tabs/components/MoreButton.vue b/src/layouts/components/Tabs/components/MoreButton.vue new file mode 100644 index 0000000..9db053b --- /dev/null +++ b/src/layouts/components/Tabs/components/MoreButton.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/layouts/components/Tabs/components/init/init.ts b/src/layouts/components/Tabs/components/init/init.ts new file mode 100644 index 0000000..d96400c --- /dev/null +++ b/src/layouts/components/Tabs/components/init/init.ts @@ -0,0 +1,7 @@ +import { useStatusStore } from "@/stores/modules/status"; +const statusStore = useStatusStore(); +export const initCache = async (data: any) => { + await statusStore.$reset(); + //设置全局状态 + statusStore.setGlobalStatus(data); +}; diff --git a/src/layouts/components/Tabs/index.scss b/src/layouts/components/Tabs/index.scss new file mode 100644 index 0000000..abbb104 --- /dev/null +++ b/src/layouts/components/Tabs/index.scss @@ -0,0 +1,53 @@ +.tabs-box { + background-color: var(--el-bg-color); + .tabs-menu { + position: relative; + width: 100%; + .el-dropdown { + position: absolute; + top: 8px; + right: 13px; + } + :deep(.el-tabs) { + .el-tabs__header { + box-sizing: border-box; + height: 40px; + padding: 0 10px; + margin: 0; + .el-tabs__nav-wrap { + position: absolute; + width: calc(100% - 110px); + .el-tabs__nav { + display: flex; + border: none; + .el-tabs__item { + display: flex; + align-items: center; + justify-content: center; + color: #afafaf; + border: none; + .tabs-icon { + margin: 1.5px 4px 0 0; + font-size: 15px; + } + .is-icon-close { + margin-top: 1px; + } + &.is-active { + color: var(--el-color-primary); + &::before { + position: absolute; + bottom: 0; + width: 100%; + height: 0; + content: ""; + border-bottom: 2px solid var(--el-color-primary) !important; + } + } + } + } + } + } + } + } +} diff --git a/src/layouts/components/Tabs/index.vue b/src/layouts/components/Tabs/index.vue new file mode 100644 index 0000000..93cbfe5 --- /dev/null +++ b/src/layouts/components/Tabs/index.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/src/layouts/index.vue b/src/layouts/index.vue new file mode 100644 index 0000000..bf8a971 --- /dev/null +++ b/src/layouts/index.vue @@ -0,0 +1,32 @@ + + + + + + diff --git a/src/layouts/indexAsync.vue b/src/layouts/indexAsync.vue new file mode 100644 index 0000000..bd8b081 --- /dev/null +++ b/src/layouts/indexAsync.vue @@ -0,0 +1,34 @@ + + + + + + diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..057aa25 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,41 @@ +import { createApp } from "vue"; +import App from "./App.vue"; +import "default-passive-events"; +// reset style sheet +import "@/styles/reset.scss"; +// iosn icon +import "@/assets/fonto/iconfont.css"; +// svg icons +import "virtual:svg-icons-register"; +// iconfont css +import "@/assets/iconfont/iconfont.scss"; +// // font css +// import "@/assets/fonts/font.scss"; + +//这个必须引入,解决ElMessageBox失效 +import "element-plus/dist/index.css"; +//公共样式 +import "@/styles/common.scss"; +// 重置 element 样式 +import "@/styles/element.scss"; +// svg icons +import "virtual:svg-icons-register"; + +// custom directives +import directives from "@/directives/index"; +// vue Router +import router from "@/routers"; + +// pinia store +import pinia from "@/stores"; +// errorHandler +import errorHandler from "@/utils/errorHandler"; +import VXETable from "vxe-table"; +import "vxe-table/lib/style.css"; +localStorage.setItem("baseUrl", import.meta.env.VITE_SINGLE_URL); + +const app = createApp(App); + +app.config.errorHandler = errorHandler; + +app.use(directives).use(router).use(pinia).use(VXETable).mount("#app"); diff --git a/src/routers/index.ts b/src/routers/index.ts new file mode 100644 index 0000000..db7faf8 --- /dev/null +++ b/src/routers/index.ts @@ -0,0 +1,97 @@ +import { createRouter, createWebHistory } from "vue-router"; +import { useUserStore } from "@/stores/modules/user"; +import { useAuthStore } from "@/stores/modules/auth"; +import { LOGIN_URL, ROUTER_WHITE_LIST } from "@/config"; +import { initDynamicRouter } from "@/routers/modules/dynamicRouter"; +import { staticRouter, errorRouter } from "@/routers/modules/staticRouter"; +import NProgress from "@/config/nprogress"; + +/** + * @description 📚 路由参数配置简介 + * @param path ==> 路由菜单访问路径 + * @param name ==> 路由 name (对应页面组件 name, 可用作 KeepAlive 缓存标识 && 按钮权限筛选) + * @param redirect ==> 路由重定向地址 + * @param component ==> 视图文件路径 + * @param meta ==> 路由菜单元信息 + * @param meta.icon ==> 菜单和面包屑对应的图标 + * @param meta.title ==> 路由标题 (用作 document.title || 菜单的名称) + * @param meta.activeMenu ==> 当前路由为详情页时,需要高亮的菜单 + * @param meta.isLink ==> 路由外链时填写的访问地址 + * @param meta.hidee ==> 是否在菜单中隐藏 (通常列表详情页需要隐藏) + * @param meta.isFull ==> 菜单是否全屏 (示例:数据大屏页面) + * @param meta.isAffix ==> 菜单是否固定在标签页中 (首页通常是固定项) + * @param meta.isKeepAlive ==> 当前路由是否缓存 + * */ +const router = createRouter({ + history: createWebHistory(), + routes: [...staticRouter, ...errorRouter], + strict: false, + scrollBehavior: () => ({ left: 0, top: 0 }) +}); + +/** + * @description 路由拦截 beforeEach + * */ +router.beforeEach(async (to, from, next) => { + const userStore = useUserStore(); + const authStore = useAuthStore(); + + // 1.NProgress 开始 + NProgress.start(); + + // 2.动态设置标题 + const title = import.meta.env.VITE_GLOB_APP_TITLE; + document.title = to.meta.title ? `${to.meta.title} - ${title}` : title; + // 3.判断是访问登陆页,有 Token 就在当前页面,没有 Token 重置路由到登陆页 + if (to.path.toLocaleLowerCase() === LOGIN_URL) { + if (userStore.newUserToken) return next(from.fullPath); + resetRouter(); + return next(); + } + + // 4.判断访问页面是否在路由白名单地址(静态路由)中,如果存在直接放行 + if (ROUTER_WHITE_LIST.includes(to.path)) return next(); + + // 5.判断是否有 Token,没有重定向到 login 页面 + if (!userStore.newUserToken) return next({ path: LOGIN_URL, replace: true }); + + // 6.如果没有菜单列表,就重新请求菜单列表并添加动态路由 + if (!authStore.authMenuListGet.length) { + await initDynamicRouter(); + return next({ ...to, replace: true }); + } + + // 7.存储 routerName 做按钮权限筛选 + authStore.setRouteName(to.name as string); + + // 8.正常访问页面 + next(); +}); + +/** + * @description 重置路由 + * */ +export const resetRouter = () => { + const authStore = useAuthStore(); + authStore.flatMenuListGet.forEach(route => { + const { name } = route; + if (name && router.hasRoute(name)) router.removeRoute(name); + }); +}; + +/** + * @description 路由跳转错误 + * */ +router.onError(error => { + NProgress.done(); + console.warn("路由错误", error.message); +}); + +/** + * @description 路由跳转结束 + * */ +router.afterEach(() => { + NProgress.done(); +}); + +export default router; diff --git a/src/routers/modules/dynamicRouter.ts b/src/routers/modules/dynamicRouter.ts new file mode 100644 index 0000000..f72b677 --- /dev/null +++ b/src/routers/modules/dynamicRouter.ts @@ -0,0 +1,52 @@ +import router from "@/routers/index"; +import { LOGIN_URL } from "@/config"; +import { RouteRecordRaw } from "vue-router"; +import { ElNotification } from "element-plus"; +import { useUserStore } from "@/stores/modules/user"; +import { useAuthStore } from "@/stores/modules/auth"; + +// 引入 views 文件夹下所有 vue 文件 +const modules = import.meta.glob("@/views/**/*.vue"); + +/** + * @description 初始化动态路由 + */ +export const initDynamicRouter = async () => { + const userStore = useUserStore(); + const authStore = useAuthStore(); + + try { + // 1.获取菜单列表 + await authStore.getAuthMenuList(); + // 2.判断当前用户有没有菜单权限 + if (!authStore.authMenuListGet.length) { + ElNotification({ + title: "无权限访问", + message: "当前账号无任何菜单权限,请联系系统管理员!", + type: "warning", + duration: 3000 + }); + userStore.setToken(""); + router.replace(LOGIN_URL); + return Promise.reject("No permission"); + } + + // 3.添加动态路由 + authStore.flatMenuListGet.forEach(item => { + item.children && delete item.children; + if (item.component && typeof item.component == "string") { + item.component = modules["/src/views" + item.component + ".vue"]; + } + if (item.meta.isFull) { + router.addRoute(item as unknown as RouteRecordRaw); + } else { + router.addRoute("layout", item as unknown as RouteRecordRaw); + } + }); + } catch (error) { + // 当按钮 || 菜单请求出错时,重定向到登陆页 + userStore.setToken(""); + router.replace(LOGIN_URL); + return Promise.reject(error); + } +}; diff --git a/src/routers/modules/staticRouter.ts b/src/routers/modules/staticRouter.ts new file mode 100644 index 0000000..d949c3f --- /dev/null +++ b/src/routers/modules/staticRouter.ts @@ -0,0 +1,63 @@ +import { RouteRecordRaw } from "vue-router"; +import { HOME_URL, LOGIN_URL } from "@/config"; + +/** + * staticRouter (静态路由) + */ +export const staticRouter: RouteRecordRaw[] = [ + { + path: "/", + redirect: HOME_URL + }, + { + path: LOGIN_URL, + name: "login", + component: () => import("@/views/login/index.vue"), + meta: { + title: "登录" + } + }, + { + path: "/layout", + name: "layout", + component: () => import("@/layouts/index.vue"), + // component: () => import("@/layouts/indexAsync.vue"), + redirect: HOME_URL, + children: [] + } +]; + +/** + * errorRouter (错误页面路由) + */ +export const errorRouter = [ + { + path: "/403", + name: "403", + component: () => import("@/components/ErrorMessage/403.vue"), + meta: { + title: "403页面" + } + }, + { + path: "/404", + name: "404", + component: () => import("@/components/ErrorMessage/404.vue"), + meta: { + title: "404页面" + } + }, + { + path: "/500", + name: "500", + component: () => import("@/components/ErrorMessage/500.vue"), + meta: { + title: "500页面" + } + }, + // Resolve refresh page, route warnings + { + path: "/:pathMatch(.*)*", + component: () => import("@/components/ErrorMessage/404.vue") + } +]; diff --git a/src/stores/index.ts b/src/stores/index.ts new file mode 100644 index 0000000..0c7dfda --- /dev/null +++ b/src/stores/index.ts @@ -0,0 +1,8 @@ +import { createPinia } from "pinia"; +import piniaPluginPersistedstate from "pinia-plugin-persistedstate"; + +// pinia persist +const pinia = createPinia(); +pinia.use(piniaPluginPersistedstate); + +export default pinia; diff --git a/src/stores/interface/global.ts b/src/stores/interface/global.ts new file mode 100644 index 0000000..6816230 --- /dev/null +++ b/src/stores/interface/global.ts @@ -0,0 +1,23 @@ +/* GlobalState */ +export type LayoutType = "vertical" | "classic" | "transverse" | "columns"; + +export type AssemblySizeType = "large" | "default" | "small"; + +export type LanguageType = "zh" | "en" | null; +export interface GlobalState { + layout: LayoutType; + assemblySize: AssemblySizeType; + language: LanguageType; + maximize: boolean; + primary: string; + isDark: boolean; + isGrey: boolean; + isWeak: boolean; + asideInverted: boolean; + isCollapse: boolean; + breadcrumb: boolean; + breadcrumbIcon: boolean; + tabs: boolean; + tabsIcon: boolean; + footer: boolean; +} diff --git a/src/stores/interface/index.ts b/src/stores/interface/index.ts new file mode 100644 index 0000000..f6a4c41 --- /dev/null +++ b/src/stores/interface/index.ts @@ -0,0 +1,5 @@ +import { GlobalState } from "./global"; +import { TabsState } from "./tabs"; +import { KeepAliveState } from "./keepAlive"; + +export type { GlobalState, KeepAliveState, TabsState }; diff --git a/src/stores/interface/keepAlive.ts b/src/stores/interface/keepAlive.ts new file mode 100644 index 0000000..657a73e --- /dev/null +++ b/src/stores/interface/keepAlive.ts @@ -0,0 +1,4 @@ +/* KeepAliveState */ +export interface KeepAliveState { + keepAliveName: string[]; +} diff --git a/src/stores/interface/tabs.ts b/src/stores/interface/tabs.ts new file mode 100644 index 0000000..aefaf6b --- /dev/null +++ b/src/stores/interface/tabs.ts @@ -0,0 +1,13 @@ +/* tabsMenuProps */ +export interface TabsMenuProps { + icon: string; + title: string; + path: string; + name: string; + close: boolean; +} + +/* TabsState */ +export interface TabsState { + tabsMenuList: TabsMenuProps[]; +} diff --git a/src/stores/modules/auth.ts b/src/stores/modules/auth.ts new file mode 100644 index 0000000..ec1babc --- /dev/null +++ b/src/stores/modules/auth.ts @@ -0,0 +1,58 @@ +import { defineStore } from "pinia"; +// import router from "@/routers"; +import { getAuthMenuListApi } from "@/api/modules/login"; +import { getFlatMenuList, getShowMenuList, getAllBreadcrumbList, setKeeAliveRoute, getShowBtList } from "@/utils"; +//setKeeAliveRoute +export const useAuthStore = defineStore({ + id: "wms-auth", + state: (): Record => ({ + // 所有菜单 + allMenuList: [], + // 菜单权限列表,过滤掉按钮的 + authMenuList: [], + // 当前页面的 router name,用来做按钮权限筛选 + routeName: "" + }), + getters: { + // 菜单权限列表 ==> 这里的菜单没有经过任何处理(单点没有设置isKeepAlive的地方所有自己动手) + authMenuListGet: state => setKeeAliveRoute(state.authMenuList), + // 菜单权限列表 ==> 左侧菜单栏渲染,需要剔除 isHide == true + showMenuListGet: state => getShowMenuList(state.authMenuList), + // 菜单权限列表 ==> 扁平化之后的一维数组菜单,主要用来添加动态路由 + flatMenuListGet: state => getFlatMenuList(state.authMenuList), + // 递归处理后的所有面包屑导航列表 + breadcrumbListGet: state => getAllBreadcrumbList(state.authMenuList), + // 单点权限按钮 + showbtsListGet: state => getShowBtList(state.allMenuList) + }, + actions: { + // Get AuthMenuList + async getAuthMenuList() { + const { data } = await getAuthMenuListApi(); + this.allMenuList = data; + //如果有路由就使用路由,如果沒有就添加一個首頁,讓用戶條到首頁去 + let setdata = []; + setdata = data.filter((itm: any) => { + return itm.type == 1; + }); + this.authMenuList = setdata || [ + { + path: "/index", + name: "home", + component: "/home/index", + hidden: true, + children: [], + meta: { + icon: "", + title: "首页", + isKeepAlive: true + } + } + ]; + }, + // Set RouteName + async setRouteName(name: string) { + this.routeName = name; + } + } +}); diff --git a/src/stores/modules/global.ts b/src/stores/modules/global.ts new file mode 100644 index 0000000..d48da11 --- /dev/null +++ b/src/stores/modules/global.ts @@ -0,0 +1,49 @@ +import { defineStore } from "pinia"; +import { GlobalState } from "@/stores/interface"; +import { DEFAULT_PRIMARY } from "@/config"; +import piniaPersistConfig from "@/config/piniaPersist"; + +export const useGlobalStore = defineStore({ + id: "wms-global", + // 修改默认值之后,需清除 localStorage 数据 + state: (): GlobalState => ({ + // 布局模式 (纵向:vertical | 经典:classic | 横向:transverse | 分栏:columns) + layout: "vertical", + // element 组件大小 + assemblySize: "default", + // 当前系统语言 + language: null, + // 当前页面是否全屏 + maximize: false, + // 主题颜色 + primary: DEFAULT_PRIMARY, + // 深色模式 + isDark: false, + // 灰色模式 + isGrey: false, + // 色弱模式 + isWeak: false, + // 侧边栏反转 (目前仅支持 'vertical' 模式) + asideInverted: false, + // 折叠菜单 + isCollapse: true, + // 面包屑导航 + breadcrumb: true, + // 面包屑导航图标 + breadcrumbIcon: true, + // 标签页 + tabs: true, + // 标签页图标 + tabsIcon: true, + // 页脚 + footer: true + }), + getters: {}, + actions: { + // Set GlobalState + setGlobalState(...args: ObjToKeyValArray) { + this.$patch({ [args[0]]: args[1] }); + } + }, + persist: piniaPersistConfig("wms-global") +}); diff --git a/src/stores/modules/keepAlive.ts b/src/stores/modules/keepAlive.ts new file mode 100644 index 0000000..f59e3be --- /dev/null +++ b/src/stores/modules/keepAlive.ts @@ -0,0 +1,23 @@ +import { defineStore } from "pinia"; +import { KeepAliveState } from "@/stores/interface"; + +export const useKeepAliveStore = defineStore({ + id: "wms-keepAlive", + state: (): KeepAliveState => ({ + keepAliveName: [] + }), + actions: { + // Add KeepAliveName + async addKeepAliveName(name: string) { + !this.keepAliveName.includes(name) && this.keepAliveName.push(name); + }, + // Remove KeepAliveName + async removeKeepAliveName(name: string) { + this.keepAliveName = this.keepAliveName.filter(item => item !== name); + }, + // Set KeepAliveName + async setKeepAliveName(keepAliveName: string[] = []) { + this.keepAliveName = keepAliveName; + } + } +}); diff --git a/src/stores/modules/refresh.ts b/src/stores/modules/refresh.ts new file mode 100644 index 0000000..f2e3263 --- /dev/null +++ b/src/stores/modules/refresh.ts @@ -0,0 +1,17 @@ +import { defineStore } from "pinia"; + +import piniaPersistConfig from "@/config/piniaPersist"; + +export const useRefresh = defineStore({ + id: "wms-refresh", + state: (): any => ({ + isRefreshSubscription: false + }), + actions: { + //订阅列表是否刷新 + async setRefreshSubscription(is: any) { + this.isRefreshSubscription = is; + } + }, + persist: piniaPersistConfig("wms-tabs") +}); diff --git a/src/stores/modules/status.ts b/src/stores/modules/status.ts new file mode 100644 index 0000000..014991f --- /dev/null +++ b/src/stores/modules/status.ts @@ -0,0 +1,29 @@ +import { defineStore } from "pinia"; +import piniaPersistConfig from "@/config/piniaPersist"; +import { useSearchInfoObject } from "@/hooks/useSearch"; +export const useStatusStore = defineStore({ + id: "wms-status", + // 修改默认值之后,需清除 localStorage 数据 + state: (): any => ({ + status: { + outStockType: [], //出库单类型 + moveBoxType: [], //移库单类型 + takeStockType: [], //盘点单结果类型 + instockType: [], //入库单类型 + instockStatus: [], //入库状态 + backRecordType: [], //入口回退类型 + inventoryInOutType: [], //收发明细类型 + orderType: [] //单据类型 + } + }), + getters: {}, + actions: { + // Set GlobalStatus + setGlobalStatus(data: any) { + for (let key in data) { + this.status[key] = useSearchInfoObject(data[key]); + } + } + }, + persist: piniaPersistConfig("wms-status") +}); diff --git a/src/stores/modules/tabs.ts b/src/stores/modules/tabs.ts new file mode 100644 index 0000000..4df4b86 --- /dev/null +++ b/src/stores/modules/tabs.ts @@ -0,0 +1,50 @@ +import router from "@/routers"; +import { defineStore } from "pinia"; +import { TabsState } from "@/stores/interface"; +import piniaPersistConfig from "@/config/piniaPersist"; + +export const useTabsStore = defineStore({ + id: "wms-tabs", + state: (): TabsState => ({ + tabsMenuList: [] + }), + actions: { + // Add Tabs + async addTabs(tabItem: any) { + if (this.tabsMenuList.every(item => item.path !== tabItem.path)) { + this.tabsMenuList.push(tabItem); + } + }, + // Remove Tabs + async removeTabs(tabPath: string, isCurrent: boolean = true) { + const tabsMenuList = this.tabsMenuList; + if (isCurrent) { + tabsMenuList.forEach((item, index) => { + if (item.path !== tabPath) return; + const nextTab = tabsMenuList[index + 1] || tabsMenuList[index - 1]; + if (!nextTab) return; + router.push(nextTab.path); + }); + } + this.tabsMenuList = tabsMenuList.filter(item => item.path !== tabPath); + }, + // Close MultipleTab + async closeMultipleTab(tabsMenuValue?: string) { + this.tabsMenuList = this.tabsMenuList.filter(item => { + return item.path === tabsMenuValue || !item.close; + }); + }, + // Set Tabs + async setTabs(tabsMenuList: any[]) { + this.tabsMenuList = tabsMenuList; + }, + // Set Tabs Title + async setTabsTitle(title: string) { + const nowFullPath = location.hash.substring(1); + this.tabsMenuList.forEach(item => { + if (item.path == nowFullPath) item.title = title; + }); + } + }, + persist: piniaPersistConfig("wms-tabs") +}); diff --git a/src/stores/modules/user.ts b/src/stores/modules/user.ts new file mode 100644 index 0000000..c78d471 --- /dev/null +++ b/src/stores/modules/user.ts @@ -0,0 +1,58 @@ +import { defineStore } from "pinia"; + +import { useSearchInfoArray, useSearchCodeInfoArray } from "@/hooks/useSearch"; //转换成表单可以用的数据 +import piniaPersistConfig from "@/config/piniaPersist"; + +export const useUserStore = defineStore({ + id: "wms-user", + state: () => ({ + newUserToken: "", + refreshToken: "", + phpToken: "", + userInfo: {}, + orgIdArr: [], + orgId: 0, + orgName: "", + warehouse: [], + dept: [] + }), + getters: {}, + actions: { + // Set Token + setToken(token: string) { + this.newUserToken = token; + }, + setRefreshToken(refreshToken: string) { + this.refreshToken = refreshToken; + }, + setPhpToken(token: string) { + this.phpToken = token; + }, + // 用户信息 + setUserInfo(userInfo: Record) { + this.userInfo = userInfo; + }, + + // 组织 + setOrgIdArr(orgs: any[]) { + this.orgIdArr = useSearchInfoArray(orgs); + }, + //组织ID + setOrgId(orgId: any) { + this.orgId = orgId; + }, + //默认组织名称 + setOrgName(orgName: any) { + this.orgName = orgName; + }, + //组织下的部门 + setDept(dept: any) { + this.dept = useSearchInfoArray(dept); + }, + //组织下的仓库 + setWarehouse(warehouse: any) { + this.warehouse = useSearchCodeInfoArray(warehouse); + } + }, + persist: piniaPersistConfig("wms-user") +}); diff --git a/src/styles/common.scss b/src/styles/common.scss new file mode 100644 index 0000000..cc1f710 --- /dev/null +++ b/src/styles/common.scss @@ -0,0 +1,142 @@ +/* flex */ +.flx-center { + display: flex; + align-items: center; + justify-content: center; +} +.flx-justify-between { + display: flex; + align-items: center; + justify-content: space-between; +} +.flx-justify-center { + display: flex; + justify-content: center; +} +.flx-align-center { + display: flex; + align-items: center; +} +.flx { + display: flex; +} + +/* clearfix */ +.clearfix::after { + display: block; + height: 0; + overflow: hidden; + clear: both; + content: ""; +} + +/* 文字单行省略号 */ +.sle { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* 文字多行省略号 */ +.mle { + display: -webkit-box; + overflow: hidden; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} + +/* 文字多了自动換行 */ +.break-word { + word-break: break-all; + word-wrap: break-word; +} + +/* fade-transform */ +.fade-transform-leave-active, +.fade-transform-enter-active { + transition: all 0.2s; +} +.fade-transform-enter-from { + opacity: 0; + transition: all 0.2s; + transform: translateX(-30px); +} +.fade-transform-leave-to { + opacity: 0; + transition: all 0.2s; + transform: translateX(30px); +} + +/* breadcrumb-transform */ +.breadcrumb-enter-active { + transition: all 0.2s; +} +.breadcrumb-enter-from, +.breadcrumb-leave-active { + opacity: 0; + transform: translateX(10px); +} + +/* scroll bar */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} +::-webkit-scrollbar-thumb { + background-color: var(--el-border-color-darker); + border-radius: 20px; +} + +/* nprogress */ +#nprogress .bar { + background: var(--el-color-primary) !important; +} +#nprogress .spinner-icon { + border-top-color: var(--el-color-primary) !important; + border-left-color: var(--el-color-primary) !important; +} +#nprogress .peg { + box-shadow: 0 0 10px var(--el-color-primary), 0 0 5px var(--el-color-primary) !important; +} + +/* 外边距、内边距全局样式 */ +@for $i from 0 through 40 { + .mt#{$i} { + margin-top: #{$i}px !important; + } + .mr#{$i} { + margin-right: #{$i}px !important; + } + .mb#{$i} { + margin-bottom: #{$i}px !important; + } + .ml#{$i} { + margin-left: #{$i}px !important; + } + .pt#{$i} { + padding-top: #{$i}px !important; + } + .pr#{$i} { + padding-right: #{$i}px !important; + } + .pb#{$i} { + padding-bottom: #{$i}px !important; + } + .pl#{$i} { + padding-left: #{$i}px !important; + } +} +.font12 { + font-size: 12px !important; +} + +// @font-face { +// font-family: MyCustomFont; + +// // font-weight: bold; +// src: url("./AlibabaPuHuiTi-3-115-Black.ttf") format("truetype"); +// } + +// body { +// font-family: MyCustomFont, sans-serif; +// } diff --git a/src/styles/element.scss b/src/styles/element.scss new file mode 100644 index 0000000..9a02ffb --- /dev/null +++ b/src/styles/element.scss @@ -0,0 +1,262 @@ +/* 设置 notification、message 层级在 loading 之上 */ +.el-message, +.el-notification { + z-index: 2058 !important; +} + +/* el-alert */ +.el-alert { + border: 1px solid; +} + +/* 当前页面最大化 css */ +.main-maximize { + .aside-split, + .el-aside, + .el-header, + .el-footer, + .tabs-box { + display: none !important; + } +} + +/* custom card */ +.card { + box-sizing: border-box; + padding: 0 16px 16px; + overflow-x: hidden; + background-color: var(--el-bg-color); + border-bottom-right-radius: 6px; + + // border: 1px solid var(--el-border-color-light); + border-bottom-left-radius: 6px; + box-shadow: 0 0 12px rgb(0 0 0 / 5%); +} + +/* ProTable 不需要 card 样式(在组件内使用 ProTable 会使用到) */ +.no-card { + .card { + padding: 0; + background-color: transparent; + border: none; + border-radius: 0; + box-shadow: none; + } + .table-search { + padding: 18px 0 0 !important; + margin-bottom: 0 !important; + } +} + +/* content-box (常用内容盒子) */ +.content-box { + display: flex; + flex-direction: column; + align-items: center; + height: 100%; + .text { + margin: 20px 0 30px; + font-size: 23px; + font-weight: bold; + color: var(--el-text-color-regular); + } + .el-descriptions { + width: 100%; + padding: 40px 0 0; + .el-descriptions__title { + font-size: 18px; + } + .el-descriptions__label { + width: 200px; + } + } +} + +/* main-box (树形表格 treeFilter 页面会使用,左右布局 flex) */ +.main-box { + display: flex; + width: 100%; + height: 100%; + .table-box { + // 这里减去的是 treeFilter 组件宽度 + width: calc(100% - 230px); + } +} + +/* proTable */ +.table-box, +.table-main { + display: flex; + flex: 1; + flex-direction: column; + width: 100%; + height: 100%; + + // table-search 表格搜索样式 + .table-search { + padding: 18px 18px 0; + margin-bottom: 10px; + .el-form { + .el-form-item__content > * { + width: 100%; + } + + // 去除时间选择器上下 padding + .el-range-editor.el-input__wrapper { + padding: 0 10px; + } + } + .operation { + display: flex; + align-items: center; + justify-content: flex-end; + margin-bottom: 18px; + } + } + + // 表格 header 样式 + .table-header { + .header-button-lf { + float: left; + } + .header-button-ri { + float: right; + } + .el-button { + margin-bottom: 15px; + } + } + + // el-table 表格样式 + .el-table { + flex: 1; + + // 修复 safari 浏览器表格错位 https://github.com/HalseySpicy/Geeker-Admin/issues/83 + table { + width: 100%; + } + .el-table__header th { + height: 45px; + font-size: 12px; + font-weight: bold; + color: var(--el-text-color-primary); + background: var(--el-fill-color-light); + } + .el-table__row { + height: 45px; + font-size: 12px; + .el-table__placeholder { + display: inline; + } + } + + // 设置 el-table 中 header 文字不换行,并省略 + .el-table__header .el-table__cell > .cell { + white-space: nowrap; + } + + // 解决表格数据为空时样式不居中问题(仅在element-plus中) + .el-table__empty-block { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + .table-empty { + line-height: 30px; + } + } + + // table 中 image 图片样式 + .table-image { + width: 50px; + height: 50px; + border-radius: 50%; + } + } + + // 表格 pagination 样式 + .el-pagination { + display: flex; + justify-content: flex-end; + margin-top: 20px; + } +} + +/* el-table 组件大小 */ +.el-table--small { + .el-table__header th { + height: 40px !important; + font-size: 14px !important; + } + .el-table__row { + height: 40px !important; + font-size: 13px !important; + } +} +.el-table--large { + .el-table__header th { + height: 50px !important; + font-size: 16px !important; + } + .el-table__row { + height: 50px !important; + font-size: 15px !important; + } +} + +/* el-drawer */ +.el-drawer { + .el-drawer__header { + padding: 16px 20px; + margin-bottom: 0; + border-bottom: 1px solid var(--el-border-color-lighter); + span { + font-size: 17px; + line-height: 17px; + color: var(--el-text-color-primary) !important; + } + } + .el-drawer__footer { + border-top: 1px solid var(--el-border-color-lighter); + } + + // select 样式 + .el-select { + width: 100%; + } + + // drawer-form 中存在两列 form-item 样式 + .drawer-multiColumn-form { + display: flex; + flex-wrap: wrap; + .el-form-item { + width: 47%; + &:nth-child(2n-1) { + margin-right: 5%; + } + } + } +} + +/* el-dialog */ +.el-dialog { + .el-dialog__header { + padding: 15px 20px; + margin: 0; + border-bottom: 1px solid var(--el-border-color-lighter); + .el-dialog__title { + font-size: 17px; + } + } +} + +/* el-tooltip点击会有黑框 */ +.el-tooltip__trigger:focus-visible { + outline: unset; +} +.el { + font-size: 12px !important; +} +.el-form-item--default { + font-size: 12px !important; +} diff --git a/src/styles/reset.scss b/src/styles/reset.scss new file mode 100644 index 0000000..209b32a --- /dev/null +++ b/src/styles/reset.scss @@ -0,0 +1,142 @@ +/* Reset style sheet */ + +/* 目前项目中使用富文本编辑器需要注释,如果你项目中没有使用富文本编辑器,可以取消注释 */ +// html, +// body, +// div, +// span, +// applet, +// object, +// iframe, +// h1, +// h2, +// h3, +// h4, +// h5, +// h6, +// p, +// blockquote, +// pre, +// a, +// abbr, +// acronym, +// address, +// big, +// cite, +// code, +// del, +// dfn, +// em, +// img, +// ins, +// kbd, +// q, +// s, +// samp, +// small, +// strike, +// strong, +// sub, +// sup, +// tt, +// var, +// b, +// u, +// i, +// center, +// dl, +// dt, +// dd, +// ol, +// ul, +// li, +// fieldset, +// form, +// label, +// legend, +// table, +// caption, +// tbody, +// tfoot, +// thead, +// tr, +// th, +// td, +// article, +// aside, +// canvas, +// details, +// embed, +// figure, +// figcaption, +// footer, +// header, +// hgroup, +// menu, +// nav, +// output, +// ruby, +// section, +// summary, +// time, +// mark, +// audio, +// video { +// padding: 0; +// margin: 0; +// font: inherit; +// font-size: 100%; +// vertical-align: baseline; +// border: 0; +// } + +// /* HTML5 display-role reset for older browsers */ +// article, +// aside, +// details, +// figcaption, +// figure, +// footer, +// header, +// hgroup, +// menu, +// nav, +// section { +// display: block; +// } +// body { +// padding: 0; +// margin: 0; +// } +// ol, +// ul { +// list-style: none; +// } +// blockquote, +// q { +// quotes: none; +// } +// blockquote::before, +// blockquote::after, +// q::before, +// q::after { +// content: ""; +// content: none; +// } +// table { +// border-spacing: 0; +// border-collapse: collapse; +// } +html, +body, +#app { + width: 100%; + height: 100%; + padding: 0; + margin: 0; +} + +/* 解决 h1 标签在 webkit 内核浏览器中文字大小失效问题 */ +:-webkit-any(article, aside, nav, section) h1 { + font-size: 2em; +} diff --git a/src/styles/theme/aside.ts b/src/styles/theme/aside.ts new file mode 100644 index 0000000..f66eb00 --- /dev/null +++ b/src/styles/theme/aside.ts @@ -0,0 +1,34 @@ +export type AsideThemeType = "light" | "inverted" | "dark"; + +export const asideTheme: Record = { + light: { + "--el-logo-text-color": "#303133", + "--el-menu-bg-color": "#ffffff", + "--el-menu-hover-bg-color": "#cccccc", + "--el-menu-active-bg-color": "var(--el-color-primary-light-9)", + "--el-menu-text-color": "#333333", + "--el-menu-active-color": "var(--el-color-primary)", + "--el-menu-hover-text-color": "#333333", + "--el-menu-horizontal-sub-item-height": "50px" + }, + inverted: { + "--el-logo-text-color": "#dadada", + "--el-menu-bg-color": "#191a20", + "--el-menu-hover-bg-color": "#000000", + "--el-menu-active-bg-color": "#000000", + "--el-menu-text-color": "#bdbdc0", + "--el-menu-active-color": "#ffffff", + "--el-menu-hover-text-color": "#ffffff", + "--el-menu-horizontal-sub-item-height": "50px" + }, + dark: { + "--el-logo-text-color": "#dadada", + "--el-menu-bg-color": "#141414", + "--el-menu-hover-bg-color": "#000000", + "--el-menu-active-bg-color": "#000000", + "--el-menu-text-color": "#bdbdc0", + "--el-menu-active-color": "#ffffff", + "--el-menu-hover-text-color": "#ffffff", + "--el-menu-horizontal-sub-item-height": "50px" + } +}; diff --git a/src/styles/theme/element-dark.scss b/src/styles/theme/element-dark.scss new file mode 100644 index 0000000..4891297 --- /dev/null +++ b/src/styles/theme/element-dark.scss @@ -0,0 +1,37 @@ +/* 自定义 element 暗黑模式 */ +html.dark { + /* wangEditor */ + --w-e-toolbar-color: #eeeeee; + --w-e-toolbar-bg-color: #141414; + --w-e-textarea-bg-color: #141414; + --w-e-textarea-color: #eeeeee; + --w-e-toolbar-border-color: var(--el-border-color-darker); + + /* login */ + .login-container { + background-color: #191919 !important; + .login-box { + background-color: rgb(0 0 0 / 80%) !important; + .login-form { + box-shadow: rgb(255 255 255 / 12%) 0 2px 10px 2px !important; + .logo-text { + color: var(--el-text-color-primary) !important; + } + } + } + } + + /* layout */ + .el-container { + // columns layout + .aside-split { + background-color: var(--el-bg-color) !important; + .logo { + border-bottom: 1px solid var(--el-border-color-light) !important; + } + } + .el-header { + background-color: var(--el-bg-color) !important; + } + } +} diff --git a/src/styles/var.scss b/src/styles/var.scss new file mode 100644 index 0000000..a066b5d --- /dev/null +++ b/src/styles/var.scss @@ -0,0 +1,12 @@ +/* global css variable */ + +// $primary-color: var(--el-color-primary); + +@forward "element-plus/theme-chalk/src/common/var.scss" with ( + // $colors: ( + // "primary": ( + // "base": green + // ) + // ), + $font-size: ("base": 12px) +); diff --git a/src/types/vueGlobal.d.ts b/src/types/vueGlobal.d.ts new file mode 100644 index 0000000..8e93c65 --- /dev/null +++ b/src/types/vueGlobal.d.ts @@ -0,0 +1,6 @@ +import { Emitter } from "mitt"; +declare module "vue" { + interface ComponentCustomProperties { + $Bus: Emitter; + } +} diff --git a/src/typings/global.d.ts b/src/typings/global.d.ts new file mode 100644 index 0000000..64465d4 --- /dev/null +++ b/src/typings/global.d.ts @@ -0,0 +1,81 @@ +/* Menu */ +declare namespace Menu { + interface MenuOptions { + path: string; + name: string; + component?: string | (() => Promise); + redirect?: string; + meta: MetaProps; + children?: MenuOptions[]; + hidden?: boolean; + } + interface MetaProps { + icon: string; + title: string; + activeMenu?: string; + isLink?: string; + isFull?: boolean; + isAffix?: boolean; + isKeepAlive?: boolean; + children?: MenuOptions[]; + } +} + +/* FileType */ +declare namespace File { + type ImageMimeType = + | "image/apng" + | "image/bmp" + | "image/gif" + | "image/jpeg" + | "image/pjpeg" + | "image/png" + | "image/svg+xml" + | "image/tiff" + | "image/webp" + | "image/x-icon"; + + type ExcelMimeType = "application/vnd.ms-excel" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; +} + +/* Vite */ +declare type Recordable = Record; + +declare interface ViteEnv { + VITE_USER_NODE_ENV: "development" | "production" | "test"; + VITE_GLOB_APP_TITLE: string; + VITE_PORT: number; + VITE_OPEN: boolean; + VITE_REPORT: boolean; + VITE_BUILD_COMPRESS: "gzip" | "brotli" | "gzip,brotli" | "none"; + VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE: boolean; + VITE_DROP_CONSOLE: boolean; + VITE_PWA: boolean; + VITE_PUBLIC_PATH: string; + VITE_API_URL: string; + VITE_PROXY: [string, string][]; +} + +interface ImportMetaEnv extends ViteEnv { + __: unknown; +} + +/* __APP_INFO__ */ +declare const __APP_INFO__: { + pkg: { + name: string; + version: string; + dependencies: Recordable; + devDependencies: Recordable; + }; + lastBuildTime: string; +}; + +/* Generic Tools */ +type ObjToKeyValUnion = { + [K in keyof T]: { key: K; value: T[K] }; +}[keyof T]; + +type ObjToKeyValArray = { + [K in keyof T]: [K, T[K]]; +}[keyof T]; diff --git a/src/typings/window.d.ts b/src/typings/window.d.ts new file mode 100644 index 0000000..757ab42 --- /dev/null +++ b/src/typings/window.d.ts @@ -0,0 +1,8 @@ +declare global { + interface Navigator { + msSaveOrOpenBlob: (blob: Blob, fileName: string) => void; + browserLanguage: string; + } +} + +export {}; diff --git a/src/utils/color.ts b/src/utils/color.ts new file mode 100644 index 0000000..3595f76 --- /dev/null +++ b/src/utils/color.ts @@ -0,0 +1,59 @@ +import { ElMessage } from "element-plus"; + +/** + * @description hex颜色转rgb颜色 + * @param {String} str 颜色值字符串 + * @returns {String} 返回处理后的颜色值 + */ +export function hexToRgb(str: any) { + let hexs: any = ""; + let reg = /^\#?[0-9A-Fa-f]{6}$/; + if (!reg.test(str)) return ElMessage.warning("输入错误的hex"); + str = str.replace("#", ""); + hexs = str.match(/../g); + for (let i = 0; i < 3; i++) hexs[i] = parseInt(hexs[i], 16); + return hexs; +} + +/** + * @description rgb颜色转Hex颜色 + * @param {*} r 代表红色 + * @param {*} g 代表绿色 + * @param {*} b 代表蓝色 + * @returns {String} 返回处理后的颜色值 + */ +export function rgbToHex(r: any, g: any, b: any) { + let reg = /^\d{1,3}$/; + if (!reg.test(r) || !reg.test(g) || !reg.test(b)) return ElMessage.warning("输入错误的rgb颜色值"); + let hexs = [r.toString(16), g.toString(16), b.toString(16)]; + for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = `0${hexs[i]}`; + return `#${hexs.join("")}`; +} + +/** + * @description 加深颜色值 + * @param {String} color 颜色值字符串 + * @param {Number} level 加深的程度,限0-1之间 + * @returns {String} 返回处理后的颜色值 + */ +export function getDarkColor(color: string, level: number) { + let reg = /^\#?[0-9A-Fa-f]{6}$/; + if (!reg.test(color)) return ElMessage.warning("输入错误的hex颜色值"); + let rgb = hexToRgb(color); + for (let i = 0; i < 3; i++) rgb[i] = Math.round(20.5 * level + rgb[i] * (1 - level)); + return rgbToHex(rgb[0], rgb[1], rgb[2]); +} + +/** + * @description 变浅颜色值 + * @param {String} color 颜色值字符串 + * @param {Number} level 加深的程度,限0-1之间 + * @returns {String} 返回处理后的颜色值 + */ +export function getLightColor(color: string, level: number) { + let reg = /^\#?[0-9A-Fa-f]{6}$/; + if (!reg.test(color)) return ElMessage.warning("输入错误的hex颜色值"); + let rgb = hexToRgb(color); + for (let i = 0; i < 3; i++) rgb[i] = Math.round(255 * level + rgb[i] * (1 - level)); + return rgbToHex(rgb[0], rgb[1], rgb[2]); +} diff --git a/src/utils/eleValidate.ts b/src/utils/eleValidate.ts new file mode 100644 index 0000000..e992615 --- /dev/null +++ b/src/utils/eleValidate.ts @@ -0,0 +1,32 @@ +// ? Element 常用表单校验规则 + +/** + * @rule 手机号 + */ +export function checkPhoneNumber(rule: any, value: any, callback: any) { + const regexp = /^(((13[0-9]{1})|(15[0-9]{1})|(16[0-9]{1})|(17[3-8]{1})|(18[0-9]{1})|(19[0-9]{1})|(14[5-7]{1}))+\d{8})$/; + if (value === "") callback("请输入手机号码"); + if (!regexp.test(value)) { + callback(new Error("请输入正确的手机号码")); + } else { + return callback(); + } +} + +export function numberRexgu(value: any) { + if (value) { + if (value.toString().indexOf(".") != -1) { + let value_after = parseInt(value.toString().substring(0, value.indexOf("."))); + let value_before = value.replace(/\d+\.(\d*)/, "$1"); + if (value_after.toString().length > 8) { + let newValue = value_after.toString().substring(0, 8) + "." + value_before; + return (newValue.toString().match(/\d{1,8}(\.\d{0,6})?/) || [""])[0]; + } else { + return (value.toString().match(/\d{1,8}(\.\d{0,6})?/) || [""])[0]; + } + } + return (value.toString().match(/\d{1,8}(\.\d{0,6})?/) || [""])[0]; + } else { + return ""; + } +} diff --git a/src/utils/errorHandler.ts b/src/utils/errorHandler.ts new file mode 100644 index 0000000..3512715 --- /dev/null +++ b/src/utils/errorHandler.ts @@ -0,0 +1,39 @@ +import { ElNotification } from "element-plus"; + +/** + * @description 全局代码错误捕捉 + * */ +const errorHandler = (error: any) => { + // 过滤 HTTP 请求错误 + + if (error.status || error.status == 0) return false; + let errorMap: { [key: string]: string } = { + InternalError: "Javascript引擎内部错误", + ReferenceError: "未找到对象", + TypeError: "使用了错误的类型或对象", + RangeError: "使用内置对象时,参数超范围", + SyntaxError: "语法错误", + EvalError: "错误的使用了Eval", + URIError: "URI错误" + }; + let errorName = errorMap[error.name] || "未知错误"; + + console.log("%c" + "====================================================", "color: red"); + console.error("O(∩_∩)O哈哈~,菜鸡又,又报错啦!!!"); + console.error(errorName + ":", error); + console.log("%c" + "====================================================", "color: red"); + + const NODE_ENV: string = import.meta.env.MODE as string; + console.log(NODE_ENV); + + if (NODE_ENV === "development") { + ElNotification({ + title: errorName, + message: error, + type: "error", + duration: 3000 + }); + } +}; + +export default errorHandler; diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..ac84077 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,338 @@ +import { isArray } from "@/utils/is"; +import { FieldNamesProps } from "@/components/ProTable/interface"; +//import { cloneDeep } from "lodash-es"; + +/** + * @description 获取localStorage + * @param {String} key Storage名称 + * @returns {String} + */ +export function localGet(key: string) { + const value = window.localStorage.getItem(key); + try { + return JSON.parse(window.localStorage.getItem(key) as string); + } catch (error) { + return value; + } +} + +/** + * @description 存储localStorage + * @param {String} key Storage名称 + * @param {*} value Storage值 + * @returns {void} + */ +export function localSet(key: string, value: any) { + window.localStorage.setItem(key, JSON.stringify(value)); +} + +/** + * @description 清除localStorage + * @param {String} key Storage名称 + * @returns {void} + */ +export function localRemove(key: string) { + window.localStorage.removeItem(key); +} + +/** + * @description 清除所有localStorage + * @returns {void} + */ +export function localClear() { + window.localStorage.clear(); +} + +/** + * @description 判断数据类型 + * @param {*} val 需要判断类型的数据 + * @returns {String} + */ +export function isType(val: any) { + if (val === null) return "null"; + if (typeof val !== "object") return typeof val; + else return Object.prototype.toString.call(val).slice(8, -1).toLocaleLowerCase(); +} + +/** + * @description 生成唯一 uuid + * @returns {String} + */ +export function generateUUID() { + let uuid = ""; + for (let i = 0; i < 32; i++) { + let random = (Math.random() * 16) | 0; + if (i === 8 || i === 12 || i === 16 || i === 20) uuid += "-"; + uuid += (i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random).toString(16); + } + return uuid; +} + +/** + * 判断两个对象是否相同 + * @param {Object} a 要比较的对象一 + * @param {Object} b 要比较的对象二 + * @returns {Boolean} 相同返回 true,反之 false + */ +export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]: any }) { + if (!a || !b) return false; + let aProps = Object.getOwnPropertyNames(a); + let bProps = Object.getOwnPropertyNames(b); + if (aProps.length != bProps.length) return false; + for (let i = 0; i < aProps.length; i++) { + let propName = aProps[i]; + let propA = a[propName]; + let propB = b[propName]; + if (!b.hasOwnProperty(propName)) return false; + if (propA instanceof Object) { + if (!isObjectValueEqual(propA, propB)) return false; + } else if (propA !== propB) { + return false; + } + } + return true; +} + +/** + * @description 生成随机数 + * @param {Number} min 最小值 + * @param {Number} max 最大值 + * @returns {Number} + */ +export function randomNum(min: number, max: number): number { + let num = Math.floor(Math.random() * (min - max) + max); + return num; +} + +/** + * @description 获取当前时间对应的提示语 + * @returns {String} + */ +export function getTimeState() { + let timeNow = new Date(); + let hours = timeNow.getHours(); + if (hours >= 6 && hours <= 10) return `早上好 ⛅`; + if (hours >= 10 && hours <= 14) return `中午好 🌞`; + if (hours >= 14 && hours <= 18) return `下午好 🌞`; + if (hours >= 18 && hours <= 24) return `晚上好 🌛`; + if (hours >= 0 && hours <= 6) return `凌晨好 🌛`; +} + +/** + * @description 获取浏览器默认语言 + * @returns {String} + */ +export function getBrowserLang() { + let browserLang = navigator.language ? navigator.language : navigator.browserLanguage; + let defaultBrowserLang = ""; + if (["cn", "zh", "zh-cn"].includes(browserLang.toLowerCase())) { + defaultBrowserLang = "zh"; + } else { + defaultBrowserLang = "en"; + } + return defaultBrowserLang; +} + +/** + * @description 使用递归扁平化菜单,方便添加动态路由 + * @param {Array} menuList 菜单列表 + * @returns {Array} + */ +export function getFlatMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[] { + let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList)); + return newMenuList.flatMap(item => [item, ...(item.children ? getFlatMenuList(item.children) : [])]); +} + +/** + * @description 使用递归过滤出需要渲染在左侧菜单的列表 (需剔除 isHide == true 的菜单) + * @param {Array} menuList 菜单列表 + * @returns {Array} + * */ +export function getShowMenuList(menuList: Menu.MenuOptions[]) { + let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList)); + return newMenuList.filter(item => { + item.children?.length && (item.children = getShowMenuList(item.children)); + return !item?.hidden; + }); +} + +/** + * @description 使用递归找出所有面包屑存储到 pinia/vuex 中 + * @param {Array} menuList 菜单列表 + * @param {Array} parent 父级菜单 + * @param {Object} result 处理后的结果 + * @returns {Object} + */ +export const getAllBreadcrumbList = (menuList: Menu.MenuOptions[], parent = [], result: { [key: string]: any } = {}) => { + for (const item of menuList) { + result[item.path] = [...parent, item]; + if (item.children) getAllBreadcrumbList(item.children, result[item.path], result); + } + return result; +}; + +/** + * @description 使用递归处理路由菜单 path,生成一维数组 (第一版本地路由鉴权会用到,该函数暂未使用) + * @param {Array} menuList 所有菜单列表 + * @param {Array} menuPathArr 菜单地址的一维数组 ['**','**'] + * @returns {Array} + */ +export function getMenuListPath(menuList: Menu.MenuOptions[], menuPathArr: string[] = []): string[] { + for (const item of menuList) { + if (typeof item === "object" && item.path) menuPathArr.push(item.path); + if (item.children?.length) getMenuListPath(item.children, menuPathArr); + } + return menuPathArr; +} + +/** + * @description 递归查询当前 path 所对应的菜单对象 (该函数暂未使用) + * @param {Array} menuList 菜单列表 + * @param {String} path 当前访问地址 + * @returns {Object | null} + */ +export function findMenuByPath(menuList: Menu.MenuOptions[], path: string): Menu.MenuOptions | null { + for (const item of menuList) { + if (item.path === path) return item; + if (item.children) { + const res = findMenuByPath(item.children, path); + if (res) return res; + } + } + return null; +} + +export function setKeeAliveRoute(menuList: any[]) { + menuList.forEach(item => { + item.meta.isKeepAlive = true; + item.hidden = !item.hidden; //取反 + if (!item.children) { + item.children = []; + } + if (item?.children.length) { + setKeeAliveRoute(item?.children); + } + }); + return menuList; +} + +/** + * @description 使用递归过滤需要缓存的菜单 name (该函数暂未使用) + * @param {Array} menuList 所有菜单列表 + * @param {Array} keepAliveNameArr 缓存的菜单 name ['**','**'] + * @returns {Array} + * */ +export function getKeepAliveRouterName(menuList: Menu.MenuOptions[], keepAliveNameArr: string[] = []) { + menuList.forEach(item => { + item.meta.isKeepAlive && item.name && keepAliveNameArr.push(item.name); + item.children?.length && getKeepAliveRouterName(item.children, keepAliveNameArr); + }); + return keepAliveNameArr; +} + +/** + * @description 格式化表格单元格默认值 (el-table-column) + * @param {Number} row 行 + * @param {Number} col 列 + * @param {*} callValue 当前单元格值 + * @returns {String} + * */ +export function formatTableColumn(row: number, col: number, callValue: any) { + // 如果当前值为数组,使用 / 拼接(根据需求自定义) + if (isArray(callValue)) return callValue.length ? callValue.join(" / ") : "--"; + return callValue ? callValue : "--"; +} + +/** + * @description 处理值无数据情况 + * @param {*} callValue 需要处理的值 + * @returns {String} + * */ +export function formatValue(callValue: any) { + // 如果当前值为数组,使用 / 拼接(根据需求自定义) + if (isArray(callValue)) return callValue.length ? callValue.join(" / ") : "--"; + //callValue?? "--" 空值合并运算符只有是null或者undefined才有用,所以""不会返回-- + return callValue ? callValue : "--"; +} + +/** + * @description 处理 prop 为多级嵌套的情况,返回的数据 (列如: prop: user.name) + * @param {Object} row 当前行数据 + * @param {String} prop 当前 prop + * @returns {*} + * */ +export function handleRowAccordingToProp(row: { [key: string]: any }, prop: string) { + if (!prop.includes(".")) return row[prop] ?? "--"; + prop.split(".").forEach(item => (row = row[item] ?? "--")); + return row; +} + +/** + * @description 处理 prop,当 prop 为多级嵌套时 ==> 返回最后一级 prop + * @param {String} prop 当前 prop + * @returns {String} + * */ +export function handleProp(prop: string) { + const propArr = prop.split("."); + if (propArr.length == 1) return prop; + return propArr[propArr.length - 1]; +} + +/** + * @description 根据枚举列表查询当需要的数据(如果指定了 label 和 value 的 key值,会自动识别格式化) + * @param {String} callValue 当前单元格值 + * @param {Array} enumData 字典列表 + * @param {Array} fieldNames label && value && children 的 key 值 + * @param {String} type 过滤类型(目前只有 tag) + * @returns {String} + * */ +export function filterEnum(callValue: any, enumData?: any, fieldNames?: FieldNamesProps, type?: "tag") { + const value = fieldNames?.value ?? "value"; + const label = fieldNames?.label ?? "label"; + const children = fieldNames?.children ?? "children"; + let filterData: { [key: string]: any } = {}; + // 判断 enumData 是否为数组 + if (Array.isArray(enumData)) filterData = findItemNested(enumData, callValue, value, children); + // 判断是否输出的结果为 tag 类型 + if (type == "tag") { + return filterData?.tagType ? filterData.tagType : ""; + } else { + return filterData ? filterData[label] : "--"; + } +} + +/** + * @description 递归查找 callValue 对应的 enum 值 + * */ +export function findItemNested(enumData: any, callValue: any, value: string, children: string) { + return enumData.reduce((accumulator: any, current: any) => { + if (accumulator) return accumulator; + if (current[value] === callValue) return current; + if (current[children]) return findItemNested(current[children], callValue, value, children); + }, null); +} +/** + * @description 单点按钮权限配置 + * @param {Array} menuList 菜单列表 + * @returns {Array} + * */ +function extractTypeZero(menuData: any) { + const result: any = []; + function traverse(item: any) { + if (item.type === 0) { + result.push(item); + } + if (item.children && item.children.length > 0) { + item.children.forEach((child: any) => traverse(child)); + } + } + menuData.forEach((item: any) => traverse(item)); + return result; +} +export function getShowBtList(menuList: Menu.MenuOptions[]) { + console.log(JSON.parse(JSON.stringify(extractTypeZero(menuList)))); + let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(extractTypeZero(menuList))); + return newMenuList.filter((item: any) => { + return item.type == 0; + }); +} diff --git a/src/utils/is/index.ts b/src/utils/is/index.ts new file mode 100644 index 0000000..ff77fbd --- /dev/null +++ b/src/utils/is/index.ts @@ -0,0 +1,125 @@ +/** + * @description: 判断值是否未某个类型 + */ +export function is(val: unknown, type: string) { + return Object.prototype.toString.call(val) === `[object ${type}]`; +} + +/** + * @description: 是否为函数 + */ +export function isFunction(val: unknown): val is T { + return is(val, "Function"); +} + +/** + * @description: 是否已定义 + */ +export const isDef = (val?: T): val is T => { + return typeof val !== "undefined"; +}; + +/** + * @description: 是否未定义 + */ +export const isUnDef = (val?: T): val is T => { + return !isDef(val); +}; + +/** + * @description: 是否为对象 + */ +export const isObject = (val: any): val is Record => { + return val !== null && is(val, "Object"); +}; + +/** + * @description: 是否为时间 + */ +export function isDate(val: unknown): val is Date { + return is(val, "Date"); +} + +/** + * @description: 是否为数值 + */ +export function isNumber(val: unknown): val is number { + return is(val, "Number"); +} + +/** + * @description: 是否为AsyncFunction + */ +export function isAsyncFunction(val: unknown): val is Promise { + return is(val, "AsyncFunction"); +} + +/** + * @description: 是否为promise + */ +export function isPromise(val: unknown): val is Promise { + return is(val, "Promise") && isObject(val) && isFunction(val.then) && isFunction(val.catch); +} + +/** + * @description: 是否为字符串 + */ +export function isString(val: unknown): val is string { + return is(val, "String"); +} + +/** + * @description: 是否为boolean类型 + */ +export function isBoolean(val: unknown): val is boolean { + return is(val, "Boolean"); +} + +/** + * @description: 是否为数组 + */ +export function isArray(val: any): val is Array { + return val && Array.isArray(val); +} + +/** + * @description: 是否客户端 + */ +export const isClient = () => { + return typeof window !== "undefined"; +}; + +/** + * @description: 是否为浏览器 + */ +export const isWindow = (val: any): val is Window => { + return typeof window !== "undefined" && is(val, "Window"); +}; + +/** + * @description: 是否为 element 元素 + */ +export const isElement = (val: unknown): val is Element => { + return isObject(val) && !!val.tagName; +}; + +/** + * @description: 是否为 null + */ +export function isNull(val: unknown): val is null { + return val === null; +} + +/** + * @description: 是否为 null || undefined + */ +export function isNullOrUnDef(val: unknown): val is null | undefined { + return isUnDef(val) || isNull(val); +} + +/** + * @description: 是否为 16 进制颜色 + */ +export const isHexColor = (str: string) => { + return /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(str); +}; diff --git a/src/utils/mittBus.ts b/src/utils/mittBus.ts new file mode 100644 index 0000000..ce36de5 --- /dev/null +++ b/src/utils/mittBus.ts @@ -0,0 +1,5 @@ +import mitt from "mitt"; + +const $Bus = mitt(); + +export default $Bus; diff --git a/src/utils/print/boxMark/boxMarkListPrint.js b/src/utils/print/boxMark/boxMarkListPrint.js new file mode 100644 index 0000000..7841d23 --- /dev/null +++ b/src/utils/print/boxMark/boxMarkListPrint.js @@ -0,0 +1,243 @@ +import { getLodop } from "../print.js"; +import JsBarcode from "jsbarcode"; +import QRCode from "qrcode"; +import axios from "axios"; +//设置日志 +const setLog = logs => { + let wmsUser = JSON.parse(localStorage.getItem("wms-user")); + let baseUrl = `${import.meta.env.VITE_APP_API_BASEURL + import.meta.env.VITE_APP_API_VERSION}ClientLog/logs`; + const { newUserToken } = wmsUser; + axios + .post(baseUrl, logs, { + headers: { + "Content-Type": "application/json", + Authorization: newUserToken + } + }) + .then(res => { + console.log(res, "=============res=============="); + }); +}; +//箱唛列表打印 +let LODOP; //声明为全局变量 +export const boxMarkListPrint = (printData, printNumber) => { + LODOP = getLodop(); + LODOP.PRINT_INIT("箱唛打印"); + LODOP.SET_PRINT_PAGESIZE(0, 900, 400, "A4"); + LODOP.SET_PRINT_STYLE("FontSize", 9.3); + LODOP.SET_PRINT_STYLE("Bold", 1); + LODOP.SET_PRINT_STYLE("FontName", "黑体"); + + let logs = []; + let printDataClone = []; + let resultArray = []; + + printDataClone = JSON.parse(JSON.stringify(printData)); + resultArray = printDataClone.reduce(function (acc, obj) { + let existing = acc.find(function (item) { + return item[0].id === obj.id; + }); + if (existing) { + existing.push(obj); + } else { + acc.push([obj]); + } + return acc; + }, []); + + let resultArrayLength = resultArray.length; + for (let i = 0; i < resultArrayLength; i++) { + let item = resultArray[i]; + + resultArray[i].sort(function (a, b) { + return a.sort - b.sort; + }); + let itemLength = item.length; + for (let j = 0; j < itemLength; j++) { + let itemJ = resultArray[i][j]; + LODOP.NewPage(); + AddPrintContent({ item: itemJ, logs: logs }); + } + } + setTimeout(() => { + LODOP.SET_PRINT_COPIES(printNumber); //指定份数 + LODOP.SET_PRINT_MODE("PRINT_NOCOLLATE", 1); //设置为非逐份打印,1-1 2-2 3-3 + LODOP.PREVIEW(); + setLog(logs); + }, 1500); +}; +function AddPrintContent(obj) { + const { item, logs } = obj; + + const { + isTail, + orderBillNo, + specifications, + materialName, + cratingQty, + productQty, + remark, + sort, + createTime, + barCode, + tailboxQty, + tailboxNetWeightQty, + cratingNetWeightQty, + tailboxGrossWeightQty, + cratingGrossWeightQty, + boxSortCount + } = item; + + let logStr = ""; + let image64 = ""; + let imageCode = ""; + if (specifications) { + let chinesePattern = /[\u4e00-\u9fa5]/; // 匹配中文字符的正则表达式 + if (chinesePattern.test(specifications)) { + if (specifications.length > 15) { + LODOP.ADD_PRINT_TEXT(8, 8, "20mm", 10, "产品型号:"); + LODOP.ADD_PRINT_TEXT(8, 64, "45mm", 20, `${specifications}`); + LODOP.SET_PRINT_STYLEA(0, "TextOverflow", 2); + LODOP.SET_PRINT_STYLEA(0, "LineSpacing", -5); + } else { + LODOP.ADD_PRINT_TEXT(8, 8, "20mm", "10mm", "产品型号:"); + LODOP.ADD_PRINT_TEXT(8, 64, "45mm", "100%", `${specifications}`); + LODOP.SET_PRINT_STYLEA(0, "LineSpacing", -5); + } + } else { + if (specifications.length > 25) { + LODOP.ADD_PRINT_TEXT(8, 8, "20mm", 10, "产品型号:"); + LODOP.ADD_PRINT_TEXT(8, 64, "45mm", 20, `${specifications}`); + LODOP.SET_PRINT_STYLEA(0, "TextOverflow", 2); + LODOP.SET_PRINT_STYLEA(0, "LineSpacing", -5); + } else { + LODOP.ADD_PRINT_TEXT(8, 8, "20mm", "10mm", "产品型号:"); + LODOP.ADD_PRINT_TEXT(8, 64, "45mm", "100%", `${specifications}`); + LODOP.SET_PRINT_STYLEA(0, "LineSpacing", -5); + } + } + logStr = `规格型号${specifications}`; + } + //备注 + if (remark) { + if (remark.length > 13) { + LODOP.ADD_PRINT_TEXT(8, 232, "28mm", 30, `${remark}`); + LODOP.SET_PRINT_STYLEA(0, "TextOverflow", 2); + LODOP.SET_PRINT_STYLEA(0, "FontSize", 12); + LODOP.SET_PRINT_STYLEA(0, "FontName", "黑体"); + LODOP.SET_PRINT_STYLEA(0, "LineSpacing", -6); + } else { + LODOP.ADD_PRINT_TEXT(8, 232, "28mm", 30, `${remark}`); + LODOP.SET_PRINT_STYLEA(0, "TextOverflow", 2); + LODOP.SET_PRINT_STYLEA(0, "FontSize", 12); + LODOP.SET_PRINT_STYLEA(0, "FontName", "黑体"); + LODOP.SET_PRINT_STYLEA(0, "LineSpacing", -6); + } + } + //条码; + + let barCodeClone = barCode ? barCode.replace(/\s/g, "") : barCode; + if (barCodeClone && barCodeClone.length === 13) { + barCodeClone = Number(barCodeClone); + //去掉空 + if (!isNaN(barCodeClone)) { + JsBarcode("#barcode", barCodeClone, { + format: "EAN13", // 指定条形码格式 + width: 1, //1.5 + height: 30, + displayValue: false //不显示条形码下面的文字 + }); + // 获取 SVG 元素 + let svgElement = document.getElementById("barcode-box"); + image64 = svgElement.innerHTML; + LODOP.ADD_PRINT_IMAGE(83, 226, "80%", "100%", svgElement.innerHTML); + let str = barCodeClone + ""; + let str1 = str.substring(0, 1); + let str2 = str.substring(1, 7); + let str3 = str.substring(7, 14); + //224 + LODOP.ADD_PRINT_TEXT(130, 231, "10mm", "10mm", `${str1}`); + LODOP.SET_PRINT_STYLEA(0, "FontName", "SourceHanSansCN-Bold"); + //238 + LODOP.ADD_PRINT_TEXT(130, 245, "15mm", "10mm", `${str2}`); + LODOP.SET_PRINT_STYLEA(0, "FontName", "SourceHanSansCN-Bold"); + //283 + LODOP.ADD_PRINT_TEXT(130, 290, "15mm", "10mm", `${str3}`); + LODOP.SET_PRINT_STYLEA(0, "FontName", "SourceHanSansCN-Bold"); + } + } + + //产品名称 + if (materialName) { + LODOP.ADD_PRINT_TEXT(37, 8, "20mm", "10mm", "产品名称:"); + LODOP.ADD_PRINT_TEXT(37, 64, "45mm", 20, `${materialName}`); + LODOP.SET_PRINT_STYLEA(0, "TextOverflow", 2); + LODOP.SET_PRINT_STYLEA(0, "LineSpacing", -4); + } + + //二维码 + if (orderBillNo) { + let options = { + type: "image/jpeg", //类型 + quality: 1, //图片质量A Number between 0 and 1 + width: 49, //高度 + height: 49, //宽度 + errorCorrectionLevel: "H", //容错率 + margin: 0, //外边距 + color: { + dark: "#000000", //前景色 + light: "#ffffff" //背景色 + } + }; + + QRCode.toString(orderBillNo, options, (error, string) => { + if (error) { + throw error; + } + // 获取 SVG 元素 + let svgElement = document.getElementById("qrcode-box"); + let qrSvgElement = document.getElementById("qrcode"); + qrSvgElement.innerHTML = string; + imageCode = svgElement.innerHTML; + LODOP.ADD_PRINT_IMAGE(42, 236, "100%", "100%", imageCode); + }); + } + //尾数图片 + if (isTail) { + let weishuElement = `
尾数
+ `; + LODOP.ADD_PRINT_HTM(68, 295, "45mm", "100%", weishuElement); + LODOP.SET_PRINT_STYLEA(0, "Angle", 30); + LODOP.ADD_PRINT_ELLIPSE(48, 293, 40, 40, 1, 1); + } + //订单号 + LODOP.ADD_PRINT_TEXT(65, 8, "78mm", 10, `订单号:${orderBillNo}`); + LODOP.SET_PRINT_STYLEA(0, "Overflow", 2); + //装箱序号 + if (isTail) { + LODOP.ADD_PRINT_TEXT(85, 8, "50mm", "10mm", `装箱序号:${boxSortCount + "/" + boxSortCount}`); + } else { + LODOP.ADD_PRINT_TEXT(85, 8, "50mm", "10mm", `装箱序号:${sort + "/" + boxSortCount}`); + } + + //净重 + LODOP.ADD_PRINT_TEXT(85, 107, "30mm", "10mm", `净重:${isTail ? tailboxNetWeightQty : cratingNetWeightQty} KG`); + //装箱数量 + + //特殊处理:当可装箱数量大于产品数量时,要取产品数量 + if (cratingQty > productQty) { + LODOP.ADD_PRINT_TEXT(107, 8, "50mm", "10mm", `装箱数量:${productQty} PCS`); + } else { + LODOP.ADD_PRINT_TEXT(107, 8, "50mm", "10mm", `装箱数量:${isTail ? tailboxQty : cratingQty} PCS`); + } + //毛重 + LODOP.ADD_PRINT_TEXT(107, 107, "30mm", "10mm", `毛重:${isTail ? tailboxGrossWeightQty : cratingGrossWeightQty} KG`); + //日期 + let createTimeClone = createTime.substring(0, 10); + LODOP.ADD_PRINT_TEXT(129, 8, "50mm", "10mm", `日期:${createTimeClone}`); + + logStr = `规格型号:【${specifications}】->订单:【${orderBillNo}】->条码:【${barCodeClone}】->条码图片路径:【${image64}】->序号:【${ + isTail ? boxSortCount + "/" + boxSortCount : sort + "/" + boxSortCount + }】->二维码:【${imageCode}】`; + logs.push(logStr); +} diff --git a/src/utils/print/index.js b/src/utils/print/index.js new file mode 100644 index 0000000..e69de29 diff --git a/src/utils/print/print.js b/src/utils/print/print.js new file mode 100644 index 0000000..623e23f --- /dev/null +++ b/src/utils/print/print.js @@ -0,0 +1,149 @@ +let CreatedOKLodop7766 = null; +import { ElMessageBox } from "element-plus"; + +export function needCLodop() { + try { + let ua = navigator.userAgent; + if (ua.match(/Windows\sPhone/i) != null) return true; + if (ua.match(/iPhone|iPod/i) != null) return true; + if (ua.match(/Android/i) != null) return true; + if (ua.match(/Edge\D?\d+/i) != null) return true; + + let verTrident = ua.match(/Trident\D?\d+/i); + let verIE = ua.match(/MSIE\D?\d+/i); + let verOPR = ua.match(/OPR\D?\d+/i); + let verFF = ua.match(/Firefox\D?\d+/i); + let x64 = ua.match(/x64/i); + if (verTrident == null && verIE == null && x64 !== null) return true; + else if (verFF !== null) { + verFF = verFF[0].match(/\d+/); + if (verFF[0] >= 41 || x64 !== null) return true; + } else if (verOPR !== null) { + verOPR = verOPR[0].match(/\d+/); + if (verOPR[0] >= 32) return true; + } else if (verTrident == null && verIE == null) { + let verChrome = ua.match(/Chrome\D?\d+/i); + if (verChrome !== null) { + verChrome = verChrome[0].match(/\d+/); + if (verChrome[0] >= 41) return true; + } + } + return false; + } catch (err) { + return true; + } +} + +//====页面引用CLodop云打印必须的JS文件:==== +if (needCLodop()) { + let head = document.head || document.getElementsByTagName("head")[0] || document.documentElement; + let oscript = document.createElement("script"); + oscript.src = "http://localhost:8000/CLodopfuncs.js?priority=1"; + head.insertBefore(oscript, head.firstChild); + + //引用双端口(8000和18000)避免其中某个被占用: + oscript = document.createElement("script"); + oscript.src = "http://localhost:18000/CLodopfuncs.js?priority=0"; + head.insertBefore(oscript, head.firstChild); +} + +//====获取LODOP对象的主过程:==== +export function getLodop(oOBJECT, oEMBED) { + let strHtmInstall = + "
打印控件未安装!点击这里执行安装,安装后请刷新页面或重新进入。"; + let strHtmUpdate = + "
打印控件需要升级!点击这里执行升级,升级后请重新进入。"; + let strHtm64_Install = + "
打印控件未安装!点击这里执行安装,安装后请刷新页面或重新进入。"; + let strHtm64_Update = + "
打印控件需要升级!点击这里执行升级,升级后请重新进入。"; + let strHtmFireFox = + "

(注意:如曾安装过Lodop旧版附件npActiveXPLugin,请在【工具】->【附加组件】->【扩展】中先卸它)"; + let strHtmChrome = + "

(如果此前正常,仅因浏览器升级或重安装而出问题,需重新执行以上安装)"; + let strCLodopInstall = + "CLodop云打印服务(localhost本地)未安装启动!点击下载执行安装,安装后请刷新页面再尝试打印。"; + let strCLodopUpdate = + "
CLodop云打印服务需升级!点击这里执行升级,升级后请刷新页面。"; + let LODOP; + try { + let isIE = navigator.userAgent.indexOf("MSIE") >= 0 || navigator.userAgent.indexOf("Trident") >= 0; + if (needCLodop()) { + try { + LODOP = getCLodop(); + } catch (err) { + console.log(err); + } + if (!LODOP && document.readyState !== "complete") { + alert("C-Lodop没准备好,请稍后再试!"); + return; + } + if (!LODOP) { + if (isIE) document.write(strCLodopInstall); + else + ElMessageBox.alert(strCLodopInstall, "安装使用提示", { + dangerouslyUseHTMLString: true, + confirmButtonText: "下载" + }).then(() => { + const elink = document.createElement("a"); + elink.href = "http://www.lodop.net/demolist/CLodop_Setup_for_Win32NT.zip"; //file.url + elink.download = "xyqzmb.xls"; //file.name + elink.style.display = "none"; + //link.target="_blank"; + elink.click(); + }); + // document.body.innerHTML = + // strCLodopInstall + document.body.innerHTML + return; + } else { + if (CLODOP.CVERSION < "3.0.4.3") { + if (isIE) document.write(strCLodopUpdate); + else document.body.innerHTML = strCLodopUpdate + document.body.innerHTML; + } + if (oEMBED && oEMBED.parentNode) oEMBED.parentNode.removeChild(oEMBED); + if (oOBJECT && oOBJECT.parentNode) oOBJECT.parentNode.removeChild(oOBJECT); + } + } else { + let is64IE = isIE && navigator.userAgent.indexOf("x64") >= 0; + //=====如果页面有Lodop就直接使用,没有则新建:========== + if (oOBJECT != undefined || oEMBED != undefined) { + if (isIE) LODOP = oOBJECT; + else LODOP = oEMBED; + } else if (CreatedOKLodop7766 == null) { + LODOP = document.createElement("object"); + LODOP.setAttribute("width", 0); + LODOP.setAttribute("height", 0); + LODOP.setAttribute("style", "position:absolute;left:0px;top:-100px;width:0px;height:0px;"); + if (isIE) LODOP.setAttribute("classid", "clsid:2105C259-1E0C-4534-8141-A753534CB4CA"); + else LODOP.setAttribute("type", "application/x-print-lodop"); + document.documentElement.appendChild(LODOP); + CreatedOKLodop7766 = LODOP; + } else LODOP = CreatedOKLodop7766; + //=====Lodop插件未安装时提示下载地址:========== + if (LODOP == null || typeof LODOP.VERSION == "undefined") { + if (navigator.userAgent.indexOf("Chrome") >= 0) document.body.innerHTML = strHtmChrome + document.body.innerHTML; + if (navigator.userAgent.indexOf("Firefox") >= 0) + document.body.innerHTML = strHtmFireFox + document.body.innerHTML; + if (is64IE) document.write(strHtm64_Install); + else if (isIE) document.write(strHtmInstall); + else document.body.innerHTML = strHtmInstall + document.body.innerHTML; + + return LODOP; + } + } + if (LODOP.VERSION < "6.2.2.3") { + if (!needCLodop()) { + if (is64IE) document.write(strHtm64_Update); + else if (isIE) document.write(strHtmUpdate); + else document.body.innerHTML = strHtmUpdate + document.body.innerHTML; + } + return LODOP; + } + //===如下空白位置适合调用统一功能(如注册语句、语言选择等):=== + + //=========================================================== + return LODOP; + } catch (err) { + alert("getLodop出错:" + err); + } +} diff --git a/src/utils/rexg/index.ts b/src/utils/rexg/index.ts new file mode 100644 index 0000000..894ae37 --- /dev/null +++ b/src/utils/rexg/index.ts @@ -0,0 +1,8 @@ +import { inputEnterRexg } from "./inputEnterRexg"; +import { numberRexg } from "./numberRexg"; +import { productRexg } from "./productRexg"; +import { integerRexg } from "./integerRexg"; +import { unitMultipleInputRexg } from "./unitMultipleInputRexg"; +import { numberRexg1 } from "./numberRexg1"; +import { numberDecimalSeparatorRexg } from "./numberDecimalSeparatorRexg"; +export { numberRexg, inputEnterRexg, productRexg, integerRexg, unitMultipleInputRexg, numberRexg1, numberDecimalSeparatorRexg }; diff --git a/src/utils/rexg/inputEnterRexg.ts b/src/utils/rexg/inputEnterRexg.ts new file mode 100644 index 0000000..2b0c42e --- /dev/null +++ b/src/utils/rexg/inputEnterRexg.ts @@ -0,0 +1,26 @@ +import { useMsg } from "@/hooks/useMsg"; +//只允许输入数字和6位小数 +export const inputEnterRexg = function (inputValue: any, empty?: any) { + inputValue = inputValue.replace(/[^\d.]/g, ""); // 清除"数字"和"."以外的字符 只能输入数字和小数点 + inputValue = inputValue.replace(/\.{2,}/g, "."); // 不能连续输入两个及以上小数点 + inputValue = inputValue.replace(".", "$#$").replace(/\./g, "").replace("$#$", "."); // 只保留第一个".", 清除多余的"." + inputValue = inputValue.replace(/^(-)*(\d+)\.(\d\d\d\d\d\d).*$/, "$1$2.$3"); // 只能输入六位小数 + if (inputValue && inputValue.indexOf(".") < 0 && inputValue != "") { + inputValue = parseFloat(inputValue); + inputValue = inputValue + ""; + inputValue = inputValue.slice(0, 8); + } // 如果没有小数点,首位不能为类似于 01、02的值 + // 输入过程中,只能输入六位小数且六位小数都为零,则清空小数点和后面的六个零(如果输入完成了只输入四个零,则在blur事件中处理) + if (inputValue.indexOf(".") > 0 && inputValue.length - inputValue.indexOf(".") > 6) { + let str = inputValue.slice(inputValue.indexOf("."), inputValue.length); + if (str / 1 <= 0) { + inputValue = inputValue.replace(str, ""); + } + } + if (inputValue.length > 15) { + useMsg("warning", "仅限数字输入,小数点后最多6位,小数点前最多8位,请重新输入"); + return empty ? "" : 0; + } else { + return inputValue; + } +}; diff --git a/src/utils/rexg/integerRexg.ts b/src/utils/rexg/integerRexg.ts new file mode 100644 index 0000000..0f1dc60 --- /dev/null +++ b/src/utils/rexg/integerRexg.ts @@ -0,0 +1,8 @@ +//只允许输入整数 +export const integerRexg = (value: any) => { + if (!value) { + return; + } + let result = value.replace(/^(0+)|[^\d]+/g, ""); + return result; +}; diff --git a/src/utils/rexg/numberDecimalSeparatorRexg.ts b/src/utils/rexg/numberDecimalSeparatorRexg.ts new file mode 100644 index 0000000..3ba3a93 --- /dev/null +++ b/src/utils/rexg/numberDecimalSeparatorRexg.ts @@ -0,0 +1,11 @@ +//只允许输入数字和小数点 +export const numberDecimalSeparatorRexg = (value: any) => { + if (!value) { + return; + } + + value = value.replace(/[^\d.]/g, ""); // 清除"数字"和"."以外的字符 只能输入数字和小数点 + value = value.replace(/\.{2,}/g, "."); // 不能连续输入两个及以上小数点 + value = value.replace(".", "$#$").replace(/\./g, "").replace("$#$", "."); // 只保留第一个".", 清除多余的"." + return value; +}; diff --git a/src/utils/rexg/numberRexg.ts b/src/utils/rexg/numberRexg.ts new file mode 100644 index 0000000..e25a503 --- /dev/null +++ b/src/utils/rexg/numberRexg.ts @@ -0,0 +1,18 @@ +// 数字验证,小数点前8位&小数点后4位 +export const numberRexg = (value: any) => { + if (value) { + if (value.toString().indexOf(".") != -1) { + let value_after = parseInt(value.toString().substring(0, value.indexOf("."))); + let value_before = value.replace(/\d+\.(\d*)/, "$1"); + if (value_after.toString().length > 8) { + let newValue = value_after.toString().substring(0, 8) + "." + value_before; + return (newValue.toString().match(/\d{1,8}(\.\d{0,4})?/) || [""])[0]; + } else { + return (value.toString().match(/\d{1,8}(\.\d{0,4})?/) || [""])[0]; + } + } + return (value.toString().match(/\d{1,8}(\.\d{0,4})?/) || [""])[0]; + } else { + return ""; + } +}; diff --git a/src/utils/rexg/numberRexg1.ts b/src/utils/rexg/numberRexg1.ts new file mode 100644 index 0000000..adb6c31 --- /dev/null +++ b/src/utils/rexg/numberRexg1.ts @@ -0,0 +1,17 @@ +//前3后4 +export const numberRexg1 = (value: any) => { + if (!value) { + return; + } + if (value.toString().indexOf(".") != -1) { + let value_after = parseInt(value.toString().substring(0, value.indexOf("."))); + let value_before = value.replace(/\d+\.(\d*)/, "$1"); + if (value_after.toString().length > 3) { + let newValue = value_after.toString().substring(0, 3) + "." + value_before; + return (newValue.toString().match(/\d{1,3}(\.\d{0,4})?/) || [""])[0]; + } else { + return (value.toString().match(/\d{1,3}(\.\d{0,4})?/) || [""])[0]; + } + } + return (value.toString().match(/\d{1,3}(\.\d{0,4})?/) || [""])[0]; +}; diff --git a/src/utils/rexg/productRexg.ts b/src/utils/rexg/productRexg.ts new file mode 100644 index 0000000..e3021ab --- /dev/null +++ b/src/utils/rexg/productRexg.ts @@ -0,0 +1,17 @@ +//尺寸/质量信息输入验证 +export const productRexg = (value: any) => { + if (!value) { + return; + } + let result = value + .toString() + .replace(/^0/) + .replace(/[^\d.]/g, "") + .replace(/\.{2,}/g, ".") + .replace(/^\./g, "") + .replace(".", "$#$") + .replace(/\./g, "") + .replace("$#$", ".") + .replace(/^(-)*(\d+)\.(\d\d\d\d).*$/, "$1$2.$3"); + return result; +}; diff --git a/src/utils/rexg/unitMultipleInputRexg.ts b/src/utils/rexg/unitMultipleInputRexg.ts new file mode 100644 index 0000000..9bea87f --- /dev/null +++ b/src/utils/rexg/unitMultipleInputRexg.ts @@ -0,0 +1,13 @@ +export const unitMultipleInputRexg = (value: any) => { + if (!value) { + return; + } + let result = value + .toString() + .replace(/[^\d^\\.]+/g, "") + .replace(".", "$#$") + .replace(/\./g, "") + .replace("$#$", ".") + .replace(/^(\\-)*(\d+)\.(\d\d\d\d\d\d\d\d).*$/, "$1$2.$3"); + return result; +}; diff --git a/src/utils/serviceDict.ts b/src/utils/serviceDict.ts new file mode 100644 index 0000000..2c65f3c --- /dev/null +++ b/src/utils/serviceDict.ts @@ -0,0 +1,17 @@ +// ? 系统全局字典 + +/** + * @description:用户性别 + */ +export const genderType = [ + { label: "男", value: 1 }, + { label: "女", value: 2 } +]; + +/** + * @description:用户状态 + */ +export const userStatus = [ + { label: "启用", value: 1 }, + { label: "禁用", value: 0 } +]; diff --git a/src/utils/svg.ts b/src/utils/svg.ts new file mode 100644 index 0000000..0c191c9 --- /dev/null +++ b/src/utils/svg.ts @@ -0,0 +1,13 @@ +/** + * @description Loading Svg + */ +export const loadingSvg = ` + +`; diff --git a/src/views/GeneralManagement/list/constant/list/index.ts b/src/views/GeneralManagement/list/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/GeneralManagement/list/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/GeneralManagement/list/constant/list/search.ts b/src/views/GeneralManagement/list/constant/list/search.ts new file mode 100644 index 0000000..1f93259 --- /dev/null +++ b/src/views/GeneralManagement/list/constant/list/search.ts @@ -0,0 +1,23 @@ +//search静态数据 + +export const FORMDATA: any[] = [ + { + prop: "corp_name", + placeholder: "文本模糊查询", + type: "input", + label: "公司名称" + }, + { + prop: "corp_id", + placeholder: "文本模糊查询", + type: "input", + label: "公司名称" + } +]; + +export const RULEFORM = { + corp_name: "", + corp_nameid: "", + page: 1, + size: 50 +}; diff --git a/src/views/GeneralManagement/list/constant/list/table.ts b/src/views/GeneralManagement/list/constant/list/table.ts new file mode 100644 index 0000000..78af74b --- /dev/null +++ b/src/views/GeneralManagement/list/constant/list/table.ts @@ -0,0 +1,42 @@ +// import { STATUS } from "@/constant"; +// import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + label: "公司名称", + prop: "Corp_name" + }, + { + align: "left", + label: "纳税人识别号", + prop: "corp_taxpayer_identify_no" + }, + { + align: "left", + label: "对接乐企ID", + prop: "corp_platform_no" + }, + { + align: "left", + label: "金蝶编码", + prop: "corp_org_code" + }, + { + align: "left", + label: "状态", + prop: "status" + }, + { + align: "left", + label: "更新时间", + prop: "updated_at" + }, + { + align: "center", + label: "更新账号", + prop: "updated_by" + } +]; diff --git a/src/views/GeneralManagement/list/index.vue b/src/views/GeneralManagement/list/index.vue new file mode 100644 index 0000000..13e5ce5 --- /dev/null +++ b/src/views/GeneralManagement/list/index.vue @@ -0,0 +1,263 @@ + + + + + diff --git a/src/views/InvoiceManagement/list/constant/list/index.ts b/src/views/InvoiceManagement/list/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/InvoiceManagement/list/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/InvoiceManagement/list/constant/list/search.ts b/src/views/InvoiceManagement/list/constant/list/search.ts new file mode 100644 index 0000000..a20a88c --- /dev/null +++ b/src/views/InvoiceManagement/list/constant/list/search.ts @@ -0,0 +1,125 @@ +//search静态数据 +export const FORMDATA: any[] = [ + { + prop: "invoice_no", + placeholder: "支持模糊查询", + type: "input", + label: "发票号码" + }, + { + prop: "buyer_tax_id", + placeholder: "支持模糊查询", + type: "input", + label: "购方税号" + }, + { + prop: "buyer_name", + placeholder: "支持模糊查询", + type: "input", + label: "购方名称" + }, + { + prop: "invoice_type", + placeholder: "请选择", + type: "select", + options: [{}], + label: "发票类型" + }, + { + prop: "backfill", + placeholder: "请选择", + type: "select", + options: [ + { + label: "成功", + value: "success" + }, + { + label: "失败", + value: "fail" + }, + { + label: "空", + value: "pending" + } + ], + label: "回传结果" + }, + { + prop: "kingdee_billno", + placeholder: "支持模糊查询", + type: "input", + label: "金蝶单据编号" + }, + { + prop: "invoice_clerk", + placeholder: "支持模糊查询", + type: "input", + label: "开票人" + }, + { + prop: "issue_date", + type: "daterange", + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "开票日期" + }, + { + prop: "status", + placeholder: "请选择", + type: "select", + options: [ + { + label: "成功", + value: "success" + }, + { + label: "失败", + value: "fail" + }, + { + label: "开票中", + value: "pending" + } + ], + label: "开票结果" + }, + { + prop: "uploaded_summary", + placeholder: "请选择", + type: "select", + options: [ + { + label: "是", + value: 1 + }, + { + label: "否", + value: 0 + } + ], + label: "汇总结果" + }, + { + prop: "seller_corp_id", + placeholder: "请选择", + type: "select", + options: [], + label: "销售方名称" + } +]; + +export const RULEFORM = { + invoice_no: "", + buyer_tax_id: "", + buyer_name: "", + invoice_type: "", + backfill: "", + kingdee_billno: "", + invoice_clerk: "", + issue_date: [], + status: "", + seller_corp_id: "", + page: 1, + size: 50 +}; diff --git a/src/views/InvoiceManagement/list/constant/list/table.ts b/src/views/InvoiceManagement/list/constant/list/table.ts new file mode 100644 index 0000000..886b08c --- /dev/null +++ b/src/views/InvoiceManagement/list/constant/list/table.ts @@ -0,0 +1,99 @@ +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + label: "发票号码", + width: "180", + prop: "invoice_no" + }, + { + align: "left", + label: "金蝶单据编号", + width: "150", + prop: "kingdee_billno" + }, + { + align: "left", + label: "购方名称", + width: "200", + prop: "buyer_name" + }, + { + align: "left", + label: "购方税号", + width: "170", + prop: "buyer_tax_id" + }, + { + align: "left", + label: "销售方名称", + width: "200", + prop: "seller_name" + }, + { + align: "left", + label: "销售方税号", + width: "170", + prop: "seller_tax_id" + }, + { + align: "center", + label: "发票类型", + width: "150", + prop: "invoice_type_zh" + }, + { + align: "center", + label: "红蓝字", + prop: "red_blue" + }, + { + align: "right", + label: "价税合计", + prop: "tax_inclusive_total_amount" + }, + { + align: "right", + label: "税额", + prop: "tax_total_amount" + }, + { + align: "right", + label: "数量", + prop: "total_qty" + }, + { + align: "center", + label: "开票日期", + width: "150", + prop: "issue_date" + }, + { + align: "center", + label: "开票人", + prop: "invoice_clerk" + }, + { + align: "center", + label: "邮箱", + width: "150", + prop: "kingdee_invoice_recv_email" + }, + { + align: "center", + label: "发票汇总确认", + width: "150", + prop: "uploaded_summary" + }, + { + align: "center", + label: "开票结果", + prop: "status" + }, + { + align: "center", + label: "回传金蝶", + prop: "backfill" + } +]; diff --git a/src/views/InvoiceManagement/list/index.vue b/src/views/InvoiceManagement/list/index.vue new file mode 100644 index 0000000..dfb18db --- /dev/null +++ b/src/views/InvoiceManagement/list/index.vue @@ -0,0 +1,406 @@ + + + + + diff --git a/src/views/deliveryAndOutbound/outboundOrderList/constant/list/details.ts b/src/views/deliveryAndOutbound/outboundOrderList/constant/list/details.ts new file mode 100644 index 0000000..7b16ad3 --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundOrderList/constant/list/details.ts @@ -0,0 +1,33 @@ +export const FORMDATA: any[] = [ + { + prop: "creator", + label: "创建人", + type: "input", + disabled: true + }, + { + prop: "createTime", + label: "创建时间", + type: "input", + disabled: true + }, + { + prop: "operate", + label: "最后修改人", + type: "input", + disabled: true + }, + + { + prop: "syncTime", + label: "重传时间", + type: "input", + disabled: true + } +]; +export const RULEFORM: Record = { + syncTime: "", + operate: "", + createTime: "", + creator: "" +}; diff --git a/src/views/deliveryAndOutbound/outboundOrderList/constant/list/index.ts b/src/views/deliveryAndOutbound/outboundOrderList/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundOrderList/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/deliveryAndOutbound/outboundOrderList/constant/list/search.ts b/src/views/deliveryAndOutbound/outboundOrderList/constant/list/search.ts new file mode 100644 index 0000000..b397a5e --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundOrderList/constant/list/search.ts @@ -0,0 +1,81 @@ +export const FORMDATA: any[] = [ + { + prop: "sourceBillNo", + placeholder: "请输入来源单号", + type: "input", + label: "来源单号:" + }, + { + prop: "type", + placeholder: "请选择出库类型", + type: "select", + options: [], + label: "出库类型:" + }, + { + prop: "stockCode", //stockCode + placeholder: "请选择仓库", + type: "select", + options: [], + label: "仓库:" + }, + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "出库日期:" + }, + + { + prop: "materialNumber", + placeholder: "请输入物料名称/规格型号/编码", + type: "input", + label: "物料:" + }, + { + prop: "deliveryOrgId", + placeholder: "请输入组织", + type: "selectRemote", + label: "组织:", + options: [] + }, + { + prop: "receiptCustomer", + placeholder: "请选择收货客户", + type: "selectRemote", + label: "收货客户:", + options: [] + }, + // { + // prop: "successSync", + // placeholder: "请选择同步状态", + // type: "select", + // options: [], + // label: "同步状态:" + // }, + { + prop: "creator", + placeholder: "请输入创建人", + type: "input", + label: "创建人:" + } +]; + +export const RULEFORM: any = { + pageNo: 1, + pageSize: 50, + createBeginDate: "", + createEndDate: "", + type: "", + creator: "", + successSync: "", + sourceBillNo: "", + deliveryOrgId: "", + receiptCustomer: "", + materialNumber: "", + stockCode: "", + orgId: null, // 组织ID + time: "" +}; diff --git a/src/views/deliveryAndOutbound/outboundOrderList/constant/list/table.ts b/src/views/deliveryAndOutbound/outboundOrderList/constant/list/table.ts new file mode 100644 index 0000000..68b0929 --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundOrderList/constant/list/table.ts @@ -0,0 +1,100 @@ +// import { STATUS } from "@/constant"; +// import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + fixed: true, + label: "出库单号", + prop: "billNo", + width: "187", + isCode: true + }, + { + align: "left", + label: "来源单号", + prop: "sourceBillNo", + width: "110" + }, + { + align: "left", + label: "销售订单号", + prop: "saleBillNo", + width: "110" + }, + { + align: "left", + label: "发货组织", + prop: "deliveryOrg", + width: "100" + }, + { + align: "left", + label: "收货客户", + prop: "receiptCustomer", + width: "80" + }, + { + align: "left", + label: "出库类型", + prop: "type", + width: "120" + }, + { + align: "left", + label: "规格型号", + prop: "specifications", + width: "172" + }, + { + align: "left", + label: "物料编码", + prop: "materialNumber", + width: "120" + }, + { + align: "left", + label: "物料名称", + prop: "materialName", + width: "120" + }, + { + align: "left", + label: "单位", + prop: "unit", + width: "172" + }, + { + align: "left", + label: "仓库", + prop: "stock", + width: "172" + }, + { + align: "left", + label: "出库数量", + prop: "qty", + width: "280" + }, + { + align: "left", + label: "创建人", + prop: "creator", + width: "150" + }, + { + align: "left", + label: "出库时间", + prop: "createTime", + width: "160" + } + // { + // align: "left", + // label: "金蝶同步状态", + // prop: "successSync", + // width: "120", + // isCode: true + // } +]; diff --git a/src/views/deliveryAndOutbound/outboundOrderList/details.vue b/src/views/deliveryAndOutbound/outboundOrderList/details.vue new file mode 100644 index 0000000..38b0ac3 --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundOrderList/details.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/src/views/deliveryAndOutbound/outboundOrderList/index.vue b/src/views/deliveryAndOutbound/outboundOrderList/index.vue new file mode 100644 index 0000000..ea4ad33 --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundOrderList/index.vue @@ -0,0 +1,138 @@ + + + + + + diff --git a/src/views/deliveryAndOutbound/outboundOrderList/init/index.ts b/src/views/deliveryAndOutbound/outboundOrderList/init/index.ts new file mode 100644 index 0000000..221adb3 --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundOrderList/init/index.ts @@ -0,0 +1,13 @@ +//全局状态 +import { useStatusStore } from "@/stores/modules/status"; +import { useUserStore } from "@/stores/modules/user"; +const statusStore = useStatusStore(); +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + type: statusStore.status.outStockType, + stockCode: userStore.warehouse, + successSync: statusStore.status.syncStatus + }); +}; diff --git a/src/views/deliveryAndOutbound/outboundTaskList/constant/details/columns.ts b/src/views/deliveryAndOutbound/outboundTaskList/constant/details/columns.ts new file mode 100644 index 0000000..4f2a387 --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundTaskList/constant/details/columns.ts @@ -0,0 +1,47 @@ +//明细信息 +export const COLUMNS = [ + { + label: "箱号", + prop: "boxBillNo", + disabled: false + }, + { + label: "规格型号", + prop: "specifications", + width: "400px", + + disabled: false + }, + { + label: "出库数量", + prop: "qty", + + disabled: false + }, + { + label: "序列号", + prop: "serialNumbers", + disabled: false, + width: "400px" + }, + { + label: "应出库数量", + prop: "accruedQty", + disabled: false + }, + { + label: "出库方式", + prop: "method", + disabled: false + }, + { + label: "出库人", + prop: "creator", + disabled: false + }, + { + label: "出库时间", + prop: "createTime", + disabled: false + } +]; diff --git a/src/views/deliveryAndOutbound/outboundTaskList/constant/details/index.ts b/src/views/deliveryAndOutbound/outboundTaskList/constant/details/index.ts new file mode 100644 index 0000000..45de8ed --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundTaskList/constant/details/index.ts @@ -0,0 +1,3 @@ +import { COLUMNS } from "./columns"; +import { RULEFORM, FORMDATA } from "./search"; +export { RULEFORM, FORMDATA, COLUMNS }; diff --git a/src/views/deliveryAndOutbound/outboundTaskList/constant/details/search.ts b/src/views/deliveryAndOutbound/outboundTaskList/constant/details/search.ts new file mode 100644 index 0000000..f1c1dcc --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundTaskList/constant/details/search.ts @@ -0,0 +1,71 @@ +export const FORMDATA: any[] = [ + { + prop: "billNo", + placeholder: "请输入出库任务单号", + type: "input", + label: "出库任务单号:", + disabled: true + }, + { + prop: "status", + placeholder: "请输入出库状态", + type: "input", + disabled: true, + label: "出库状态:" + }, + { + prop: "sourceBillNo", + placeholder: "请输入来源单号", + type: "input", + disabled: true, + label: "来源单号:" + }, + { + prop: "saleBillNo", + placeholder: "请输入销售订单号", + type: "input", + disabled: true, + label: "销售订单号:" + }, + { + prop: "type", + placeholder: "请输入出库类型", + type: "input", + disabled: true, + label: "出库类型:" + }, + { + prop: "receiptCustomer", + placeholder: "请输入客户", + type: "input", + disabled: true, + label: "客户:" + }, + { + prop: "deliveryOrg", + placeholder: "请输入组织", + type: "input", + disabled: true, + label: "组织:" + }, + { + prop: "createTime", + placeholder: "请输入创建时间", + type: "input", + disabled: true, + label: "创建时间:" + } +]; + +export const RULEFORM: any = { + createTime: "", + type: "", + billNo: "", + status: "", + sourceBillNo: "", + receiptCustomer: "", + deliveryOrg: "", + id: 0, + saleBillNo: "", + details: [] +}; diff --git a/src/views/deliveryAndOutbound/outboundTaskList/constant/list/index.ts b/src/views/deliveryAndOutbound/outboundTaskList/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundTaskList/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/deliveryAndOutbound/outboundTaskList/constant/list/search.ts b/src/views/deliveryAndOutbound/outboundTaskList/constant/list/search.ts new file mode 100644 index 0000000..5213650 --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundTaskList/constant/list/search.ts @@ -0,0 +1,91 @@ +export const FORMDATA: any[] = [ + { + prop: "sourceBillNo", + placeholder: "请输入来源单号", + type: "input", + label: "来源单号:" + }, + { + prop: "type", + placeholder: "请选择出库类型", + type: "select", + options: [], + label: "出库类型:" + }, + { + prop: "stockCode", + placeholder: "请选择仓库", + type: "select", + options: [], + label: "仓库:" + }, + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "出库日期:" + }, + + { + prop: "materialNumber", + placeholder: "请输入物料名称/规格型号/编码", + type: "input", + label: "物料:" + }, + { + prop: "status", + placeholder: "请选择出库状态", + type: "select", + options: [], + label: "出库状态:" + }, + { + prop: "deliveryOrgId", + placeholder: "请输入组织", + type: "selectRemote", + label: "组织:", + options: [] + }, + { + prop: "receiptCustomer", + placeholder: "请选择收货客户", + type: "selectRemote", + label: "收货客户:", + options: [] + }, + { + prop: "boxBillNos", + placeholder: "请输入箱号", + type: "input", + disabled: false, + label: "箱号:" + }, + { + prop: "serialNumbers", + placeholder: "请输入序列号", + type: "input", + disabled: false, + label: "序列号:" + } +]; + +export const RULEFORM: any = { + stockCode: "", + time: "", + pageNo: 1, + pageSize: 20, + materialNumber: "", + receiptCustomer: "", + deliveryOrgId: "", + sourceBillNo: "", + createEndDate: "", + createBeginDate: "", + status: "", + type: "", + ids: [], + serialNumbers: "", + boxBillNos: "", + orgId: null // 组织ID +}; diff --git a/src/views/deliveryAndOutbound/outboundTaskList/constant/list/table.ts b/src/views/deliveryAndOutbound/outboundTaskList/constant/list/table.ts new file mode 100644 index 0000000..9417024 --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundTaskList/constant/list/table.ts @@ -0,0 +1,137 @@ +// import { STATUS } from "@/constant"; +import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + fixed: true, + label: "出库任务单号", + prop: "billNo", + width: "200" + }, + { + align: "left", + label: "出库状态", + prop: "status", + width: "120" + }, + { + align: "left", + label: "来源单号", + prop: "sourceBillNo", + width: "200" + }, + { + align: "left", + label: "销售订单号", + prop: "saleBillNo", + width: "200" + }, + { + align: "left", + label: "发货组织", + prop: "deliveryOrg", + width: "160" + }, + { + align: "left", + label: "收货客户", + prop: "receiptCustomer", + width: "160" + }, + { + align: "left", + label: "出库类型", + prop: "type", + width: "120" + }, + { + align: "left", + label: "规格型号", + prop: "specifications", + width: "160" + }, + { + align: "left", + label: "物料编码", + prop: "materialNumber", + width: "160" + }, + { + align: "left", + label: "物料名称", + prop: "materialName", + width: "160" + }, + { + align: "left", + label: "单位", + prop: "unit", + width: "120" + }, + { + align: "left", + label: "发货仓库", + prop: "stock", + width: "200" + }, + { + align: "left", + label: "应出库数量", + prop: "accruedQty", + width: "120" + }, + { + align: "left", + label: "已出库数据", + prop: "realityQty", + width: "120" + }, + { + align: "left", + label: "出库开始时间", + prop: "outStockBeginTime", //没有 + width: "160" + }, + { + align: "left", + label: "出库完成时间", + prop: "outStockEndTime", //没有 + width: "160" + }, + { + align: "left", + label: "出库人", + prop: "outStock", + width: "120" + }, + { + align: "left", + label: "出库时间", + prop: "outStockTime", + width: "160" + }, + { + align: "left", + label: "订单明细备注", + prop: "remark", + width: "200" + }, + { + align: "left", + label: "是否作废", + prop: "isRepeal", + width: "120", + render: (scope: RenderScope): VNode | string | any => { + return scope.row.isRepeal ? "是" : "否"; + } + }, + { + align: "left", + label: "创建时间", + prop: "createTime", + width: "160" + } +]; diff --git a/src/views/deliveryAndOutbound/outboundTaskList/details.vue b/src/views/deliveryAndOutbound/outboundTaskList/details.vue new file mode 100644 index 0000000..471b36b --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundTaskList/details.vue @@ -0,0 +1,96 @@ + + + + diff --git a/src/views/deliveryAndOutbound/outboundTaskList/index.vue b/src/views/deliveryAndOutbound/outboundTaskList/index.vue new file mode 100644 index 0000000..265846c --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundTaskList/index.vue @@ -0,0 +1,136 @@ + + + + + + diff --git a/src/views/deliveryAndOutbound/outboundTaskList/init/index.ts b/src/views/deliveryAndOutbound/outboundTaskList/init/index.ts new file mode 100644 index 0000000..dd5dc7b --- /dev/null +++ b/src/views/deliveryAndOutbound/outboundTaskList/init/index.ts @@ -0,0 +1,13 @@ +//全局状态 +import { useStatusStore } from "@/stores/modules/status"; +import { useUserStore } from "@/stores/modules/user"; +const statusStore = useStatusStore(); +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + type: statusStore.status.outStockType, + status: statusStore.status.outStockStatus, + stockCode: userStore.warehouse + }); +}; diff --git a/src/views/export/list/constant/list/index.ts b/src/views/export/list/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/export/list/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/export/list/constant/list/search.ts b/src/views/export/list/constant/list/search.ts new file mode 100644 index 0000000..08590ab --- /dev/null +++ b/src/views/export/list/constant/list/search.ts @@ -0,0 +1,44 @@ +//search静态数据 + +export const FORMDATA: any[] = [ + { + prop: "type", + placeholder: "请选择任务类型", + type: "select", + label: "任务类型:", + options: [] + }, + + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "操作开始日期", + endPlaceholder: "操作结束日期", + label: "操作日期:" + }, + { + prop: "status", + placeholder: "请选择状态", + type: "select", + options: [], + label: "状态:" + }, + { + prop: "user", + placeholder: "请输入操作人", + type: "input", + label: "操作人:" + } +]; + +export const RULEFORM = { + user: "", + status: "", + type: "", + time: [], + pageNo: 1, + pageSize: 50, + endDate: "", + beginDate: "" +}; diff --git a/src/views/export/list/constant/list/table.ts b/src/views/export/list/constant/list/table.ts new file mode 100644 index 0000000..d29491e --- /dev/null +++ b/src/views/export/list/constant/list/table.ts @@ -0,0 +1,31 @@ +// import { STATUS } from "@/constant"; +// import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { + align: "left", + label: "任务类型", + prop: "type" + }, + { + align: "left", + label: "操作日期", + prop: "date" + }, + { + align: "left", + label: "状态", + prop: "status" + }, + { + align: "left", + label: "附件", + prop: "filePath" + }, + { + align: "left", + label: "操作人", + prop: "userName" + } +]; diff --git a/src/views/export/list/index.vue b/src/views/export/list/index.vue new file mode 100644 index 0000000..66c72bd --- /dev/null +++ b/src/views/export/list/index.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/views/home/index.scss b/src/views/home/index.scss new file mode 100644 index 0000000..9f37686 --- /dev/null +++ b/src/views/home/index.scss @@ -0,0 +1,12 @@ +.box { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + .box-bg { + width: 70%; + max-width: 1200px; + margin-bottom: 20px; + } +} diff --git a/src/views/home/index.vue b/src/views/home/index.vue new file mode 100644 index 0000000..632560e --- /dev/null +++ b/src/views/home/index.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/src/views/inOtherLibraries/boxModificationsList/constant/list/index.ts b/src/views/inOtherLibraries/boxModificationsList/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/inOtherLibraries/boxModificationsList/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/inOtherLibraries/boxModificationsList/constant/list/search.ts b/src/views/inOtherLibraries/boxModificationsList/constant/list/search.ts new file mode 100644 index 0000000..2646e20 --- /dev/null +++ b/src/views/inOtherLibraries/boxModificationsList/constant/list/search.ts @@ -0,0 +1,56 @@ +export const FORMDATA: any[] = [ + { + prop: "srcsubStockCode", + placeholder: "请选择原仓位", + type: "selectRemote2", + options: [], + label: "原仓位:" + }, + { + prop: "destsubStockCode", + placeholder: "请选择现仓位", + type: "selectRemote2", + options: [], + label: "现仓位:" + }, + { + prop: "srcBox", + placeholder: "请输入原有箱号", + type: "input", + label: "原有箱号:" + }, + { + prop: "destBox", + placeholder: "请输入目标箱号", + type: "input", + label: "目标箱号:" + }, + + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "操作日期:" + }, + { + prop: "creator", + placeholder: "请输入操作人", + type: "input", + label: "操作人:" + } +]; + +export const RULEFORM: any = { + pageNo: 1, + pageSize: 20, + srcBox: "", + destBox: "", + srcsubStockCode: "", + destsubStockCode: "", + creator: "", + createBeginDate: "", + createEndDate: "", + time: "" +}; diff --git a/src/views/inOtherLibraries/boxModificationsList/constant/list/table.ts b/src/views/inOtherLibraries/boxModificationsList/constant/list/table.ts new file mode 100644 index 0000000..eed00a1 --- /dev/null +++ b/src/views/inOtherLibraries/boxModificationsList/constant/list/table.ts @@ -0,0 +1,71 @@ +// import { STATUS } from "@/constant"; +// import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + label: "单据号", + fixed: true, + prop: "billNo" + }, + { + align: "left", + fixed: true, + label: "规格型号", + prop: "specifications" + }, + { + align: "left", + label: "物料名称", + prop: "materialName" + }, + { + align: "left", + label: "物料编码", + prop: "materialNumber" + }, + { + align: "left", + label: "序列号", + prop: "serialNumbers" + }, + { + align: "left", + label: "原有箱号", + prop: "srcBox" + }, + { + align: "left", + label: "原仓位", + prop: "srcSubStock" + }, + { + align: "left", + label: "目标箱号", + prop: "destBox" + }, + { + align: "left", + label: "现仓位", + prop: "destSubStock" + }, + { + align: "left", + label: "数量", + prop: "qty" + }, + + { + align: "left", + label: "操作时间", + prop: "createTime", + width: "160" + }, + { + align: "left", + label: "操作人", + prop: "creator" + } +]; diff --git a/src/views/inOtherLibraries/boxModificationsList/index.vue b/src/views/inOtherLibraries/boxModificationsList/index.vue new file mode 100644 index 0000000..ccd6e06 --- /dev/null +++ b/src/views/inOtherLibraries/boxModificationsList/index.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/src/views/inOtherLibraries/inboundOutboundRollbackList/constant/list/index.ts b/src/views/inOtherLibraries/inboundOutboundRollbackList/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/inOtherLibraries/inboundOutboundRollbackList/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/inOtherLibraries/inboundOutboundRollbackList/constant/list/search.ts b/src/views/inOtherLibraries/inboundOutboundRollbackList/constant/list/search.ts new file mode 100644 index 0000000..00fa76c --- /dev/null +++ b/src/views/inOtherLibraries/inboundOutboundRollbackList/constant/list/search.ts @@ -0,0 +1,47 @@ +export const FORMDATA: any[] = [ + { + prop: "type", + placeholder: "请选择操作类型", + type: "select", + options: [], + label: "操作类型:" + }, + { + prop: "subStockCode", + placeholder: "请输入仓位", + type: "selectRemote", + label: "仓位:", + options: [] + }, + { + prop: "boxBillNo", + placeholder: "请选择箱号", + type: "input", + label: "箱号:" + }, + + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "操作日期:" + }, + { + prop: "creator", + placeholder: "请选择操作人", + type: "input", + label: "操作人:" + } +]; + +export const RULEFORM: any = { + creator: "", + time: "", + boxBillNo: "", + subStockCode: "", + type: "", + createBeginDate: "", + createEndDate: "" +}; diff --git a/src/views/inOtherLibraries/inboundOutboundRollbackList/constant/list/table.ts b/src/views/inOtherLibraries/inboundOutboundRollbackList/constant/list/table.ts new file mode 100644 index 0000000..e88f0ae --- /dev/null +++ b/src/views/inOtherLibraries/inboundOutboundRollbackList/constant/list/table.ts @@ -0,0 +1,73 @@ +// import { STATUS } from "@/constant"; +import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + label: "单据号", + prop: "billNo", + fixed: true + }, + { + align: "left", + fixed: true, + label: "单据类型", + prop: "type" + }, + { + align: "left", + label: "箱号", + prop: "boxBillNo" + }, + { + align: "left", + label: "仓位", + prop: "subStock" + }, + { + align: "left", + label: "规格型号", + prop: "specifications" + }, + { + align: "left", + label: "物料名称", + prop: "materialName" + }, + { + align: "left", + label: "物料编码", + prop: "materialNumber" + }, + { + align: "left", + label: "序列号", + prop: "serialNumbers" + }, + { + align: "left", + label: "操作数量", + prop: "qty" + }, + { + align: "left", + label: "操作时间", + prop: "createTime", + width: "160" + }, + { + align: "left", + label: "操作人", + prop: "creator" + }, + { + align: "left", + label: "备注", + prop: "remark", + render: (scope: RenderScope): VNode | string | any => { + return scope.row.remark ? scope.row.remark : ""; + } + } +]; diff --git a/src/views/inOtherLibraries/inboundOutboundRollbackList/index.vue b/src/views/inOtherLibraries/inboundOutboundRollbackList/index.vue new file mode 100644 index 0000000..a5da05d --- /dev/null +++ b/src/views/inOtherLibraries/inboundOutboundRollbackList/index.vue @@ -0,0 +1,80 @@ + + + + + + diff --git a/src/views/inOtherLibraries/inboundOutboundRollbackList/init/index.ts b/src/views/inOtherLibraries/inboundOutboundRollbackList/init/index.ts new file mode 100644 index 0000000..954c01a --- /dev/null +++ b/src/views/inOtherLibraries/inboundOutboundRollbackList/init/index.ts @@ -0,0 +1,12 @@ +//全局状态 +import { useStatusStore } from "@/stores/modules/status"; +import { useUserStore } from "@/stores/modules/user"; +const statusStore = useStatusStore(); +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + type: statusStore.status.backRecordType, + stockCode: userStore.warehouse + }); +}; diff --git a/src/views/inOtherLibraries/movingBoxesList/constant/list/index.ts b/src/views/inOtherLibraries/movingBoxesList/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/inOtherLibraries/movingBoxesList/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/inOtherLibraries/movingBoxesList/constant/list/search.ts b/src/views/inOtherLibraries/movingBoxesList/constant/list/search.ts new file mode 100644 index 0000000..443120d --- /dev/null +++ b/src/views/inOtherLibraries/movingBoxesList/constant/list/search.ts @@ -0,0 +1,40 @@ +export const FORMDATA: any[] = [ + { + prop: "type", + placeholder: "请选择操作类型", + type: "select", + options: [], + label: "操作类型:" + }, + { + prop: "box", + placeholder: "请选择箱号", + type: "input", + label: "箱号:" + }, + { + prop: "creator", + placeholder: "请选择操作人", + type: "input", + label: "操作人:" + }, + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "操作日期:" + } +]; + +export const RULEFORM: any = { + time: "", + createBeginDate: "", + createEndDate: "", + creator: "", + box: "", + type: "", + pageSize: 20, + pageNo: 1 +}; diff --git a/src/views/inOtherLibraries/movingBoxesList/constant/list/table.ts b/src/views/inOtherLibraries/movingBoxesList/constant/list/table.ts new file mode 100644 index 0000000..db9ed4b --- /dev/null +++ b/src/views/inOtherLibraries/movingBoxesList/constant/list/table.ts @@ -0,0 +1,55 @@ +// import { STATUS } from "@/constant"; +// import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + label: "单据号", + prop: "billNo", + fixed: true + }, + { + align: "left", + label: "操作类型", + prop: "type" + }, + // { + // align: "left", + // label: "规格型号", + // prop: "specifications" + // }, + + { + align: "left", + label: "箱号", + prop: "box" + }, + { + align: "left", + label: "数量", + prop: "qty" + }, + { + align: "left", + label: "原仓位", + prop: "srcSubStock" + }, + { + align: "left", + label: "新仓位", + prop: "destSubStock" + }, + { + align: "left", + label: "操作时间", + prop: "createTime", + width: "172" + }, + { + align: "left", + label: "操作人", + prop: "creator" + } +]; diff --git a/src/views/inOtherLibraries/movingBoxesList/index.vue b/src/views/inOtherLibraries/movingBoxesList/index.vue new file mode 100644 index 0000000..f802c4b --- /dev/null +++ b/src/views/inOtherLibraries/movingBoxesList/index.vue @@ -0,0 +1,65 @@ + + + + + + diff --git a/src/views/inOtherLibraries/movingBoxesList/init/index.ts b/src/views/inOtherLibraries/movingBoxesList/init/index.ts new file mode 100644 index 0000000..f922432 --- /dev/null +++ b/src/views/inOtherLibraries/movingBoxesList/init/index.ts @@ -0,0 +1,12 @@ +//全局状态 +import { useStatusStore } from "@/stores/modules/status"; +import { useUserStore } from "@/stores/modules/user"; +const statusStore = useStatusStore(); +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + type: statusStore.status.moveBoxType, + stockCode: userStore.warehouse + }); +}; diff --git a/src/views/inventory/inventoryList/constant/list/index.ts b/src/views/inventory/inventoryList/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/inventory/inventoryList/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/inventory/inventoryList/constant/list/search.ts b/src/views/inventory/inventoryList/constant/list/search.ts new file mode 100644 index 0000000..1b38504 --- /dev/null +++ b/src/views/inventory/inventoryList/constant/list/search.ts @@ -0,0 +1,55 @@ +export const FORMDATA: any[] = [ + { + prop: "stockCode", + placeholder: "请选择仓库", + type: "select", + options: [], + label: "仓库:" + }, + { + prop: "resultType", + placeholder: "请选择盘点结果", + type: "select", + options: [], + label: "盘点结果:" + }, + { + prop: "billNo", + placeholder: "请选择盘盈亏单号", + type: "input", + label: "盘盈亏单号:" + }, + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "盘点日期:" + }, + + { + prop: "materialNumber", + placeholder: "请输入物料名称/规格型号/编码", + type: "input", + label: "物料:" + } + // { + // prop: "successSync", + // placeholder: "请选择同步状态", + // type: "select", + // options: [], + // label: "同步状态:" + // } +]; + +export const RULEFORM: any = { + materialNumber: "", + billNo: "", + resultType: "", + stockCode: "", + time: "", + dateBeginDate: "", + dateEndDate: "", + successSync: "" +}; diff --git a/src/views/inventory/inventoryList/constant/list/table.ts b/src/views/inventory/inventoryList/constant/list/table.ts new file mode 100644 index 0000000..950af1e --- /dev/null +++ b/src/views/inventory/inventoryList/constant/list/table.ts @@ -0,0 +1,92 @@ +// import { STATUS } from "@/constant"; +// import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + fixed: true, + label: "盘点结果", + prop: "resultType", + width: "120" + }, + { + align: "left", + label: "盘盈亏单号", + prop: "billNo", + width: "200" + }, + { + align: "left", + label: "仓库", + prop: "stock", + width: "160" + }, + { + align: "left", + label: "子仓库", + prop: "erp_SubStock", + width: "160" + }, + { + align: "left", + label: "盘点日期", + prop: "date", + width: "120" + }, + { + align: "left", + label: "规格型号", + prop: "specifications", + width: "160" + }, + { + align: "left", + label: "物料编码", + prop: "materialNumber", + width: "160" + }, + { + align: "left", + label: "物料名称", + prop: "materialName", + width: "160" + }, + { + align: "left", + label: "单位", + prop: "unit", + width: "120" + }, + { + align: "left", + label: "系统库存", + prop: "beforeQty", + width: "120" + }, + { + align: "left", + label: "盘点数量", + prop: "afterQty", + width: "120" + }, + { + align: "left", + label: "盈亏数量", + prop: "finalQty", + width: "120" + }, + { + align: "left", + label: "备注", + prop: "remark", + width: "200" + } + // { + // align: "left", + // label: "金蝶同步状态", + // prop: "successSync", + // width: "150" + // } +]; diff --git a/src/views/inventory/inventoryList/index.vue b/src/views/inventory/inventoryList/index.vue new file mode 100644 index 0000000..ede78a1 --- /dev/null +++ b/src/views/inventory/inventoryList/index.vue @@ -0,0 +1,86 @@ + + + + + + diff --git a/src/views/inventory/inventoryList/init/index.ts b/src/views/inventory/inventoryList/init/index.ts new file mode 100644 index 0000000..677844b --- /dev/null +++ b/src/views/inventory/inventoryList/init/index.ts @@ -0,0 +1,13 @@ +//全局状态 +import { useStatusStore } from "@/stores/modules/status"; +import { useUserStore } from "@/stores/modules/user"; +const statusStore = useStatusStore(); +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + resultType: statusStore.status.takeStockType, + stockCode: userStore.warehouse, + successSync: statusStore.status.syncStatus + }); +}; diff --git a/src/views/login/index.scss b/src/views/login/index.scss new file mode 100644 index 0000000..9d7bdb4 --- /dev/null +++ b/src/views/login/index.scss @@ -0,0 +1,83 @@ +.login-container { + height: 100%; + min-height: 550px; + background-color: #eeeeee; + background-image: url("@/assets/images/login_bg.svg"); + background-size: 100% 100%; + background-size: cover; + .login-box { + position: relative; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: space-around; + width: 96.5%; + height: 94%; + padding: 0 50px; + background-color: rgb(255 255 255 / 80%); + border-radius: 10px; + .dark { + position: absolute; + top: 13px; + right: 18px; + } + .login-left { + width: 800px; + margin-right: 10px; + .login-left-img { + width: 100%; + height: 100%; + } + } + .login-form { + width: 420px; + padding: 50px 40px 45px; + background-color: var(--el-bg-color); + border-radius: 10px; + box-shadow: rgb(0 0 0 / 10%) 0 2px 10px 2px; + .login-logo { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 45px; + .login-icon { + width: 60px; + height: 52px; + } + .logo-text { + padding: 0 0 0 25px; + margin: 0; + font-size: 18px; + font-weight: bold; + color: #34495e; + white-space: nowrap; + } + } + .el-form-item { + margin-bottom: 40px; + } + .login-btn { + display: flex; + justify-content: space-between; + width: 100%; + margin-top: 40px; + white-space: nowrap; + .el-button { + width: 185px; + } + } + } + } +} + +@media screen and (width <= 1250px) { + .login-left { + display: none; + } +} + +@media screen and (width <= 600px) { + .login-form { + width: 97% !important; + } +} diff --git a/src/views/login/index.vue b/src/views/login/index.vue new file mode 100644 index 0000000..b0637ae --- /dev/null +++ b/src/views/login/index.vue @@ -0,0 +1,120 @@ + + + diff --git a/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/details/columns.ts b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/details/columns.ts new file mode 100644 index 0000000..b4e317d --- /dev/null +++ b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/details/columns.ts @@ -0,0 +1,67 @@ +//明细信息 +export const COLUMNS = [ + { + label: "箱号", + prop: "boxBillNo", + disabled: false, + width: "120px" + }, + { + label: "规格型号", + prop: "specifications", + width: "400px", + + disabled: false + }, + { + label: "箱数量", + prop: "qty", + width: "80px", + disabled: false + }, + { + label: "序列号", + prop: "serialNumbers", + disabled: false, + width: "400px" + }, + { + label: "收货数量", + prop: "receiveQty", + disabled: false, + width: "100px" + }, + { + label: "实入库数量", + prop: "realityQty", + disabled: false, + width: "100px" + }, + { + label: "收货人", + prop: "receiver", + disabled: false + }, + { + label: "收货时间", + prop: "receiveTime", + disabled: false, + width: "160px" + }, + { + label: "上架人", + prop: "shelfer", + disabled: false + }, + { + label: "上架类型", + prop: "method", + disabled: false + }, + { + label: "入库时间", + prop: "shelfTime", + disabled: false, + width: "160px" + } +]; diff --git a/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/details/index.ts b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/details/index.ts new file mode 100644 index 0000000..45de8ed --- /dev/null +++ b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/details/index.ts @@ -0,0 +1,3 @@ +import { COLUMNS } from "./columns"; +import { RULEFORM, FORMDATA } from "./search"; +export { RULEFORM, FORMDATA, COLUMNS }; diff --git a/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/details/search.ts b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/details/search.ts new file mode 100644 index 0000000..9d60cca --- /dev/null +++ b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/details/search.ts @@ -0,0 +1,71 @@ +export const FORMDATA: any[] = [ + { + prop: "billNo", + placeholder: "请输入库任务单号", + type: "input", + label: "入库任务单号:", + disabled: true + }, + { + prop: "saleBillNo", + placeholder: "请输入销售订单号", + type: "input", + label: "销售订单号:", + disabled: true + }, + { + prop: "sourceBillNo", + placeholder: "请输入来源单号", + type: "input", + disabled: true, + label: "来源单号:" + }, + { + prop: "status", + placeholder: "请输入入库状态", + type: "input", + disabled: true, + label: "入库状态:" + }, + { + prop: "supplier", + placeholder: "请输入供应商", + type: "input", + disabled: true, + label: "供应商:" + }, + { + prop: "type", + placeholder: "请输入入库类型", + type: "input", + disabled: true, + label: "入库类型:" + }, + { + prop: "createTime", + placeholder: "请输入创建时间", + type: "input", + disabled: true, + label: "创建时间:" + }, + { + prop: "org", + placeholder: "请输入组织", + type: "input", + disabled: true, + label: "组织:" + } +]; + +export const RULEFORM: any = { + org: "", + billNo: "", + sourceBillNo: "", + saleBillNo: "", + supplier: "", + status: "", + type: "", + createTime: "", + id: 0, + boxs: [] +}; diff --git a/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/list/index.ts b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/list/search.ts b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/list/search.ts new file mode 100644 index 0000000..fd3c663 --- /dev/null +++ b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/list/search.ts @@ -0,0 +1,102 @@ +export const FORMDATA: any[] = [ + { + prop: "sourceBillNo", + placeholder: "请输入来源单号", + type: "input", + label: "来源单号:" + }, + { + prop: "type", + placeholder: "请选择入库类型", + type: "select", + options: [], + label: "入库类型:" + }, + { + prop: "stockCode", + placeholder: "请选择状态", + type: "select", + options: [], + label: "仓库:" + }, + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "入库日期:" + }, + { + prop: "supplierId", + placeholder: "请输入供应商", + type: "selectRemote", + label: "供应商:", + options: [] + }, + { + prop: "materialNumber", + placeholder: "请输入物料名称/规格型号/编码", + type: "input", + label: "物料:" + }, + { + prop: "status", + placeholder: "请选择入库状态", + type: "select", + options: [], + label: "入库状态:" + }, + { + prop: "orgId", + placeholder: "请输入组织", + type: "selectRemote", + label: "组织:", + options: [] + }, + { + prop: "receiver", + placeholder: "请输入收货人", + type: "input", + label: "收货人:" + }, + { + prop: "operator", + placeholder: "请输入上架人", + type: "input", + label: "上架人:" + }, + { + prop: "boxBillNos", + placeholder: "请输入箱号", + type: "input", + disabled: false, + label: "箱号:" + }, + { + prop: "serialNumbers", + placeholder: "请输入序列号", + type: "input", + disabled: false, + label: "序列号:" + } +]; + +export const RULEFORM: any = { + time: "", + pageNo: 1, //页码 + pageSize: 20, //每页显示条目个数 + sourceBillNo: "", //来源单号 + type: "", //入库类型 + status: "", //入库状态 + receiver: "", //收货人 + operator: "", //上架人 + createBeginDate: "", //创建时间 + createEndDate: "", //结束时间 + supplierId: "", //供应商 + orgId: null, //组织 + materialNumber: "", //物料编码 + stockCode: "", //仓库 + serialNumbers: "", + boxBillNos: "" +}; diff --git a/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/list/table.ts b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/list/table.ts new file mode 100644 index 0000000..f27134d --- /dev/null +++ b/src/views/receiptAndWarehousing/ofInboundInstructionsList/constant/list/table.ts @@ -0,0 +1,143 @@ +// import { STATUS } from "@/constant"; +import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + fixed: true, + label: "入库任务单号", + prop: "billNo", + width: "200" + }, + { + align: "left", + label: "入库状态", + prop: "status", + width: "120" + }, + { + align: "left", + label: "来源单号", + prop: "sourceBillNo", + width: "200" + }, + { + align: "left", + label: "销售订单号", + prop: "saleBillNo", + width: "200" + }, + { + align: "left", + label: "入库类型", + prop: "type", + width: "120" + }, + { + align: "left", + label: "供应商", + prop: "supplier", + width: "160" + }, + { + align: "left", + label: "组织", + prop: "org", + width: "160" + }, + { + align: "left", + label: "规格型号", + prop: "specifications", + width: "160" + }, + { + align: "left", + label: "物料编码", + prop: "materialNumber", + width: "160" + }, + { + align: "left", + label: "物料名称", + prop: "materialName", + width: "120" + }, + { + align: "left", + label: "出厂价", + prop: "factoryPrice", + width: "120" + }, + { + align: "left", + label: "收货仓库", + prop: "stock", + width: "160" + }, + { + align: "left", + label: "应入库数量", + prop: "accruedQty", + width: "120" + }, + { + align: "left", + label: "收货数量", + prop: "receiveQty", + width: "120" + }, + { + align: "left", + label: "实入库数量", + prop: "realityQty", + width: "120" + }, + { + align: "left", + label: "收货人", + prop: "receiver", + width: "120" + }, + { + align: "left", + label: "收货时间", + prop: "receiveTime", + width: "160" + }, + { + align: "left", + label: "上架人", + prop: "shelfer", + width: "120" + }, + { + align: "left", + label: "入库时间", + prop: "shelfTime", + width: "160" + }, + { + align: "left", + label: "订单明细备注", + prop: "remark", + width: "200" + }, + { + align: "left", + label: "是否作废", + prop: "isRepeal", + width: "120", + render: (scope: RenderScope): VNode | string | any => { + return scope.row.isRepeal ? "是" : "否"; + } + }, + { + align: "left", + label: "创建时间", + prop: "createTime", + width: "160" + } +]; diff --git a/src/views/receiptAndWarehousing/ofInboundInstructionsList/details.vue b/src/views/receiptAndWarehousing/ofInboundInstructionsList/details.vue new file mode 100644 index 0000000..3d852d6 --- /dev/null +++ b/src/views/receiptAndWarehousing/ofInboundInstructionsList/details.vue @@ -0,0 +1,98 @@ + + + + diff --git a/src/views/receiptAndWarehousing/ofInboundInstructionsList/index.vue b/src/views/receiptAndWarehousing/ofInboundInstructionsList/index.vue new file mode 100644 index 0000000..b1076c0 --- /dev/null +++ b/src/views/receiptAndWarehousing/ofInboundInstructionsList/index.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/src/views/receiptAndWarehousing/ofInboundInstructionsList/init/index.ts b/src/views/receiptAndWarehousing/ofInboundInstructionsList/init/index.ts new file mode 100644 index 0000000..9f2af20 --- /dev/null +++ b/src/views/receiptAndWarehousing/ofInboundInstructionsList/init/index.ts @@ -0,0 +1,13 @@ +//全局状态 +import { useStatusStore } from "@/stores/modules/status"; +import { useUserStore } from "@/stores/modules/user"; +const statusStore = useStatusStore(); +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + type: statusStore.status.instockType, + status: statusStore.status.instockStatus, + stockCode: userStore.warehouse + }); +}; diff --git a/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/details.ts b/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/details.ts new file mode 100644 index 0000000..7b16ad3 --- /dev/null +++ b/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/details.ts @@ -0,0 +1,33 @@ +export const FORMDATA: any[] = [ + { + prop: "creator", + label: "创建人", + type: "input", + disabled: true + }, + { + prop: "createTime", + label: "创建时间", + type: "input", + disabled: true + }, + { + prop: "operate", + label: "最后修改人", + type: "input", + disabled: true + }, + + { + prop: "syncTime", + label: "重传时间", + type: "input", + disabled: true + } +]; +export const RULEFORM: Record = { + syncTime: "", + operate: "", + createTime: "", + creator: "" +}; diff --git a/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/index.ts b/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/search.ts b/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/search.ts new file mode 100644 index 0000000..1002720 --- /dev/null +++ b/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/search.ts @@ -0,0 +1,79 @@ +export const FORMDATA: any[] = [ + { + prop: "sourceBillNo", + placeholder: "请输入来源单号", + type: "input", + label: "来源单号:" + }, + { + prop: "type", + placeholder: "请选择入库类型", + type: "select", + options: [], + label: "入库类型:" + }, + { + prop: "stockCode", + placeholder: "请选择仓库", + type: "select", + options: [], + label: "仓库:" + }, + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "入库日期:" + }, + { + prop: "supplierId", + placeholder: "请输入供应商", + type: "selectRemote", + label: "供应商:", + options: [] + }, + { + prop: "materialNumber", + placeholder: "请输入物料名称/规格型号/编码", + type: "input", + label: "物料:" + }, + { + prop: "orgId", + placeholder: "请输入组织", + type: "selectRemote", + label: "组织:", + options: [] + }, + { + prop: "successSync", + placeholder: "请选择同步状态", + type: "select", + options: [], + label: "同步状态:" + }, + { + prop: "creator", + placeholder: "请输入创建人", + type: "input", + label: "创建人:" + } +]; + +export const RULEFORM: any = { + time: "", + pageNo: 1, + pageSize: 20, + sourceBillNo: "", + type: "", + creator: "", + createBeginDate: "", + createEndDate: "", + successSync: "", + supplierId: "", + orgId: null, + materialNumber: "", + stockCode: "" +}; diff --git a/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/table.ts b/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/table.ts new file mode 100644 index 0000000..d711b84 --- /dev/null +++ b/src/views/receiptAndWarehousing/warehouseReceiptList/constant/list/table.ts @@ -0,0 +1,87 @@ +// import { STATUS } from "@/constant"; +// import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + fixed: true, + label: "入库单号", + prop: "billNo", + width: "200", + isCode: true + }, + { + align: "left", + label: "来源单号", + prop: "sourceBillNo", + width: "200" + }, + { + align: "left", + label: "入库类型", + prop: "type", + width: "120" + }, + { + align: "left", + label: "供应商", + prop: "supplier", + width: "160" + }, + { + align: "left", + label: "组织", + prop: "org", + width: "160" + }, + { + align: "left", + label: "规格型号", + prop: "specifications", + width: "160" + }, + { + align: "left", + label: "物料编码", + prop: "materialNumber", + width: "160" + }, + { + align: "left", + label: "物料名称", + prop: "materialName", + width: "120" + }, + { + align: "left", + label: "仓库", + prop: "stock", + width: "160" + }, + { + align: "left", + label: "入库数量", + prop: "qty", + width: "120" + }, + { + align: "left", + label: "创建人", + prop: "creator", + width: "120" + }, + { + align: "left", + label: "入库时间", + prop: "createTime", + width: "160" + }, + { + align: "left", + label: "金蝶同步状态", + prop: "successSync", + width: "120" + } +]; diff --git a/src/views/receiptAndWarehousing/warehouseReceiptList/details.vue b/src/views/receiptAndWarehousing/warehouseReceiptList/details.vue new file mode 100644 index 0000000..e49e404 --- /dev/null +++ b/src/views/receiptAndWarehousing/warehouseReceiptList/details.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/src/views/receiptAndWarehousing/warehouseReceiptList/index.vue b/src/views/receiptAndWarehousing/warehouseReceiptList/index.vue new file mode 100644 index 0000000..5b25475 --- /dev/null +++ b/src/views/receiptAndWarehousing/warehouseReceiptList/index.vue @@ -0,0 +1,136 @@ + + + + + + diff --git a/src/views/receiptAndWarehousing/warehouseReceiptList/init/index.ts b/src/views/receiptAndWarehousing/warehouseReceiptList/init/index.ts new file mode 100644 index 0000000..d33ee13 --- /dev/null +++ b/src/views/receiptAndWarehousing/warehouseReceiptList/init/index.ts @@ -0,0 +1,14 @@ +//全局状态 +import { useStatusStore } from "@/stores/modules/status"; +import { useUserStore } from "@/stores/modules/user"; +const statusStore = useStatusStore(); +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + type: statusStore.status.instockType, + status: statusStore.status.instockStatus, + stockCode: userStore.warehouse, + successSync: statusStore.status.syncStatus + }); +}; diff --git a/src/views/reportForm/boxStorage/constant/list/index.ts b/src/views/reportForm/boxStorage/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/reportForm/boxStorage/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/reportForm/boxStorage/constant/list/search.ts b/src/views/reportForm/boxStorage/constant/list/search.ts new file mode 100644 index 0000000..5671eb7 --- /dev/null +++ b/src/views/reportForm/boxStorage/constant/list/search.ts @@ -0,0 +1,38 @@ +export const FORMDATA: any[] = [ + { + prop: "stockCode", + placeholder: "请选择仓库", + type: "select", + options: [], + label: "仓库:" + }, + + { + prop: "subStockCode", + placeholder: "请输入仓位", + type: "selectRemote", + label: "仓位:", + options: [] + }, + { + prop: "boxBillNo", + placeholder: "请输入箱号", + type: "input", + label: "箱号:" + }, + { + prop: "materialNumber", + placeholder: "请输入物料名称/规格型号/编码", + type: "input", + label: "物料:" + } +]; + +export const RULEFORM: any = { + materialNumber: "", + boxBillNo: "", + subStockCode: "", + pageNo: 1, + pageSize: 50, + stockCode: "" +}; diff --git a/src/views/reportForm/boxStorage/constant/list/table.ts b/src/views/reportForm/boxStorage/constant/list/table.ts new file mode 100644 index 0000000..1b1a528 --- /dev/null +++ b/src/views/reportForm/boxStorage/constant/list/table.ts @@ -0,0 +1,55 @@ +// import { STATUS } from "@/constant"; +// import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + fixed: true, + label: "箱号", + prop: "boxBillNo" + }, + { + align: "left", + label: "仓库", + prop: "stock" + }, + { + align: "left", + label: "仓位", + prop: "subStock" + }, + { + align: "left", + label: "物料编码", + prop: "materialNumber" + }, + { + align: "left", + label: "序列号", + prop: "serialNumbers" + }, + { + align: "left", + label: "规格型号", + prop: "specifications" + }, + { + align: "left", + label: "物料名称", + prop: "materialName" + }, + { + align: "left", + label: "数量", + prop: "qty", + width: "120" + }, + + { + align: "left", + label: "组织", + prop: "org" + } +]; diff --git a/src/views/reportForm/boxStorage/index.vue b/src/views/reportForm/boxStorage/index.vue new file mode 100644 index 0000000..b4d1c6f --- /dev/null +++ b/src/views/reportForm/boxStorage/index.vue @@ -0,0 +1,86 @@ + + + + + + diff --git a/src/views/reportForm/boxStorage/init/index.ts b/src/views/reportForm/boxStorage/init/index.ts new file mode 100644 index 0000000..41aa783 --- /dev/null +++ b/src/views/reportForm/boxStorage/init/index.ts @@ -0,0 +1,8 @@ +import { useUserStore } from "@/stores/modules/user"; +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + stockCode: userStore.warehouse + }); +}; diff --git a/src/views/reportForm/immediately/constant/list/index.ts b/src/views/reportForm/immediately/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/reportForm/immediately/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/reportForm/immediately/constant/list/search.ts b/src/views/reportForm/immediately/constant/list/search.ts new file mode 100644 index 0000000..26aa25e --- /dev/null +++ b/src/views/reportForm/immediately/constant/list/search.ts @@ -0,0 +1,38 @@ +export const FORMDATA: any[] = [ + { + prop: "stockCode", + placeholder: "请选择仓库", + type: "select", + options: [], + label: "仓库:" + }, + { + prop: "subStockCode", + placeholder: "请输入仓位", + type: "selectRemote", + label: "仓位:", + options: [] + }, + { + prop: "materialNumber", + placeholder: "请输入物料名称/规格型号/编码", + type: "input", + label: "物料:" + }, + { + prop: "qty", + placeholder: "请输入库存量", + type: "input", + label: "库存量:", + maxLength: 18 + } +]; + +export const RULEFORM: any = { + qty: "", + materialNumber: "", + stockCode: "", + subStockCode: "", + pageNo: 1, + pageSize: 20 +}; diff --git a/src/views/reportForm/immediately/constant/list/table.ts b/src/views/reportForm/immediately/constant/list/table.ts new file mode 100644 index 0000000..2914f5e --- /dev/null +++ b/src/views/reportForm/immediately/constant/list/table.ts @@ -0,0 +1,49 @@ +// import { STATUS } from "@/constant"; +// import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + fixed: true, + label: "物料编码", + prop: "materialNumber" + }, + { + align: "left", + label: "规格型号", + prop: "specifications" + }, + { + align: "left", + label: "物料名称", + prop: "materialName" + }, + { + align: "left", + label: "仓库", + prop: "stock" + }, + { + align: "left", + label: "组织", + prop: "org" + }, + { + align: "left", + label: "仓位", + prop: "subStock" + }, + { + align: "left", + label: "库存量", + prop: "qty" + }, + { + align: "left", + label: "单位", + prop: "unit", + width: "120" + } +]; diff --git a/src/views/reportForm/immediately/index.vue b/src/views/reportForm/immediately/index.vue new file mode 100644 index 0000000..7e4fb12 --- /dev/null +++ b/src/views/reportForm/immediately/index.vue @@ -0,0 +1,86 @@ + + + + + + diff --git a/src/views/reportForm/immediately/init/index.ts b/src/views/reportForm/immediately/init/index.ts new file mode 100644 index 0000000..41aa783 --- /dev/null +++ b/src/views/reportForm/immediately/init/index.ts @@ -0,0 +1,8 @@ +import { useUserStore } from "@/stores/modules/user"; +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + stockCode: userStore.warehouse + }); +}; diff --git a/src/views/reportForm/material/constant/list/index.ts b/src/views/reportForm/material/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/reportForm/material/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/reportForm/material/constant/list/search.ts b/src/views/reportForm/material/constant/list/search.ts new file mode 100644 index 0000000..0815b5b --- /dev/null +++ b/src/views/reportForm/material/constant/list/search.ts @@ -0,0 +1,40 @@ +export const FORMDATA: any[] = [ + { + prop: "stockCode", + placeholder: "请选择仓库", + type: "select", + options: [], + label: "仓库:" + }, + { + prop: "orderType", + placeholder: "请选择单据类型", + type: "select", + options: [], + label: "单据类型:" + }, + { + prop: "materialNumber", + placeholder: "请输入物料名称/规格型号/编码", + type: "input", + label: "物料:" + }, + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "日期:" + } +]; + +export const RULEFORM: any = { + createEndDate: "", + createBeginDate: "", + orderType: "", + materialNumber: "", + stockCode: "", + pageSize: 20, + pageNo: 1 +}; diff --git a/src/views/reportForm/material/constant/list/table.ts b/src/views/reportForm/material/constant/list/table.ts new file mode 100644 index 0000000..957c4c1 --- /dev/null +++ b/src/views/reportForm/material/constant/list/table.ts @@ -0,0 +1,66 @@ +// import { STATUS } from "@/constant"; +// import { RenderScope } from "@/components/ProTable/interface"; + +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + fixed: true, + label: "物料编码", + prop: "materialNumber" + }, + { + align: "left", + label: "规格型号", + prop: "specifications" + }, + { + align: "left", + label: "物料名称", + prop: "materialName" + }, + { + align: "left", + label: "单号", + prop: "orderBillNo" + }, + { + align: "left", + label: "单据类型", + prop: "orderType" + }, + { + align: "left", + label: "组织", + prop: "org" + }, + { + align: "left", + label: "日期", + prop: "createTime" + }, + { + align: "left", + label: "出入库类型", + prop: "type" + }, + { + align: "left", + label: "数量", + prop: "qty", + width: "120" + }, + { + align: "left", + label: "结存", + prop: "surplusQty", + width: "120" + }, + { + align: "left", + label: "仓库", + prop: "stock", + width: "160" + } +]; diff --git a/src/views/reportForm/material/index.vue b/src/views/reportForm/material/index.vue new file mode 100644 index 0000000..ea91bdf --- /dev/null +++ b/src/views/reportForm/material/index.vue @@ -0,0 +1,65 @@ + + + + + + diff --git a/src/views/reportForm/material/init/index.ts b/src/views/reportForm/material/init/index.ts new file mode 100644 index 0000000..5d3f446 --- /dev/null +++ b/src/views/reportForm/material/init/index.ts @@ -0,0 +1,11 @@ +import { useStatusStore } from "@/stores/modules/status"; +import { useUserStore } from "@/stores/modules/user"; +const statusStore = useStatusStore(); +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + stockCode: userStore.warehouse, + orderType: statusStore.status.orderType + }); +}; diff --git a/src/views/setUp/boxMark/constant/details/search.ts b/src/views/setUp/boxMark/constant/details/search.ts new file mode 100644 index 0000000..f68d63c --- /dev/null +++ b/src/views/setUp/boxMark/constant/details/search.ts @@ -0,0 +1,109 @@ +export const FORMDATA: any[] = [ + { + prop: "orderBillNo", + placeholder: "请输入订单号", + type: "input", + label: "订单号:", + disabled: false, + required: true, + maxLength: 30 + }, + { + prop: "materialNumber", + placeholder: "规格型号", + type: "selectRemote", + label: "规格型号:", + disabled: false, + required: true, + options: [] + }, + { + prop: "productQty", + placeholder: "请输入产品数量", + type: "input", + label: "产品数量:", + disabled: false, + required: true, + maxLength: 10, + reg: "integerRexg" + } +]; +export const FORMDATA1: any[] = [ + { + prop: "cratingQty", + placeholder: "请输入装箱数量", + type: "input", + label: "装箱数量:", + disabled: false, + maxLength: 10, + required: true, + reg: "integerRexg" + }, + { + prop: "cratingNetWeightQty", + type: "input", + label: "净重:", + disabled: false, + isTxt: true, + maxLength: 5, + reg: "numberDecimalSeparatorRexg" + }, + { + prop: "cratingGrossWeightQty", + placeholder: "请输入毛重", + type: "input", + label: "毛重:", + disabled: false, + isTxt: true, + maxLength: 5, + reg: "numberDecimalSeparatorRexg" + } +]; +export const FORMDATA2: any[] = [ + { + prop: "tailboxQty", + placeholder: "", + type: "input", + label: "尾箱数量:", + disabled: true + }, + { + prop: "tailboxNetWeightQty", + placeholder: "", + type: "input", + label: "净重:", + disabled: true, + isTxt: true + }, + { + prop: "tailboxGrossWeightQty", + placeholder: "", + type: "input", + label: "毛重:", + disabled: true, + isTxt: true + } +]; +export const FORMDATA3: any[] = [ + { + prop: "remark", + placeholder: "请输入备注", + type: "textarea", + label: "备注:", + disabled: false, + class: "form-item1" + } +]; +export const RULEFORM: any = { + billNo: null, + orderBillNo: null, + materialNumber: null, + productQty: 0, + cratingQty: 0, + cratingNetWeightQty: 0, + cratingGrossWeightQty: 0, + tailboxQty: 0, + tailboxNetWeightQty: 0, + tailboxGrossWeightQty: 0, + remark: null +}; diff --git a/src/views/setUp/boxMark/constant/list/index.ts b/src/views/setUp/boxMark/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/setUp/boxMark/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/setUp/boxMark/constant/list/search.ts b/src/views/setUp/boxMark/constant/list/search.ts new file mode 100644 index 0000000..1b4ebc7 --- /dev/null +++ b/src/views/setUp/boxMark/constant/list/search.ts @@ -0,0 +1,56 @@ +export const FORMDATA: any[] = [ + { + prop: "orderBillNos", + placeholder: "请输入订单号", + type: "input", + label: "订单号:" + }, + { + prop: "material", + placeholder: "请输入物料名称/规格型号/编码", + type: "input", + label: "物料:" + }, + { + prop: "beginBillNo", + placeholder: "请输入箱唛", + type: "input", + label: "箱唛:" + }, + { + prop: "endBillNo", + placeholder: "请输入箱唛", + type: "input", + label: "一", + labelWidth: 32, + style: "width:200px;", + formItemStyle: "width:232px;" + }, + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "生成时间:" + }, + + { + prop: "creator", + placeholder: "请输入操作人", + type: "input", + label: "操作人:" + } +]; + +export const RULEFORM: any = { + orderBillNos: "", + material: "", + beginBillNo: "", + endBillNo: "", + creator: "", + beginDate: "", + endDate: "" + // beginTime: "", + // endTime: "" +}; diff --git a/src/views/setUp/boxMark/constant/list/table.ts b/src/views/setUp/boxMark/constant/list/table.ts new file mode 100644 index 0000000..c1a2891 --- /dev/null +++ b/src/views/setUp/boxMark/constant/list/table.ts @@ -0,0 +1,111 @@ +import { RenderScope } from "@/components/ProTable/interface"; +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", fixed: "left", width: 40 }, + { + align: "left", + fixed: true, + label: "订单号", + prop: "orderBillNo", + width: "200" + }, + { + align: "left", + fixed: true, + label: "箱唛", + prop: "billNo", + width: "160" + }, + { + align: "left", + fixed: true, + label: "装箱序号", + prop: "boxSortCount", + width: "80", + render: (scope: RenderScope): VNode | string | any => { + if (scope.row.isTail) { + return scope.row.boxSortCount + "/" + scope.row.boxSortCount; + } else { + return scope.row.sort + "/" + scope.row.boxSortCount; + } + } + }, + + { + align: "left", + label: "规格型号", + prop: "specifications", + width: "220" + }, + { + align: "left", + label: "物料编码", + prop: "materialNumber", + width: "160" + }, + { + align: "left", + label: "物料名称", + prop: "materialName", + width: "160" + }, + { + align: "left", + label: "内装数量(PSC)", //productQty + prop: "Qty", + width: "120", + render: (scope: RenderScope): VNode | string | any => { + //当总数小于等于1时,显示产品数量 + if (scope.row.boxSortCount <= 1) { + return scope.row.productQty; + } + //是否尾数 + if (scope.row.isTail) { + return scope.row.tailboxQty; + } else { + return scope.row.cratingQty; + } + } + }, + { + align: "left", + label: "可装箱数量(PSC)", + prop: "cratingQty", + width: "120" + }, + { + align: "left", + label: "净重(KG)", + prop: "weightQty", + width: "120", + render: (scope: RenderScope): VNode | string => + scope.row.isTail ? scope.row.tailboxNetWeightQty : scope.row.cratingNetWeightQty + }, + { + align: "left", + label: "毛重(KG)", + prop: "grossQty", + width: "120", + render: (scope: RenderScope): VNode | string => + scope.row.isTail ? scope.row.tailboxGrossWeightQty : scope.row.cratingGrossWeightQty + }, + { + align: "left", + label: "备注", + prop: "remark", + width: "200", + render: (scope: RenderScope): VNode | string => (scope.row.remark ? scope.row.remark : "--") + }, + { + align: "left", + label: "操作人", + prop: "creator", + width: "200" + }, + { + align: "left", + label: "生成时间", + prop: "createTime", + width: "200" + } +]; diff --git a/src/views/setUp/boxMark/details.vue b/src/views/setUp/boxMark/details.vue new file mode 100644 index 0000000..aba02a5 --- /dev/null +++ b/src/views/setUp/boxMark/details.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/src/views/setUp/boxMark/index.vue b/src/views/setUp/boxMark/index.vue new file mode 100644 index 0000000..bc13e26 --- /dev/null +++ b/src/views/setUp/boxMark/index.vue @@ -0,0 +1,109 @@ + + + + + + + diff --git a/src/views/setUp/boxMark/init/details.ts b/src/views/setUp/boxMark/init/details.ts new file mode 100644 index 0000000..b5539a2 --- /dev/null +++ b/src/views/setUp/boxMark/init/details.ts @@ -0,0 +1,30 @@ +export const handleAddDisNo = (datas: any) => { + datas.formData.forEach((item: any) => { + item.disabled = false; + }); + datas.formData1.forEach((item: any) => { + item.disabled = false; + }); + + datas.formData3.forEach((item: any) => { + item.disabled = false; + }); +}; +export const handleGenerateDisYes = (datas: any) => { + datas.formData.forEach((item: any) => { + item.disabled = true; + }); + datas.formData1.forEach((item: any) => { + item.disabled = true; + }); + + datas.formData3.forEach((item: any) => { + item.disabled = true; + }); +}; + +export const initFormData = (datas: any) => { + for (let key in datas.ruleForm) { + datas.ruleForm[key] = ""; + } +}; diff --git a/src/views/setUp/boxMark/init/index.ts b/src/views/setUp/boxMark/init/index.ts new file mode 100644 index 0000000..677844b --- /dev/null +++ b/src/views/setUp/boxMark/init/index.ts @@ -0,0 +1,13 @@ +//全局状态 +import { useStatusStore } from "@/stores/modules/status"; +import { useUserStore } from "@/stores/modules/user"; +const statusStore = useStatusStore(); +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + resultType: statusStore.status.takeStockType, + stockCode: userStore.warehouse, + successSync: statusStore.status.syncStatus + }); +}; diff --git a/src/views/setUp/subscription/constant/details/search.ts b/src/views/setUp/subscription/constant/details/search.ts new file mode 100644 index 0000000..1d17d0c --- /dev/null +++ b/src/views/setUp/subscription/constant/details/search.ts @@ -0,0 +1,58 @@ +export const FORMDATA: any[] = [ + { + prop: "customerName", + placeholder: "请输入客户名称", + type: "selectRemote1", + options: [], + required: true, + label: "客户名称:" + } +]; +export const FORMDATA1: any[] = [ + { + prop: "customerNumber", + placeholder: "请输入客户编码", + type: "input", + label: "客户编码:", + disabled: true, + required: true, + maxLength: 35 + } +]; +export const FORMDATA2: any[] = [ + { + prop: "telephones", + placeholder: "请输入手机号码(添加订阅邮箱通知的手机号码,不同手机号码之间逗号区隔)", + type: "textarea", + label: "订阅手机号码:", + disabled: false, + class: "form-item1", + required: true, + maxLength: 5000, + autosize: { + minRows: 8 + } + } +]; +export const FORMDATA3: any[] = [ + { + prop: "emails", + placeholder: "请输入邮箱地址(添加订阅邮箱通知的邮箱地址,不同邮箱地址之间逗号区隔)", + type: "textarea", + label: "订阅邮箱地址:", + disabled: false, + class: "form-item1", + maxLength: 5000, + autosize: { + minRows: 8 + } + } +]; + +export const RULEFORM: any = { + emails: "", + telephones: "", + customerNumber: "", + customerName: "", + id: 0 +}; diff --git a/src/views/setUp/subscription/constant/list/index.ts b/src/views/setUp/subscription/constant/list/index.ts new file mode 100644 index 0000000..a3710df --- /dev/null +++ b/src/views/setUp/subscription/constant/list/index.ts @@ -0,0 +1,3 @@ +import { FORMDATA, RULEFORM } from "./search"; +import { COLUMNS } from "./table"; +export { FORMDATA, RULEFORM, COLUMNS }; diff --git a/src/views/setUp/subscription/constant/list/search.ts b/src/views/setUp/subscription/constant/list/search.ts new file mode 100644 index 0000000..a0f09fe --- /dev/null +++ b/src/views/setUp/subscription/constant/list/search.ts @@ -0,0 +1,39 @@ +export const FORMDATA: any[] = [ + { + prop: "customerName", + placeholder: "请输入客户名称", + type: "input", + label: "客户名称:" + }, + + { + prop: "customerNumber", + placeholder: "请输入客户编码", + type: "input", + label: "客户编码:" + }, + + { + prop: "time", + type: "daterange", + options: [], + startPlaceholder: "开始日期", + endPlaceholder: "结束日期", + label: "生成时间:" + }, + + { + prop: "creator", + placeholder: "请输入创建人", + type: "input", + label: "创建人:" + } +]; + +export const RULEFORM: any = { + creator: "", + createBeginDate: "", + createEndDate: "", + customerName: "", + customerNumber: "" +}; diff --git a/src/views/setUp/subscription/constant/list/table.ts b/src/views/setUp/subscription/constant/list/table.ts new file mode 100644 index 0000000..9b28a62 --- /dev/null +++ b/src/views/setUp/subscription/constant/list/table.ts @@ -0,0 +1,44 @@ +//import { RenderScope } from "@/components/ProTable/interface"; +// 销售订单 表格配置项 +export const COLUMNS = [ + { type: "selection", width: 40 }, + { + align: "left", + label: "客户名称", + prop: "customerName" + // width: "200" + }, + { + align: "left", + label: "客户编码", + prop: "customerNumber" + // width: "160" + }, + + { + align: "left", + label: "手机号码", + prop: "telephones" + // width: "160" + }, + + { + align: "left", + label: "邮箱", + prop: "emails" + // width: "120" + }, + + { + align: "left", + label: "创建人", + prop: "creator" + // width: "200" + }, + { + align: "left", + label: "更新时间", + prop: "operateTime" + // width: "200" + } +]; diff --git a/src/views/setUp/subscription/details.vue b/src/views/setUp/subscription/details.vue new file mode 100644 index 0000000..9ca1834 --- /dev/null +++ b/src/views/setUp/subscription/details.vue @@ -0,0 +1,143 @@ + + + + + diff --git a/src/views/setUp/subscription/index.vue b/src/views/setUp/subscription/index.vue new file mode 100644 index 0000000..93f5179 --- /dev/null +++ b/src/views/setUp/subscription/index.vue @@ -0,0 +1,117 @@ + + + + + + diff --git a/src/views/setUp/subscription/init/details.ts b/src/views/setUp/subscription/init/details.ts new file mode 100644 index 0000000..4b267ac --- /dev/null +++ b/src/views/setUp/subscription/init/details.ts @@ -0,0 +1,35 @@ +export const handleAddDisNo = (datas: any) => { + datas.formData.forEach((item: any) => { + item.disabled = false; + }); + //客户编码永远禁止 + // datas.formData1.forEach((item: any) => { + // item.disabled = true; + // }); + datas.formData2.forEach((item: any) => { + item.disabled = false; + }); + datas.formData3.forEach((item: any) => { + item.disabled = false; + }); +}; +export const handleSubmitDisYes = (datas: any) => { + datas.formData.forEach((item: any) => { + item.disabled = true; + }); + datas.formData1.forEach((item: any) => { + item.disabled = true; + }); + datas.formData2.forEach((item: any) => { + item.disabled = true; + }); + datas.formData3.forEach((item: any) => { + item.disabled = true; + }); +}; + +export const initFormData = (datas: any) => { + for (let key in datas.ruleForm) { + datas.ruleForm[key] = ""; + } +}; diff --git a/src/views/setUp/subscription/init/index.ts b/src/views/setUp/subscription/init/index.ts new file mode 100644 index 0000000..677844b --- /dev/null +++ b/src/views/setUp/subscription/init/index.ts @@ -0,0 +1,13 @@ +//全局状态 +import { useStatusStore } from "@/stores/modules/status"; +import { useUserStore } from "@/stores/modules/user"; +const statusStore = useStatusStore(); +const userStore = useUserStore(); +import { useSetSearchData } from "@/hooks/useSearch"; +export const initSearch = (datas: any) => { + datas.formData = useSetSearchData(datas.formData, { + resultType: statusStore.status.takeStockType, + stockCode: userStore.warehouse, + successSync: statusStore.status.syncStatus + }); +}; diff --git a/src/views/setUp/test/index.scss b/src/views/setUp/test/index.scss new file mode 100644 index 0000000..41b8494 --- /dev/null +++ b/src/views/setUp/test/index.scss @@ -0,0 +1,4 @@ +.box { + display: flex; + align-items: center; +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..cebe349 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,46 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "moduleResolution": "Node", + "types": ["vite/client", "element-plus/global"], + + /* Strict Type-Checking Options */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + "allowJs": true, //添加 编译时允许有js + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ESNext", "DOM"], + "skipLibCheck": true, + "noEmit": true, + "baseUrl": "./", + "paths": { + "@": ["src"], + "@/*": ["src/*"] + } + }, + "include": [ + "src/**/*.ts", + "src/**/*.d.ts", + "src/**/*.tsx", + "src/**/*.vue", + "src/**/**/*.vue", + "src/components/**/*.ts", + "build/**/*.ts", + "build/**/*.d.ts", + "vite.config.ts", + "src/hooks/constant/outsourc/order.ts", + "src/utils/print/productionOrOutSourcOthers.js" + ], + "exclude": ["node_modules", "dist", "**/*.js"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..3839cd9 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,78 @@ +import { defineConfig, loadEnv, ConfigEnv, UserConfig } from "vite"; +import { resolve } from "path"; +import { wrapperEnv } from "./build/getEnv"; +import { createProxy } from "./build/proxy"; +import { createVitePlugins } from "./build/plugins"; + +import pkg from "./package.json"; +import dayjs from "dayjs"; + +const { dependencies, devDependencies, name, version } = pkg; +const __APP_INFO__ = { + pkg: { dependencies, devDependencies, name, version }, + lastBuildTime: dayjs().format("YYYY-MM-DD HH:mm:ss") +}; + +// @see: https://vitejs.dev/config/ +export default defineConfig(({ mode }: ConfigEnv): UserConfig => { + const root = process.cwd(); + const env = loadEnv(mode, root); + const viteEnv = wrapperEnv(env); + + return { + base: viteEnv.VITE_PUBLIC_PATH, + root, + resolve: { + alias: { + "@": resolve(__dirname, "./src") + } + }, + define: { + __APP_INFO__: JSON.stringify(__APP_INFO__) + }, + css: { + preprocessorOptions: { + scss: { + additionalData: `@use "@/styles/var.scss" as *;` + } + } + }, + server: { + host: "0.0.0.0", + port: viteEnv.VITE_PORT, + open: viteEnv.VITE_OPEN, + cors: true, + // Load proxy configuration from .env.development + proxy: createProxy(viteEnv.VITE_PROXY) + }, + plugins: createVitePlugins(viteEnv), + esbuild: { + //"console.log", + pure: viteEnv.VITE_DROP_CONSOLE ? ["console.log", "debugger"] : [] + }, + build: { + outDir: "dist", + minify: "esbuild", + // esbuild 打包更快,但是不能去除 console.log,terser打包慢,但能去除 console.log + // minify: "terser", + // terserOptions: { + // compress: { + // drop_console: viteEnv.VITE_DROP_CONSOLE, + // drop_debugger: true + // } + // }, + // 禁用 gzip 压缩大小报告,可略微减少打包时间 + reportCompressedSize: false, + // 规定触发警告的 chunk 大小 + chunkSizeWarningLimit: 2000, + rollupOptions: { + output: { + // Static resource classification and packaging + chunkFileNames: "assets/js/[name]-[hash].js", + entryFileNames: "assets/js/[name]-[hash].js", + assetFileNames: "assets/[ext]/[name]-[hash].[ext]" + } + } + } + }; +}); diff --git a/vite.config.ts.timestamp-1697763975859-9fadd96b6a9b5.mjs b/vite.config.ts.timestamp-1697763975859-9fadd96b6a9b5.mjs new file mode 100644 index 0000000..dd43829 --- /dev/null +++ b/vite.config.ts.timestamp-1697763975859-9fadd96b6a9b5.mjs @@ -0,0 +1,360 @@ +// vite.config.ts +import { defineConfig, loadEnv } from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/vite/dist/node/index.js"; +import { resolve as resolve2 } from "path"; + +// build/getEnv.ts +function wrapperEnv(envConf) { + const ret = {}; + 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") { + try { + realName = JSON.parse(realName); + } catch (error) { + } + } + ret[envName] = realName; + } + return ret; +} + +// build/proxy.ts +function createProxy(list = []) { + const ret = {}; + for (const [prefix, target] of list) { + const httpsRE = /^https:\/\//; + const isHttps = httpsRE.test(target); + ret[prefix] = { + target, + changeOrigin: true, + ws: true, + rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ""), + // https is require secure=false + ...isHttps ? { secure: false } : {} + }; + } + return ret; +} + +// build/plugins.ts +import { resolve } from "path"; +import { VitePWA } from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/vite-plugin-pwa/dist/index.js"; +import { visualizer } from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/rollup-plugin-visualizer/dist/plugin/index.js"; +import { createHtmlPlugin } from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/vite-plugin-html/dist/index.mjs"; +import { createSvgIconsPlugin } from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/vite-plugin-svg-icons/dist/index.mjs"; +import vue from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/@vitejs/plugin-vue/dist/index.mjs"; +import vueJsx from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/@vitejs/plugin-vue-jsx/dist/index.mjs"; +import eslintPlugin from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/vite-plugin-eslint/dist/index.mjs"; +import viteCompression from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/vite-plugin-compression/dist/index.mjs"; +import vueSetupExtend from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/unplugin-vue-setup-extend-plus/dist/vite.js"; +import AutoImport from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/unplugin-auto-import/dist/vite.js"; +import Components from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/unplugin-vue-components/dist/vite.mjs"; +import { ElementPlusResolver } from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/unplugin-vue-components/dist/resolvers.mjs"; +import Icons from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/unplugin-icons/dist/vite.mjs"; +import IconsResolver from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/unplugin-icons/dist/resolver.mjs"; +var createVitePlugins = (viteEnv) => { + const { VITE_GLOB_APP_TITLE, VITE_REPORT, VITE_PWA } = viteEnv; + return [ + vue(), + // vue 可以使用 jsx/tsx 语法 + vueJsx(), + // esLint 报错信息显示在浏览器界面上 + eslintPlugin(), + // name 可以写在 script 标签上 + vueSetupExtend({}), + // 创建打包压缩配置 + createCompression(viteEnv), + // 注入变量到 html 文件 + createHtmlPlugin({ + inject: { + data: { title: VITE_GLOB_APP_TITLE } + } + }), + // 使用 svg 图标 + createSvgIconsPlugin({ + iconDirs: [resolve(process.cwd(), "src/assets/icons")], + symbolId: "icon-[dir]-[name]" + }), + // element按需导入 + AutoImport({ + // 安装两行后你会发现在组件中不用再导入ref,reactive等 + imports: ["vue", "vue-router"], + dts: "src/auto-import.d.ts", + // element + resolvers: [ + ElementPlusResolver({ importStyle: "sass" }), + IconsResolver({ + prefix: "Icon" + }) + ] + }), + Components({ + // element + resolvers: [ + ElementPlusResolver({ importStyle: "sass" }), + IconsResolver({ + enabledCollections: ["ep"] + }) + ], + // 默认存放位置 + dts: "src/components.d.ts" + }), + Icons({ + autoInstall: true + }), + // vitePWA + VITE_PWA && createVitePwa(viteEnv), + // 是否生成包预览,分析依赖包大小做优化处理 + VITE_REPORT && visualizer({ filename: "stats.html", gzipSize: true, brotliSize: true }) + ]; +}; +var createCompression = (viteEnv) => { + const { VITE_BUILD_COMPRESS = "none", VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE } = viteEnv; + const compressList = VITE_BUILD_COMPRESS.split(","); + const plugins = []; + if (compressList.includes("gzip")) { + plugins.push( + viteCompression({ + ext: ".gz", + algorithm: "gzip", + deleteOriginFile: VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE + }) + ); + } + if (compressList.includes("brotli")) { + plugins.push( + viteCompression({ + ext: ".br", + algorithm: "brotliCompress", + deleteOriginFile: VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE + }) + ); + } + return plugins; +}; +var createVitePwa = (viteEnv) => { + const { VITE_GLOB_APP_TITLE } = viteEnv; + return VitePWA({ + registerType: "autoUpdate", + manifest: { + name: VITE_GLOB_APP_TITLE, + short_name: VITE_GLOB_APP_TITLE, + theme_color: "#ffffff", + icons: [ + { + src: "/logo.png", + sizes: "192x192", + type: "image/png" + }, + { + src: "/logo.png", + sizes: "512x512", + type: "image/png" + }, + { + src: "/logo.png", + sizes: "512x512", + type: "image/png", + purpose: "any maskable" + } + ] + } + }); +}; + +// package.json +var package_default = { + name: "ops_admin_ts", + private: true, + version: "1.0.0", + type: "module", + scripts: { + dev: "vite", + serve: "vite", + "build:dev": "vue-tsc && vite build --mode development", + "build:test": "vue-tsc && vite build --mode test", + "build:pro": "vue-tsc && vite build --mode production", + "type:check": "vue-tsc --noEmit --skipLibCheck", + preview: "npm run build:dev && vite preview", + "lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src", + "lint:prettier": 'prettier --write "src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}"', + "lint:stylelint": 'stylelint --cache --fix "**/*.{vue,less,postcss,css,scss}" --cache --cache-location node_modules/.cache/stylelint/', + "lint:lint-staged": "lint-staged", + prepare: "husky install", + release: "standard-version", + commit: "git add -A && czg && git push" + }, + dependencies: { + "@element-plus/icons-vue": "^2.1.0", + "@types/decimal.js": "^7.4.0", + "@vueuse/core": "^10.1.2", + "@wangeditor/editor": "^5.1.23", + "@wangeditor/editor-for-vue": "^5.1.12", + "async-validator": "^4.2.5", + axios: "^1.4.0", + dayjs: "^1.11.9", + decimal: "^0.0.2", + "driver.js": "^0.9.8", + "element-plus": "^2.3.4", + "file-saver": "^2.0.5", + "js-md5": "^0.7.3", + "lodash-es": "^4.17.21", + mitt: "^3.0.0", + nprogress: "^0.2.0", + pinia: "^2.1.3", + "pinia-plugin-persistedstate": "^3.1.0", + "print-js": "^1.6.0", + qs: "^6.11.2", + sortablejs: "^1.15.0", + vue: "^3.3.4", + "vue-router": "^4.2.2", + vuedraggable: "^4.1.0", + "vxe-table": "^4.5.0-beta.10", + "xe-utils": "^3.5.11", + xlsx: "^0.18.5" + }, + devDependencies: { + "@commitlint/cli": "^17.6.3", + "@commitlint/config-conventional": "^17.6.3", + "@iconify-json/ep": "^1.1.10", + "@types/file-saver": "^2.0.5", + "@types/js-md5": "^0.7.0", + "@types/nprogress": "^0.2.0", + "@types/qs": "^6.9.7", + "@types/sortablejs": "^1.15.1", + "@typescript-eslint/eslint-plugin": "^5.59.7", + "@typescript-eslint/parser": "^5.59.7", + "@vitejs/plugin-vue": "^4.2.3", + "@vitejs/plugin-vue-jsx": "^3.0.1", + autoprefixer: "^10.4.14", + "cz-git": "^1.6.1", + czg: "^1.6.1", + eslint: "^8.41.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-vue": "^9.14.0", + husky: "^8.0.3", + "lint-staged": "^13.2.2", + postcss: "^8.4.23", + "postcss-html": "^1.5.0", + prettier: "^2.8.8", + "rollup-plugin-visualizer": "^5.9.0", + sass: "^1.62.1", + "standard-version": "^9.5.0", + stylelint: "^15.6.2", + "stylelint-config-html": "^1.1.0", + "stylelint-config-recess-order": "^4.0.0", + "stylelint-config-recommended-scss": "^12.0.0", + "stylelint-config-recommended-vue": "^1.4.0", + "stylelint-config-standard": "^33.0.0", + "stylelint-config-standard-scss": "^9.0.0", + typescript: "^5.0.2", + "unplugin-auto-import": "^0.16.4", + "unplugin-icons": "^0.16.3", + "unplugin-vue-components": "^0.25.1", + "unplugin-vue-setup-extend-plus": "^1.0.0", + vite: "^4.3.9", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-eslint": "^1.8.1", + "vite-plugin-html": "^3.2.0", + "vite-plugin-pwa": "^0.15.0", + "vite-plugin-svg-icons": "^2.0.1", + "vue-tsc": "^1.6.5" + }, + engines: { + node: ">=16.0.0" + }, + browserslist: { + production: [ + "> 1%", + "not dead", + "not op_mini all" + ], + development: [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + config: { + commitizen: { + path: "node_modules/cz-git" + } + } +}; + +// vite.config.ts +import dayjs from "file:///D:/new_ops/orico-wms-ts-admin/node_modules/dayjs/dayjs.min.js"; +var __vite_injected_original_dirname = "D:\\new_ops\\orico-wms-ts-admin"; +var { dependencies, devDependencies, name, version } = package_default; +var __APP_INFO__ = { + pkg: { dependencies, devDependencies, name, version }, + lastBuildTime: dayjs().format("YYYY-MM-DD HH:mm:ss") +}; +var vite_config_default = defineConfig(({ mode }) => { + const root = process.cwd(); + const env = loadEnv(mode, root); + const viteEnv = wrapperEnv(env); + return { + base: viteEnv.VITE_PUBLIC_PATH, + root, + resolve: { + alias: { + "@": resolve2(__vite_injected_original_dirname, "./src") + } + }, + define: { + __APP_INFO__: JSON.stringify(__APP_INFO__) + }, + css: { + preprocessorOptions: { + scss: { + additionalData: `@use "@/styles/var.scss" as *;` + } + } + }, + server: { + host: "0.0.0.0", + port: viteEnv.VITE_PORT, + open: viteEnv.VITE_OPEN, + cors: true, + // Load proxy configuration from .env.development + proxy: createProxy(viteEnv.VITE_PROXY) + }, + plugins: createVitePlugins(viteEnv), + esbuild: { + pure: viteEnv.VITE_DROP_CONSOLE ? ["console.log", "debugger"] : [] + }, + build: { + outDir: "dist", + minify: "esbuild", + // esbuild 打包更快,但是不能去除 console.log,terser打包慢,但能去除 console.log + // minify: "terser", + // terserOptions: { + // compress: { + // drop_console: viteEnv.VITE_DROP_CONSOLE, + // drop_debugger: true + // } + // }, + // 禁用 gzip 压缩大小报告,可略微减少打包时间 + reportCompressedSize: false, + // 规定触发警告的 chunk 大小 + chunkSizeWarningLimit: 2e3, + rollupOptions: { + output: { + // Static resource classification and packaging + chunkFileNames: "assets/js/[name]-[hash].js", + entryFileNames: "assets/js/[name]-[hash].js", + assetFileNames: "assets/[ext]/[name]-[hash].[ext]" + } + } + } + }; +}); +export { + vite_config_default as default +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiLCAiYnVpbGQvZ2V0RW52LnRzIiwgImJ1aWxkL3Byb3h5LnRzIiwgImJ1aWxkL3BsdWdpbnMudHMiLCAicGFja2FnZS5qc29uIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiRDpcXFxcbmV3X29wc1xcXFxvcmljby13bXMtdHMtYWRtaW5cIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkQ6XFxcXG5ld19vcHNcXFxcb3JpY28td21zLXRzLWFkbWluXFxcXHZpdGUuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9EOi9uZXdfb3BzL29yaWNvLXdtcy10cy1hZG1pbi92aXRlLmNvbmZpZy50c1wiO2ltcG9ydCB7IGRlZmluZUNvbmZpZywgbG9hZEVudiwgQ29uZmlnRW52LCBVc2VyQ29uZmlnIH0gZnJvbSBcInZpdGVcIjtcbmltcG9ydCB7IHJlc29sdmUgfSBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgd3JhcHBlckVudiB9IGZyb20gXCIuL2J1aWxkL2dldEVudlwiO1xuaW1wb3J0IHsgY3JlYXRlUHJveHkgfSBmcm9tIFwiLi9idWlsZC9wcm94eVwiO1xuaW1wb3J0IHsgY3JlYXRlVml0ZVBsdWdpbnMgfSBmcm9tIFwiLi9idWlsZC9wbHVnaW5zXCI7XG5cbmltcG9ydCBwa2cgZnJvbSBcIi4vcGFja2FnZS5qc29uXCI7XG5pbXBvcnQgZGF5anMgZnJvbSBcImRheWpzXCI7XG5cbmNvbnN0IHsgZGVwZW5kZW5jaWVzLCBkZXZEZXBlbmRlbmNpZXMsIG5hbWUsIHZlcnNpb24gfSA9IHBrZztcbmNvbnN0IF9fQVBQX0lORk9fXyA9IHtcbiAgICBwa2c6IHsgZGVwZW5kZW5jaWVzLCBkZXZEZXBlbmRlbmNpZXMsIG5hbWUsIHZlcnNpb24gfSxcbiAgICBsYXN0QnVpbGRUaW1lOiBkYXlqcygpLmZvcm1hdChcIllZWVktTU0tREQgSEg6bW06c3NcIilcbn07XG5cbi8vIEBzZWU6IGh0dHBzOi8vdml0ZWpzLmRldi9jb25maWcvXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoKHsgbW9kZSB9OiBDb25maWdFbnYpOiBVc2VyQ29uZmlnID0+IHtcbiAgICBjb25zdCByb290ID0gcHJvY2Vzcy5jd2QoKTtcbiAgICBjb25zdCBlbnYgPSBsb2FkRW52KG1vZGUsIHJvb3QpO1xuICAgIGNvbnN0IHZpdGVFbnYgPSB3cmFwcGVyRW52KGVudik7XG5cbiAgICByZXR1cm4ge1xuICAgICAgICBiYXNlOiB2aXRlRW52LlZJVEVfUFVCTElDX1BBVEgsXG4gICAgICAgIHJvb3QsXG4gICAgICAgIHJlc29sdmU6IHtcbiAgICAgICAgICAgIGFsaWFzOiB7XG4gICAgICAgICAgICAgICAgXCJAXCI6IHJlc29sdmUoX19kaXJuYW1lLCBcIi4vc3JjXCIpXG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGRlZmluZToge1xuICAgICAgICAgICAgX19BUFBfSU5GT19fOiBKU09OLnN0cmluZ2lmeShfX0FQUF9JTkZPX18pXG4gICAgICAgIH0sXG4gICAgICAgIGNzczoge1xuICAgICAgICAgICAgcHJlcHJvY2Vzc29yT3B0aW9uczoge1xuICAgICAgICAgICAgICAgIHNjc3M6IHtcbiAgICAgICAgICAgICAgICAgICAgYWRkaXRpb25hbERhdGE6IGBAdXNlIFwiQC9zdHlsZXMvdmFyLnNjc3NcIiBhcyAqO2BcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHNlcnZlcjoge1xuICAgICAgICAgICAgaG9zdDogXCIwLjAuMC4wXCIsXG4gICAgICAgICAgICBwb3J0OiB2aXRlRW52LlZJVEVfUE9SVCxcbiAgICAgICAgICAgIG9wZW46IHZpdGVFbnYuVklURV9PUEVOLFxuICAgICAgICAgICAgY29yczogdHJ1ZSxcbiAgICAgICAgICAgIC8vIExvYWQgcHJveHkgY29uZmlndXJhdGlvbiBmcm9tIC5lbnYuZGV2ZWxvcG1lbnRcbiAgICAgICAgICAgIHByb3h5OiBjcmVhdGVQcm94eSh2aXRlRW52LlZJVEVfUFJPWFkpXG4gICAgICAgIH0sXG4gICAgICAgIHBsdWdpbnM6IGNyZWF0ZVZpdGVQbHVnaW5zKHZpdGVFbnYpLFxuICAgICAgICBlc2J1aWxkOiB7XG4gICAgICAgICAgICBwdXJlOiB2aXRlRW52LlZJVEVfRFJPUF9DT05TT0xFID8gW1wiY29uc29sZS5sb2dcIiwgXCJkZWJ1Z2dlclwiXSA6IFtdXG4gICAgICAgIH0sXG4gICAgICAgIGJ1aWxkOiB7XG4gICAgICAgICAgICBvdXREaXI6IFwiZGlzdFwiLFxuICAgICAgICAgICAgbWluaWZ5OiBcImVzYnVpbGRcIixcbiAgICAgICAgICAgIC8vIGVzYnVpbGQgXHU2MjUzXHU1MzA1XHU2NkY0XHU1RkVCXHVGRjBDXHU0RjQ2XHU2NjJGXHU0RTBEXHU4MEZEXHU1M0JCXHU5NjY0IGNvbnNvbGUubG9nXHVGRjBDdGVyc2VyXHU2MjUzXHU1MzA1XHU2MTYyXHVGRjBDXHU0RjQ2XHU4MEZEXHU1M0JCXHU5NjY0IGNvbnNvbGUubG9nXG4gICAgICAgICAgICAvLyBtaW5pZnk6IFwidGVyc2VyXCIsXG4gICAgICAgICAgICAvLyB0ZXJzZXJPcHRpb25zOiB7XG4gICAgICAgICAgICAvLyBcdGNvbXByZXNzOiB7XG4gICAgICAgICAgICAvLyBcdFx0ZHJvcF9jb25zb2xlOiB2aXRlRW52LlZJVEVfRFJPUF9DT05TT0xFLFxuICAgICAgICAgICAgLy8gXHRcdGRyb3BfZGVidWdnZXI6IHRydWVcbiAgICAgICAgICAgIC8vIFx0fVxuICAgICAgICAgICAgLy8gfSxcbiAgICAgICAgICAgIC8vIFx1Nzk4MVx1NzUyOCBnemlwIFx1NTM4Qlx1N0YyOVx1NTkyN1x1NUMwRlx1NjJBNVx1NTQ0QVx1RkYwQ1x1NTNFRlx1NzU2NVx1NUZBRVx1NTFDRlx1NUMxMVx1NjI1M1x1NTMwNVx1NjVGNlx1OTVGNFxuICAgICAgICAgICAgcmVwb3J0Q29tcHJlc3NlZFNpemU6IGZhbHNlLFxuICAgICAgICAgICAgLy8gXHU4OUM0XHU1QjlBXHU4OUU2XHU1M0QxXHU4QjY2XHU1NDRBXHU3Njg0IGNodW5rIFx1NTkyN1x1NUMwRlxuICAgICAgICAgICAgY2h1bmtTaXplV2FybmluZ0xpbWl0OiAyMDAwLFxuICAgICAgICAgICAgcm9sbHVwT3B0aW9uczoge1xuICAgICAgICAgICAgICAgIG91dHB1dDoge1xuICAgICAgICAgICAgICAgICAgICAvLyBTdGF0aWMgcmVzb3VyY2UgY2xhc3NpZmljYXRpb24gYW5kIHBhY2thZ2luZ1xuICAgICAgICAgICAgICAgICAgICBjaHVua0ZpbGVOYW1lczogXCJhc3NldHMvanMvW25hbWVdLVtoYXNoXS5qc1wiLFxuICAgICAgICAgICAgICAgICAgICBlbnRyeUZpbGVOYW1lczogXCJhc3NldHMvanMvW25hbWVdLVtoYXNoXS5qc1wiLFxuICAgICAgICAgICAgICAgICAgICBhc3NldEZpbGVOYW1lczogXCJhc3NldHMvW2V4dF0vW25hbWVdLVtoYXNoXS5bZXh0XVwiXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbn0pO1xuIiwgImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxuZXdfb3BzXFxcXG9yaWNvLXdtcy10cy1hZG1pblxcXFxidWlsZFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRDpcXFxcbmV3X29wc1xcXFxvcmljby13bXMtdHMtYWRtaW5cXFxcYnVpbGRcXFxcZ2V0RW52LnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9EOi9uZXdfb3BzL29yaWNvLXdtcy10cy1hZG1pbi9idWlsZC9nZXRFbnYudHNcIjtpbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuXG5leHBvcnQgZnVuY3Rpb24gaXNEZXZGbihtb2RlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gbW9kZSA9PT0gXCJkZXZlbG9wbWVudFwiO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNQcm9kRm4obW9kZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIG1vZGUgPT09IFwicHJvZHVjdGlvblwiO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNUZXN0Rm4obW9kZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIG1vZGUgPT09IFwidGVzdFwiO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgdG8gZ2VuZXJhdGUgcGFja2FnZSBwcmV2aWV3XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1JlcG9ydE1vZGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHByb2Nlc3MuZW52LlZJVEVfUkVQT1JUID09PSBcInRydWVcIjtcbn1cblxuLy8gUmVhZCBhbGwgZW52aXJvbm1lbnQgdmFyaWFibGUgY29uZmlndXJhdGlvbiBmaWxlcyB0byBwcm9jZXNzLmVudlxuZXhwb3J0IGZ1bmN0aW9uIHdyYXBwZXJFbnYoZW52Q29uZjogUmVjb3JkYWJsZSk6IFZpdGVFbnYge1xuICAgIGNvbnN0IHJldDogYW55ID0ge307XG5cbiAgICBmb3IgKGNvbnN0IGVudk5hbWUgb2YgT2JqZWN0LmtleXMoZW52Q29uZikpIHtcbiAgICAgICAgbGV0IHJlYWxOYW1lID0gZW52Q29uZltlbnZOYW1lXS5yZXBsYWNlKC9cXFxcbi9nLCBcIlxcblwiKTtcbiAgICAgICAgcmVhbE5hbWUgPSByZWFsTmFtZSA9PT0gXCJ0cnVlXCIgPyB0cnVlIDogcmVhbE5hbWUgPT09IFwiZmFsc2VcIiA/IGZhbHNlIDogcmVhbE5hbWU7XG4gICAgICAgIGlmIChlbnZOYW1lID09PSBcIlZJVEVfUE9SVFwiKSByZWFsTmFtZSA9IE51bWJlcihyZWFsTmFtZSk7XG4gICAgICAgIGlmIChlbnZOYW1lID09PSBcIlZJVEVfUFJPWFlcIikge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICByZWFsTmFtZSA9IEpTT04ucGFyc2UocmVhbE5hbWUpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHt9XG4gICAgICAgIH1cbiAgICAgICAgcmV0W2Vudk5hbWVdID0gcmVhbE5hbWU7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG59XG5cbi8qKlxuICogR2V0IHVzZXIgcm9vdCBkaXJlY3RvcnlcbiAqIEBwYXJhbSBkaXIgZmlsZSBwYXRoXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRSb290UGF0aCguLi5kaXI6IHN0cmluZ1tdKSB7XG4gICAgcmV0dXJuIHBhdGgucmVzb2x2ZShwcm9jZXNzLmN3ZCgpLCAuLi5kaXIpO1xufVxuIiwgImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxuZXdfb3BzXFxcXG9yaWNvLXdtcy10cy1hZG1pblxcXFxidWlsZFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRDpcXFxcbmV3X29wc1xcXFxvcmljby13bXMtdHMtYWRtaW5cXFxcYnVpbGRcXFxccHJveHkudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0Q6L25ld19vcHMvb3JpY28td21zLXRzLWFkbWluL2J1aWxkL3Byb3h5LnRzXCI7aW1wb3J0IHR5cGUgeyBQcm94eU9wdGlvbnMgfSBmcm9tIFwidml0ZVwiO1xuXG50eXBlIFByb3h5SXRlbSA9IFtzdHJpbmcsIHN0cmluZ107XG5cbnR5cGUgUHJveHlMaXN0ID0gUHJveHlJdGVtW107XG5cbnR5cGUgUHJveHlUYXJnZXRMaXN0ID0gUmVjb3JkPHN0cmluZywgUHJveHlPcHRpb25zPjtcblxuLyoqXG4gKiBcdTUyMUJcdTVFRkFcdTRFRTNcdTc0MDZcdUZGMENcdTc1MjhcdTRFOEVcdTg5RTNcdTY3OTAgLmVudi5kZXZlbG9wbWVudCBcdTRFRTNcdTc0MDZcdTkxNERcdTdGNkVcbiAqIEBwYXJhbSBsaXN0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQcm94eShsaXN0OiBQcm94eUxpc3QgPSBbXSkge1xuICAgIGNvbnN0IHJldDogUHJveHlUYXJnZXRMaXN0ID0ge307XG4gICAgZm9yIChjb25zdCBbcHJlZml4LCB0YXJnZXRdIG9mIGxpc3QpIHtcbiAgICAgICAgY29uc3QgaHR0cHNSRSA9IC9eaHR0cHM6XFwvXFwvLztcbiAgICAgICAgY29uc3QgaXNIdHRwcyA9IGh0dHBzUkUudGVzdCh0YXJnZXQpO1xuXG4gICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9odHRwLXBhcnR5L25vZGUtaHR0cC1wcm94eSNvcHRpb25zXG4gICAgICAgIHJldFtwcmVmaXhdID0ge1xuICAgICAgICAgICAgdGFyZ2V0OiB0YXJnZXQsXG4gICAgICAgICAgICBjaGFuZ2VPcmlnaW46IHRydWUsXG4gICAgICAgICAgICB3czogdHJ1ZSxcbiAgICAgICAgICAgIHJld3JpdGU6IHBhdGggPT4gcGF0aC5yZXBsYWNlKG5ldyBSZWdFeHAoYF4ke3ByZWZpeH1gKSwgXCJcIiksXG4gICAgICAgICAgICAvLyBodHRwcyBpcyByZXF1aXJlIHNlY3VyZT1mYWxzZVxuICAgICAgICAgICAgLi4uKGlzSHR0cHMgPyB7IHNlY3VyZTogZmFsc2UgfSA6IHt9KVxuICAgICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4gcmV0O1xufVxuIiwgImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxuZXdfb3BzXFxcXG9yaWNvLXdtcy10cy1hZG1pblxcXFxidWlsZFwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRDpcXFxcbmV3X29wc1xcXFxvcmljby13bXMtdHMtYWRtaW5cXFxcYnVpbGRcXFxccGx1Z2lucy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vRDovbmV3X29wcy9vcmljby13bXMtdHMtYWRtaW4vYnVpbGQvcGx1Z2lucy50c1wiO2ltcG9ydCB7IHJlc29sdmUgfSBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgUGx1Z2luT3B0aW9uIH0gZnJvbSBcInZpdGVcIjtcbmltcG9ydCB7IFZpdGVQV0EgfSBmcm9tIFwidml0ZS1wbHVnaW4tcHdhXCI7XG5pbXBvcnQgeyB2aXN1YWxpemVyIH0gZnJvbSBcInJvbGx1cC1wbHVnaW4tdmlzdWFsaXplclwiO1xuaW1wb3J0IHsgY3JlYXRlSHRtbFBsdWdpbiB9IGZyb20gXCJ2aXRlLXBsdWdpbi1odG1sXCI7XG5pbXBvcnQgeyBjcmVhdGVTdmdJY29uc1BsdWdpbiB9IGZyb20gXCJ2aXRlLXBsdWdpbi1zdmctaWNvbnNcIjtcbmltcG9ydCB2dWUgZnJvbSBcIkB2aXRlanMvcGx1Z2luLXZ1ZVwiO1xuaW1wb3J0IHZ1ZUpzeCBmcm9tIFwiQHZpdGVqcy9wbHVnaW4tdnVlLWpzeFwiO1xuaW1wb3J0IGVzbGludFBsdWdpbiBmcm9tIFwidml0ZS1wbHVnaW4tZXNsaW50XCI7XG5pbXBvcnQgdml0ZUNvbXByZXNzaW9uIGZyb20gXCJ2aXRlLXBsdWdpbi1jb21wcmVzc2lvblwiO1xuaW1wb3J0IHZ1ZVNldHVwRXh0ZW5kIGZyb20gXCJ1bnBsdWdpbi12dWUtc2V0dXAtZXh0ZW5kLXBsdXMvdml0ZVwiO1xuLy8gXHU4MUVBXHU1MkE4XHU1QkZDXHU1MTY1dnVlXHU0RTJEaG9vayByZWFjdGl2ZSByZWZcdTdCNDlcbmltcG9ydCBBdXRvSW1wb3J0IGZyb20gXCJ1bnBsdWdpbi1hdXRvLWltcG9ydC92aXRlXCI7XG4vLyBcdTgxRUFcdTUyQThcdTVCRkNcdTUxNjV1aS1cdTdFQzRcdTRFRjYgXHU2QkQ0XHU1OTgyXHU4QkY0YW50LWRlc2lnbi12dWUgIGVsZW1lbnQtcGx1c1x1N0I0OVxuaW1wb3J0IENvbXBvbmVudHMgZnJvbSBcInVucGx1Z2luLXZ1ZS1jb21wb25lbnRzL3ZpdGVcIjtcbi8vIGVsZW1lbnRcbmltcG9ydCB7IEVsZW1lbnRQbHVzUmVzb2x2ZXIgfSBmcm9tIFwidW5wbHVnaW4tdnVlLWNvbXBvbmVudHMvcmVzb2x2ZXJzXCI7XG4vLyBcdTVCRkNcdTUxNjVcdTU2RkVcdTY4MDdcbmltcG9ydCBJY29ucyBmcm9tIFwidW5wbHVnaW4taWNvbnMvdml0ZVwiO1xuaW1wb3J0IEljb25zUmVzb2x2ZXIgZnJvbSBcInVucGx1Z2luLWljb25zL3Jlc29sdmVyXCI7XG5cbi8qKlxuICogXHU1MjFCXHU1RUZBIHZpdGUgXHU2M0QyXHU0RUY2XG4gKiBAcGFyYW0gdml0ZUVudlxuICovXG5leHBvcnQgY29uc3QgY3JlYXRlVml0ZVBsdWdpbnMgPSAodml0ZUVudjogVml0ZUVudik6IChQbHVnaW5PcHRpb24gfCBQbHVnaW5PcHRpb25bXSlbXSA9PiB7XG4gICAgY29uc3QgeyBWSVRFX0dMT0JfQVBQX1RJVExFLCBWSVRFX1JFUE9SVCwgVklURV9QV0EgfSA9IHZpdGVFbnY7XG4gICAgcmV0dXJuIFtcbiAgICAgICAgdnVlKCksXG4gICAgICAgIC8vIHZ1ZSBcdTUzRUZcdTRFRTVcdTRGN0ZcdTc1MjgganN4L3RzeCBcdThCRURcdTZDRDVcbiAgICAgICAgdnVlSnN4KCksXG4gICAgICAgIC8vIGVzTGludCBcdTYyQTVcdTk1MTlcdTRGRTFcdTYwNkZcdTY2M0VcdTc5M0FcdTU3MjhcdTZENEZcdTg5QzhcdTU2NjhcdTc1NENcdTk3NjJcdTRFMEFcbiAgICAgICAgZXNsaW50UGx1Z2luKCksXG4gICAgICAgIC8vIG5hbWUgXHU1M0VGXHU0RUU1XHU1MTk5XHU1NzI4IHNjcmlwdCBcdTY4MDdcdTdCN0VcdTRFMEFcbiAgICAgICAgdnVlU2V0dXBFeHRlbmQoe30pLFxuICAgICAgICAvLyBcdTUyMUJcdTVFRkFcdTYyNTNcdTUzMDVcdTUzOEJcdTdGMjlcdTkxNERcdTdGNkVcbiAgICAgICAgY3JlYXRlQ29tcHJlc3Npb24odml0ZUVudiksXG4gICAgICAgIC8vIFx1NkNFOFx1NTE2NVx1NTNEOFx1OTFDRlx1NTIzMCBodG1sIFx1NjU4N1x1NEVGNlxuICAgICAgICBjcmVhdGVIdG1sUGx1Z2luKHtcbiAgICAgICAgICAgIGluamVjdDoge1xuICAgICAgICAgICAgICAgIGRhdGE6IHsgdGl0bGU6IFZJVEVfR0xPQl9BUFBfVElUTEUgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KSxcbiAgICAgICAgLy8gXHU0RjdGXHU3NTI4IHN2ZyBcdTU2RkVcdTY4MDdcbiAgICAgICAgY3JlYXRlU3ZnSWNvbnNQbHVnaW4oe1xuICAgICAgICAgICAgaWNvbkRpcnM6IFtyZXNvbHZlKHByb2Nlc3MuY3dkKCksIFwic3JjL2Fzc2V0cy9pY29uc1wiKV0sXG4gICAgICAgICAgICBzeW1ib2xJZDogXCJpY29uLVtkaXJdLVtuYW1lXVwiXG4gICAgICAgIH0pLFxuICAgICAgICAvLyBlbGVtZW50XHU2MzA5XHU5NzAwXHU1QkZDXHU1MTY1XG4gICAgICAgIEF1dG9JbXBvcnQoe1xuICAgICAgICAgICAgLy8gXHU1Qjg5XHU4OEM1XHU0RTI0XHU4ODRDXHU1NDBFXHU0RjYwXHU0RjFBXHU1M0QxXHU3M0IwXHU1NzI4XHU3RUM0XHU0RUY2XHU0RTJEXHU0RTBEXHU3NTI4XHU1MThEXHU1QkZDXHU1MTY1cmVmXHVGRjBDcmVhY3RpdmVcdTdCNDlcbiAgICAgICAgICAgIGltcG9ydHM6IFtcInZ1ZVwiLCBcInZ1ZS1yb3V0ZXJcIl0sXG4gICAgICAgICAgICBkdHM6IFwic3JjL2F1dG8taW1wb3J0LmQudHNcIixcbiAgICAgICAgICAgIC8vIGVsZW1lbnRcbiAgICAgICAgICAgIHJlc29sdmVyczogW1xuICAgICAgICAgICAgICAgIEVsZW1lbnRQbHVzUmVzb2x2ZXIoeyBpbXBvcnRTdHlsZTogXCJzYXNzXCIgfSksXG4gICAgICAgICAgICAgICAgSWNvbnNSZXNvbHZlcih7XG4gICAgICAgICAgICAgICAgICAgIHByZWZpeDogXCJJY29uXCJcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgXVxuICAgICAgICB9KSxcbiAgICAgICAgQ29tcG9uZW50cyh7XG4gICAgICAgICAgICAvLyBlbGVtZW50XG4gICAgICAgICAgICByZXNvbHZlcnM6IFtcbiAgICAgICAgICAgICAgICBFbGVtZW50UGx1c1Jlc29sdmVyKHsgaW1wb3J0U3R5bGU6IFwic2Fzc1wiIH0pLFxuICAgICAgICAgICAgICAgIEljb25zUmVzb2x2ZXIoe1xuICAgICAgICAgICAgICAgICAgICBlbmFibGVkQ29sbGVjdGlvbnM6IFtcImVwXCJdXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAvLyBcdTlFRDhcdThCQTRcdTVCNThcdTY1M0VcdTRGNERcdTdGNkVcbiAgICAgICAgICAgIGR0czogXCJzcmMvY29tcG9uZW50cy5kLnRzXCJcbiAgICAgICAgfSksXG4gICAgICAgIEljb25zKHtcbiAgICAgICAgICAgIGF1dG9JbnN0YWxsOiB0cnVlXG4gICAgICAgIH0pLFxuICAgICAgICAvLyB2aXRlUFdBXG4gICAgICAgIFZJVEVfUFdBICYmIGNyZWF0ZVZpdGVQd2Eodml0ZUVudiksXG4gICAgICAgIC8vIFx1NjYyRlx1NTQyNlx1NzUxRlx1NjIxMFx1NTMwNVx1OTg4NFx1ODlDOFx1RkYwQ1x1NTIwNlx1Njc5MFx1NEY5RFx1OEQ1Nlx1NTMwNVx1NTkyN1x1NUMwRlx1NTA1QVx1NEYxOFx1NTMxNlx1NTkwNFx1NzQwNlxuICAgICAgICBWSVRFX1JFUE9SVCAmJiAodmlzdWFsaXplcih7IGZpbGVuYW1lOiBcInN0YXRzLmh0bWxcIiwgZ3ppcFNpemU6IHRydWUsIGJyb3RsaVNpemU6IHRydWUgfSkgYXMgUGx1Z2luT3B0aW9uKVxuICAgIF07XG59O1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBcdTY4MzlcdTYzNkUgY29tcHJlc3MgXHU5MTREXHU3RjZFXHVGRjBDXHU3NTFGXHU2MjEwXHU0RTBEXHU1NDBDXHU3Njg0XHU1MzhCXHU3RjI5XHU4OUM0XHU1MjE5XG4gKiBAcGFyYW0gdml0ZUVudlxuICovXG5jb25zdCBjcmVhdGVDb21wcmVzc2lvbiA9ICh2aXRlRW52OiBWaXRlRW52KTogUGx1Z2luT3B0aW9uIHwgUGx1Z2luT3B0aW9uW10gPT4ge1xuICAgIGNvbnN0IHsgVklURV9CVUlMRF9DT01QUkVTUyA9IFwibm9uZVwiLCBWSVRFX0JVSUxEX0NPTVBSRVNTX0RFTEVURV9PUklHSU5fRklMRSB9ID0gdml0ZUVudjtcbiAgICBjb25zdCBjb21wcmVzc0xpc3QgPSBWSVRFX0JVSUxEX0NPTVBSRVNTLnNwbGl0KFwiLFwiKTtcbiAgICBjb25zdCBwbHVnaW5zOiBQbHVnaW5PcHRpb25bXSA9IFtdO1xuICAgIGlmIChjb21wcmVzc0xpc3QuaW5jbHVkZXMoXCJnemlwXCIpKSB7XG4gICAgICAgIHBsdWdpbnMucHVzaChcbiAgICAgICAgICAgIHZpdGVDb21wcmVzc2lvbih7XG4gICAgICAgICAgICAgICAgZXh0OiBcIi5nelwiLFxuICAgICAgICAgICAgICAgIGFsZ29yaXRobTogXCJnemlwXCIsXG4gICAgICAgICAgICAgICAgZGVsZXRlT3JpZ2luRmlsZTogVklURV9CVUlMRF9DT01QUkVTU19ERUxFVEVfT1JJR0lOX0ZJTEVcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgfVxuICAgIGlmIChjb21wcmVzc0xpc3QuaW5jbHVkZXMoXCJicm90bGlcIikpIHtcbiAgICAgICAgcGx1Z2lucy5wdXNoKFxuICAgICAgICAgICAgdml0ZUNvbXByZXNzaW9uKHtcbiAgICAgICAgICAgICAgICBleHQ6IFwiLmJyXCIsXG4gICAgICAgICAgICAgICAgYWxnb3JpdGhtOiBcImJyb3RsaUNvbXByZXNzXCIsXG4gICAgICAgICAgICAgICAgZGVsZXRlT3JpZ2luRmlsZTogVklURV9CVUlMRF9DT01QUkVTU19ERUxFVEVfT1JJR0lOX0ZJTEVcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBwbHVnaW5zO1xufTtcblxuLyoqXG4gKiBAZGVzY3JpcHRpb24gVml0ZVB3YVxuICogQHBhcmFtIHZpdGVFbnZcbiAqL1xuY29uc3QgY3JlYXRlVml0ZVB3YSA9ICh2aXRlRW52OiBWaXRlRW52KTogUGx1Z2luT3B0aW9uIHwgUGx1Z2luT3B0aW9uW10gPT4ge1xuICAgIGNvbnN0IHsgVklURV9HTE9CX0FQUF9USVRMRSB9ID0gdml0ZUVudjtcbiAgICByZXR1cm4gVml0ZVBXQSh7XG4gICAgICAgIHJlZ2lzdGVyVHlwZTogXCJhdXRvVXBkYXRlXCIsXG4gICAgICAgIG1hbmlmZXN0OiB7XG4gICAgICAgICAgICBuYW1lOiBWSVRFX0dMT0JfQVBQX1RJVExFLFxuICAgICAgICAgICAgc2hvcnRfbmFtZTogVklURV9HTE9CX0FQUF9USVRMRSxcbiAgICAgICAgICAgIHRoZW1lX2NvbG9yOiBcIiNmZmZmZmZcIixcbiAgICAgICAgICAgIGljb25zOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBzcmM6IFwiL2xvZ28ucG5nXCIsXG4gICAgICAgICAgICAgICAgICAgIHNpemVzOiBcIjE5MngxOTJcIixcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogXCJpbWFnZS9wbmdcIlxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBzcmM6IFwiL2xvZ28ucG5nXCIsXG4gICAgICAgICAgICAgICAgICAgIHNpemVzOiBcIjUxMng1MTJcIixcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogXCJpbWFnZS9wbmdcIlxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBzcmM6IFwiL2xvZ28ucG5nXCIsXG4gICAgICAgICAgICAgICAgICAgIHNpemVzOiBcIjUxMng1MTJcIixcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogXCJpbWFnZS9wbmdcIixcbiAgICAgICAgICAgICAgICAgICAgcHVycG9zZTogXCJhbnkgbWFza2FibGVcIlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIF1cbiAgICAgICAgfVxuICAgIH0pO1xufTtcbiIsICJ7XG4gICAgXCJuYW1lXCI6IFwib3BzX2FkbWluX3RzXCIsXG4gICAgXCJwcml2YXRlXCI6IHRydWUsXG4gICAgXCJ2ZXJzaW9uXCI6IFwiMS4wLjBcIixcbiAgICBcInR5cGVcIjogXCJtb2R1bGVcIixcbiAgICBcInNjcmlwdHNcIjoge1xuICAgICAgICBcImRldlwiOiBcInZpdGVcIixcbiAgICAgICAgXCJzZXJ2ZVwiOiBcInZpdGVcIixcbiAgICAgICAgXCJidWlsZDpkZXZcIjogXCJ2dWUtdHNjICYmIHZpdGUgYnVpbGQgLS1tb2RlIGRldmVsb3BtZW50XCIsXG4gICAgICAgIFwiYnVpbGQ6dGVzdFwiOiBcInZ1ZS10c2MgJiYgdml0ZSBidWlsZCAtLW1vZGUgdGVzdFwiLFxuICAgICAgICBcImJ1aWxkOnByb1wiOiBcInZ1ZS10c2MgJiYgdml0ZSBidWlsZCAtLW1vZGUgcHJvZHVjdGlvblwiLFxuICAgICAgICBcInR5cGU6Y2hlY2tcIjogXCJ2dWUtdHNjIC0tbm9FbWl0IC0tc2tpcExpYkNoZWNrXCIsXG4gICAgICAgIFwicHJldmlld1wiOiBcIm5wbSBydW4gYnVpbGQ6ZGV2ICYmIHZpdGUgcHJldmlld1wiLFxuICAgICAgICBcImxpbnQ6ZXNsaW50XCI6IFwiZXNsaW50IC0tZml4IC0tZXh0IC5qcywudHMsLnZ1ZSAuL3NyY1wiLFxuICAgICAgICBcImxpbnQ6cHJldHRpZXJcIjogXCJwcmV0dGllciAtLXdyaXRlIFxcXCJzcmMvKiovKi57anMsdHMsanNvbix0c3gsY3NzLGxlc3Msc2Nzcyx2dWUsaHRtbCxtZH1cXFwiXCIsXG4gICAgICAgIFwibGludDpzdHlsZWxpbnRcIjogXCJzdHlsZWxpbnQgLS1jYWNoZSAtLWZpeCBcXFwiKiovKi57dnVlLGxlc3MscG9zdGNzcyxjc3Msc2Nzc31cXFwiIC0tY2FjaGUgLS1jYWNoZS1sb2NhdGlvbiBub2RlX21vZHVsZXMvLmNhY2hlL3N0eWxlbGludC9cIixcbiAgICAgICAgXCJsaW50OmxpbnQtc3RhZ2VkXCI6IFwibGludC1zdGFnZWRcIixcbiAgICAgICAgXCJwcmVwYXJlXCI6IFwiaHVza3kgaW5zdGFsbFwiLFxuICAgICAgICBcInJlbGVhc2VcIjogXCJzdGFuZGFyZC12ZXJzaW9uXCIsXG4gICAgICAgIFwiY29tbWl0XCI6IFwiZ2l0IGFkZCAtQSAmJiBjemcgJiYgZ2l0IHB1c2hcIlxuICAgIH0sXG4gICAgXCJkZXBlbmRlbmNpZXNcIjoge1xuICAgICAgICBcIkBlbGVtZW50LXBsdXMvaWNvbnMtdnVlXCI6IFwiXjIuMS4wXCIsXG4gICAgICAgIFwiQHR5cGVzL2RlY2ltYWwuanNcIjogXCJeNy40LjBcIixcbiAgICAgICAgXCJAdnVldXNlL2NvcmVcIjogXCJeMTAuMS4yXCIsXG4gICAgICAgIFwiQHdhbmdlZGl0b3IvZWRpdG9yXCI6IFwiXjUuMS4yM1wiLFxuICAgICAgICBcIkB3YW5nZWRpdG9yL2VkaXRvci1mb3ItdnVlXCI6IFwiXjUuMS4xMlwiLFxuICAgICAgICBcImFzeW5jLXZhbGlkYXRvclwiOiBcIl40LjIuNVwiLFxuICAgICAgICBcImF4aW9zXCI6IFwiXjEuNC4wXCIsXG4gICAgICAgIFwiZGF5anNcIjogXCJeMS4xMS45XCIsXG4gICAgICAgIFwiZGVjaW1hbFwiOiBcIl4wLjAuMlwiLFxuICAgICAgICBcImRyaXZlci5qc1wiOiBcIl4wLjkuOFwiLFxuICAgICAgICBcImVsZW1lbnQtcGx1c1wiOiBcIl4yLjMuNFwiLFxuICAgICAgICBcImZpbGUtc2F2ZXJcIjogXCJeMi4wLjVcIixcbiAgICAgICAgXCJqcy1tZDVcIjogXCJeMC43LjNcIixcbiAgICAgICAgXCJsb2Rhc2gtZXNcIjogXCJeNC4xNy4yMVwiLFxuICAgICAgICBcIm1pdHRcIjogXCJeMy4wLjBcIixcbiAgICAgICAgXCJucHJvZ3Jlc3NcIjogXCJeMC4yLjBcIixcbiAgICAgICAgXCJwaW5pYVwiOiBcIl4yLjEuM1wiLFxuICAgICAgICBcInBpbmlhLXBsdWdpbi1wZXJzaXN0ZWRzdGF0ZVwiOiBcIl4zLjEuMFwiLFxuICAgICAgICBcInByaW50LWpzXCI6IFwiXjEuNi4wXCIsXG4gICAgICAgIFwicXNcIjogXCJeNi4xMS4yXCIsXG4gICAgICAgIFwic29ydGFibGVqc1wiOiBcIl4xLjE1LjBcIixcbiAgICAgICAgXCJ2dWVcIjogXCJeMy4zLjRcIixcbiAgICAgICAgXCJ2dWUtcm91dGVyXCI6IFwiXjQuMi4yXCIsXG4gICAgICAgIFwidnVlZHJhZ2dhYmxlXCI6IFwiXjQuMS4wXCIsXG4gICAgICAgIFwidnhlLXRhYmxlXCI6IFwiXjQuNS4wLWJldGEuMTBcIixcbiAgICAgICAgXCJ4ZS11dGlsc1wiOiBcIl4zLjUuMTFcIixcbiAgICAgICAgXCJ4bHN4XCI6IFwiXjAuMTguNVwiXG4gICAgfSxcbiAgICBcImRldkRlcGVuZGVuY2llc1wiOiB7XG4gICAgICAgIFwiQGNvbW1pdGxpbnQvY2xpXCI6IFwiXjE3LjYuM1wiLFxuICAgICAgICBcIkBjb21taXRsaW50L2NvbmZpZy1jb252ZW50aW9uYWxcIjogXCJeMTcuNi4zXCIsXG4gICAgICAgIFwiQGljb25pZnktanNvbi9lcFwiOiBcIl4xLjEuMTBcIixcbiAgICAgICAgXCJAdHlwZXMvZmlsZS1zYXZlclwiOiBcIl4yLjAuNVwiLFxuICAgICAgICBcIkB0eXBlcy9qcy1tZDVcIjogXCJeMC43LjBcIixcbiAgICAgICAgXCJAdHlwZXMvbnByb2dyZXNzXCI6IFwiXjAuMi4wXCIsXG4gICAgICAgIFwiQHR5cGVzL3FzXCI6IFwiXjYuOS43XCIsXG4gICAgICAgIFwiQHR5cGVzL3NvcnRhYmxlanNcIjogXCJeMS4xNS4xXCIsXG4gICAgICAgIFwiQHR5cGVzY3JpcHQtZXNsaW50L2VzbGludC1wbHVnaW5cIjogXCJeNS41OS43XCIsXG4gICAgICAgIFwiQHR5cGVzY3JpcHQtZXNsaW50L3BhcnNlclwiOiBcIl41LjU5LjdcIixcbiAgICAgICAgXCJAdml0ZWpzL3BsdWdpbi12dWVcIjogXCJeNC4yLjNcIixcbiAgICAgICAgXCJAdml0ZWpzL3BsdWdpbi12dWUtanN4XCI6IFwiXjMuMC4xXCIsXG4gICAgICAgIFwiYXV0b3ByZWZpeGVyXCI6IFwiXjEwLjQuMTRcIixcbiAgICAgICAgXCJjei1naXRcIjogXCJeMS42LjFcIixcbiAgICAgICAgXCJjemdcIjogXCJeMS42LjFcIixcbiAgICAgICAgXCJlc2xpbnRcIjogXCJeOC40MS4wXCIsXG4gICAgICAgIFwiZXNsaW50LWNvbmZpZy1wcmV0dGllclwiOiBcIl44LjguMFwiLFxuICAgICAgICBcImVzbGludC1wbHVnaW4tcHJldHRpZXJcIjogXCJeNC4yLjFcIixcbiAgICAgICAgXCJlc2xpbnQtcGx1Z2luLXZ1ZVwiOiBcIl45LjE0LjBcIixcbiAgICAgICAgXCJodXNreVwiOiBcIl44LjAuM1wiLFxuICAgICAgICBcImxpbnQtc3RhZ2VkXCI6IFwiXjEzLjIuMlwiLFxuICAgICAgICBcInBvc3Rjc3NcIjogXCJeOC40LjIzXCIsXG4gICAgICAgIFwicG9zdGNzcy1odG1sXCI6IFwiXjEuNS4wXCIsXG4gICAgICAgIFwicHJldHRpZXJcIjogXCJeMi44LjhcIixcbiAgICAgICAgXCJyb2xsdXAtcGx1Z2luLXZpc3VhbGl6ZXJcIjogXCJeNS45LjBcIixcbiAgICAgICAgXCJzYXNzXCI6IFwiXjEuNjIuMVwiLFxuICAgICAgICBcInN0YW5kYXJkLXZlcnNpb25cIjogXCJeOS41LjBcIixcbiAgICAgICAgXCJzdHlsZWxpbnRcIjogXCJeMTUuNi4yXCIsXG4gICAgICAgIFwic3R5bGVsaW50LWNvbmZpZy1odG1sXCI6IFwiXjEuMS4wXCIsXG4gICAgICAgIFwic3R5bGVsaW50LWNvbmZpZy1yZWNlc3Mtb3JkZXJcIjogXCJeNC4wLjBcIixcbiAgICAgICAgXCJzdHlsZWxpbnQtY29uZmlnLXJlY29tbWVuZGVkLXNjc3NcIjogXCJeMTIuMC4wXCIsXG4gICAgICAgIFwic3R5bGVsaW50LWNvbmZpZy1yZWNvbW1lbmRlZC12dWVcIjogXCJeMS40LjBcIixcbiAgICAgICAgXCJzdHlsZWxpbnQtY29uZmlnLXN0YW5kYXJkXCI6IFwiXjMzLjAuMFwiLFxuICAgICAgICBcInN0eWxlbGludC1jb25maWctc3RhbmRhcmQtc2Nzc1wiOiBcIl45LjAuMFwiLFxuICAgICAgICBcInR5cGVzY3JpcHRcIjogXCJeNS4wLjJcIixcbiAgICAgICAgXCJ1bnBsdWdpbi1hdXRvLWltcG9ydFwiOiBcIl4wLjE2LjRcIixcbiAgICAgICAgXCJ1bnBsdWdpbi1pY29uc1wiOiBcIl4wLjE2LjNcIixcbiAgICAgICAgXCJ1bnBsdWdpbi12dWUtY29tcG9uZW50c1wiOiBcIl4wLjI1LjFcIixcbiAgICAgICAgXCJ1bnBsdWdpbi12dWUtc2V0dXAtZXh0ZW5kLXBsdXNcIjogXCJeMS4wLjBcIixcbiAgICAgICAgXCJ2aXRlXCI6IFwiXjQuMy45XCIsXG4gICAgICAgIFwidml0ZS1wbHVnaW4tY29tcHJlc3Npb25cIjogXCJeMC41LjFcIixcbiAgICAgICAgXCJ2aXRlLXBsdWdpbi1lc2xpbnRcIjogXCJeMS44LjFcIixcbiAgICAgICAgXCJ2aXRlLXBsdWdpbi1odG1sXCI6IFwiXjMuMi4wXCIsXG4gICAgICAgIFwidml0ZS1wbHVnaW4tcHdhXCI6IFwiXjAuMTUuMFwiLFxuICAgICAgICBcInZpdGUtcGx1Z2luLXN2Zy1pY29uc1wiOiBcIl4yLjAuMVwiLFxuICAgICAgICBcInZ1ZS10c2NcIjogXCJeMS42LjVcIlxuICAgIH0sXG4gICAgXCJlbmdpbmVzXCI6IHtcbiAgICAgICAgXCJub2RlXCI6IFwiPj0xNi4wLjBcIlxuICAgIH0sXG4gICAgXCJicm93c2Vyc2xpc3RcIjoge1xuICAgICAgICBcInByb2R1Y3Rpb25cIjogW1xuICAgICAgICAgICAgXCI+IDElXCIsXG4gICAgICAgICAgICBcIm5vdCBkZWFkXCIsXG4gICAgICAgICAgICBcIm5vdCBvcF9taW5pIGFsbFwiXG4gICAgICAgIF0sXG4gICAgICAgIFwiZGV2ZWxvcG1lbnRcIjogW1xuICAgICAgICAgICAgXCJsYXN0IDEgY2hyb21lIHZlcnNpb25cIixcbiAgICAgICAgICAgIFwibGFzdCAxIGZpcmVmb3ggdmVyc2lvblwiLFxuICAgICAgICAgICAgXCJsYXN0IDEgc2FmYXJpIHZlcnNpb25cIlxuICAgICAgICBdXG4gICAgfSxcbiAgICBcImNvbmZpZ1wiOiB7XG4gICAgICAgIFwiY29tbWl0aXplblwiOiB7XG4gICAgICAgICAgICBcInBhdGhcIjogXCJub2RlX21vZHVsZXMvY3otZ2l0XCJcbiAgICAgICAgfVxuICAgIH1cbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7QUFBK1EsU0FBUyxjQUFjLGVBQXNDO0FBQzVVLFNBQVMsV0FBQUEsZ0JBQWU7OztBQ3FCakIsU0FBUyxXQUFXLFNBQThCO0FBQ3JELFFBQU0sTUFBVyxDQUFDO0FBRWxCLGFBQVcsV0FBVyxPQUFPLEtBQUssT0FBTyxHQUFHO0FBQ3hDLFFBQUksV0FBVyxRQUFRLE9BQU8sRUFBRSxRQUFRLFFBQVEsSUFBSTtBQUNwRCxlQUFXLGFBQWEsU0FBUyxPQUFPLGFBQWEsVUFBVSxRQUFRO0FBQ3ZFLFFBQUksWUFBWTtBQUFhLGlCQUFXLE9BQU8sUUFBUTtBQUN2RCxRQUFJLFlBQVksY0FBYztBQUMxQixVQUFJO0FBQ0EsbUJBQVcsS0FBSyxNQUFNLFFBQVE7QUFBQSxNQUNsQyxTQUFTLE9BQVA7QUFBQSxNQUFlO0FBQUEsSUFDckI7QUFDQSxRQUFJLE9BQU8sSUFBSTtBQUFBLEVBQ25CO0FBQ0EsU0FBTztBQUNYOzs7QUN6Qk8sU0FBUyxZQUFZLE9BQWtCLENBQUMsR0FBRztBQUM5QyxRQUFNLE1BQXVCLENBQUM7QUFDOUIsYUFBVyxDQUFDLFFBQVEsTUFBTSxLQUFLLE1BQU07QUFDakMsVUFBTSxVQUFVO0FBQ2hCLFVBQU0sVUFBVSxRQUFRLEtBQUssTUFBTTtBQUduQyxRQUFJLE1BQU0sSUFBSTtBQUFBLE1BQ1Y7QUFBQSxNQUNBLGNBQWM7QUFBQSxNQUNkLElBQUk7QUFBQSxNQUNKLFNBQVMsVUFBUSxLQUFLLFFBQVEsSUFBSSxPQUFPLElBQUksUUFBUSxHQUFHLEVBQUU7QUFBQTtBQUFBLE1BRTFELEdBQUksVUFBVSxFQUFFLFFBQVEsTUFBTSxJQUFJLENBQUM7QUFBQSxJQUN2QztBQUFBLEVBQ0o7QUFDQSxTQUFPO0FBQ1g7OztBQzdCMlIsU0FBUyxlQUFlO0FBRW5ULFNBQVMsZUFBZTtBQUN4QixTQUFTLGtCQUFrQjtBQUMzQixTQUFTLHdCQUF3QjtBQUNqQyxTQUFTLDRCQUE0QjtBQUNyQyxPQUFPLFNBQVM7QUFDaEIsT0FBTyxZQUFZO0FBQ25CLE9BQU8sa0JBQWtCO0FBQ3pCLE9BQU8scUJBQXFCO0FBQzVCLE9BQU8sb0JBQW9CO0FBRTNCLE9BQU8sZ0JBQWdCO0FBRXZCLE9BQU8sZ0JBQWdCO0FBRXZCLFNBQVMsMkJBQTJCO0FBRXBDLE9BQU8sV0FBVztBQUNsQixPQUFPLG1CQUFtQjtBQU1uQixJQUFNLG9CQUFvQixDQUFDLFlBQXdEO0FBQ3RGLFFBQU0sRUFBRSxxQkFBcUIsYUFBYSxTQUFTLElBQUk7QUFDdkQsU0FBTztBQUFBLElBQ0gsSUFBSTtBQUFBO0FBQUEsSUFFSixPQUFPO0FBQUE7QUFBQSxJQUVQLGFBQWE7QUFBQTtBQUFBLElBRWIsZUFBZSxDQUFDLENBQUM7QUFBQTtBQUFBLElBRWpCLGtCQUFrQixPQUFPO0FBQUE7QUFBQSxJQUV6QixpQkFBaUI7QUFBQSxNQUNiLFFBQVE7QUFBQSxRQUNKLE1BQU0sRUFBRSxPQUFPLG9CQUFvQjtBQUFBLE1BQ3ZDO0FBQUEsSUFDSixDQUFDO0FBQUE7QUFBQSxJQUVELHFCQUFxQjtBQUFBLE1BQ2pCLFVBQVUsQ0FBQyxRQUFRLFFBQVEsSUFBSSxHQUFHLGtCQUFrQixDQUFDO0FBQUEsTUFDckQsVUFBVTtBQUFBLElBQ2QsQ0FBQztBQUFBO0FBQUEsSUFFRCxXQUFXO0FBQUE7QUFBQSxNQUVQLFNBQVMsQ0FBQyxPQUFPLFlBQVk7QUFBQSxNQUM3QixLQUFLO0FBQUE7QUFBQSxNQUVMLFdBQVc7QUFBQSxRQUNQLG9CQUFvQixFQUFFLGFBQWEsT0FBTyxDQUFDO0FBQUEsUUFDM0MsY0FBYztBQUFBLFVBQ1YsUUFBUTtBQUFBLFFBQ1osQ0FBQztBQUFBLE1BQ0w7QUFBQSxJQUNKLENBQUM7QUFBQSxJQUNELFdBQVc7QUFBQTtBQUFBLE1BRVAsV0FBVztBQUFBLFFBQ1Asb0JBQW9CLEVBQUUsYUFBYSxPQUFPLENBQUM7QUFBQSxRQUMzQyxjQUFjO0FBQUEsVUFDVixvQkFBb0IsQ0FBQyxJQUFJO0FBQUEsUUFDN0IsQ0FBQztBQUFBLE1BQ0w7QUFBQTtBQUFBLE1BRUEsS0FBSztBQUFBLElBQ1QsQ0FBQztBQUFBLElBQ0QsTUFBTTtBQUFBLE1BQ0YsYUFBYTtBQUFBLElBQ2pCLENBQUM7QUFBQTtBQUFBLElBRUQsWUFBWSxjQUFjLE9BQU87QUFBQTtBQUFBLElBRWpDLGVBQWdCLFdBQVcsRUFBRSxVQUFVLGNBQWMsVUFBVSxNQUFNLFlBQVksS0FBSyxDQUFDO0FBQUEsRUFDM0Y7QUFDSjtBQU1BLElBQU0sb0JBQW9CLENBQUMsWUFBb0Q7QUFDM0UsUUFBTSxFQUFFLHNCQUFzQixRQUFRLHVDQUF1QyxJQUFJO0FBQ2pGLFFBQU0sZUFBZSxvQkFBb0IsTUFBTSxHQUFHO0FBQ2xELFFBQU0sVUFBMEIsQ0FBQztBQUNqQyxNQUFJLGFBQWEsU0FBUyxNQUFNLEdBQUc7QUFDL0IsWUFBUTtBQUFBLE1BQ0osZ0JBQWdCO0FBQUEsUUFDWixLQUFLO0FBQUEsUUFDTCxXQUFXO0FBQUEsUUFDWCxrQkFBa0I7QUFBQSxNQUN0QixDQUFDO0FBQUEsSUFDTDtBQUFBLEVBQ0o7QUFDQSxNQUFJLGFBQWEsU0FBUyxRQUFRLEdBQUc7QUFDakMsWUFBUTtBQUFBLE1BQ0osZ0JBQWdCO0FBQUEsUUFDWixLQUFLO0FBQUEsUUFDTCxXQUFXO0FBQUEsUUFDWCxrQkFBa0I7QUFBQSxNQUN0QixDQUFDO0FBQUEsSUFDTDtBQUFBLEVBQ0o7QUFDQSxTQUFPO0FBQ1g7QUFNQSxJQUFNLGdCQUFnQixDQUFDLFlBQW9EO0FBQ3ZFLFFBQU0sRUFBRSxvQkFBb0IsSUFBSTtBQUNoQyxTQUFPLFFBQVE7QUFBQSxJQUNYLGNBQWM7QUFBQSxJQUNkLFVBQVU7QUFBQSxNQUNOLE1BQU07QUFBQSxNQUNOLFlBQVk7QUFBQSxNQUNaLGFBQWE7QUFBQSxNQUNiLE9BQU87QUFBQSxRQUNIO0FBQUEsVUFDSSxLQUFLO0FBQUEsVUFDTCxPQUFPO0FBQUEsVUFDUCxNQUFNO0FBQUEsUUFDVjtBQUFBLFFBQ0E7QUFBQSxVQUNJLEtBQUs7QUFBQSxVQUNMLE9BQU87QUFBQSxVQUNQLE1BQU07QUFBQSxRQUNWO0FBQUEsUUFDQTtBQUFBLFVBQ0ksS0FBSztBQUFBLFVBQ0wsT0FBTztBQUFBLFVBQ1AsTUFBTTtBQUFBLFVBQ04sU0FBUztBQUFBLFFBQ2I7QUFBQSxNQUNKO0FBQUEsSUFDSjtBQUFBLEVBQ0osQ0FBQztBQUNMOzs7QUMvSUE7QUFBQSxFQUNJLE1BQVE7QUFBQSxFQUNSLFNBQVc7QUFBQSxFQUNYLFNBQVc7QUFBQSxFQUNYLE1BQVE7QUFBQSxFQUNSLFNBQVc7QUFBQSxJQUNQLEtBQU87QUFBQSxJQUNQLE9BQVM7QUFBQSxJQUNULGFBQWE7QUFBQSxJQUNiLGNBQWM7QUFBQSxJQUNkLGFBQWE7QUFBQSxJQUNiLGNBQWM7QUFBQSxJQUNkLFNBQVc7QUFBQSxJQUNYLGVBQWU7QUFBQSxJQUNmLGlCQUFpQjtBQUFBLElBQ2pCLGtCQUFrQjtBQUFBLElBQ2xCLG9CQUFvQjtBQUFBLElBQ3BCLFNBQVc7QUFBQSxJQUNYLFNBQVc7QUFBQSxJQUNYLFFBQVU7QUFBQSxFQUNkO0FBQUEsRUFDQSxjQUFnQjtBQUFBLElBQ1osMkJBQTJCO0FBQUEsSUFDM0IscUJBQXFCO0FBQUEsSUFDckIsZ0JBQWdCO0FBQUEsSUFDaEIsc0JBQXNCO0FBQUEsSUFDdEIsOEJBQThCO0FBQUEsSUFDOUIsbUJBQW1CO0FBQUEsSUFDbkIsT0FBUztBQUFBLElBQ1QsT0FBUztBQUFBLElBQ1QsU0FBVztBQUFBLElBQ1gsYUFBYTtBQUFBLElBQ2IsZ0JBQWdCO0FBQUEsSUFDaEIsY0FBYztBQUFBLElBQ2QsVUFBVTtBQUFBLElBQ1YsYUFBYTtBQUFBLElBQ2IsTUFBUTtBQUFBLElBQ1IsV0FBYTtBQUFBLElBQ2IsT0FBUztBQUFBLElBQ1QsK0JBQStCO0FBQUEsSUFDL0IsWUFBWTtBQUFBLElBQ1osSUFBTTtBQUFBLElBQ04sWUFBYztBQUFBLElBQ2QsS0FBTztBQUFBLElBQ1AsY0FBYztBQUFBLElBQ2QsY0FBZ0I7QUFBQSxJQUNoQixhQUFhO0FBQUEsSUFDYixZQUFZO0FBQUEsSUFDWixNQUFRO0FBQUEsRUFDWjtBQUFBLEVBQ0EsaUJBQW1CO0FBQUEsSUFDZixtQkFBbUI7QUFBQSxJQUNuQixtQ0FBbUM7QUFBQSxJQUNuQyxvQkFBb0I7QUFBQSxJQUNwQixxQkFBcUI7QUFBQSxJQUNyQixpQkFBaUI7QUFBQSxJQUNqQixvQkFBb0I7QUFBQSxJQUNwQixhQUFhO0FBQUEsSUFDYixxQkFBcUI7QUFBQSxJQUNyQixvQ0FBb0M7QUFBQSxJQUNwQyw2QkFBNkI7QUFBQSxJQUM3QixzQkFBc0I7QUFBQSxJQUN0QiwwQkFBMEI7QUFBQSxJQUMxQixjQUFnQjtBQUFBLElBQ2hCLFVBQVU7QUFBQSxJQUNWLEtBQU87QUFBQSxJQUNQLFFBQVU7QUFBQSxJQUNWLDBCQUEwQjtBQUFBLElBQzFCLDBCQUEwQjtBQUFBLElBQzFCLHFCQUFxQjtBQUFBLElBQ3JCLE9BQVM7QUFBQSxJQUNULGVBQWU7QUFBQSxJQUNmLFNBQVc7QUFBQSxJQUNYLGdCQUFnQjtBQUFBLElBQ2hCLFVBQVk7QUFBQSxJQUNaLDRCQUE0QjtBQUFBLElBQzVCLE1BQVE7QUFBQSxJQUNSLG9CQUFvQjtBQUFBLElBQ3BCLFdBQWE7QUFBQSxJQUNiLHlCQUF5QjtBQUFBLElBQ3pCLGlDQUFpQztBQUFBLElBQ2pDLHFDQUFxQztBQUFBLElBQ3JDLG9DQUFvQztBQUFBLElBQ3BDLDZCQUE2QjtBQUFBLElBQzdCLGtDQUFrQztBQUFBLElBQ2xDLFlBQWM7QUFBQSxJQUNkLHdCQUF3QjtBQUFBLElBQ3hCLGtCQUFrQjtBQUFBLElBQ2xCLDJCQUEyQjtBQUFBLElBQzNCLGtDQUFrQztBQUFBLElBQ2xDLE1BQVE7QUFBQSxJQUNSLDJCQUEyQjtBQUFBLElBQzNCLHNCQUFzQjtBQUFBLElBQ3RCLG9CQUFvQjtBQUFBLElBQ3BCLG1CQUFtQjtBQUFBLElBQ25CLHlCQUF5QjtBQUFBLElBQ3pCLFdBQVc7QUFBQSxFQUNmO0FBQUEsRUFDQSxTQUFXO0FBQUEsSUFDUCxNQUFRO0FBQUEsRUFDWjtBQUFBLEVBQ0EsY0FBZ0I7QUFBQSxJQUNaLFlBQWM7QUFBQSxNQUNWO0FBQUEsTUFDQTtBQUFBLE1BQ0E7QUFBQSxJQUNKO0FBQUEsSUFDQSxhQUFlO0FBQUEsTUFDWDtBQUFBLE1BQ0E7QUFBQSxNQUNBO0FBQUEsSUFDSjtBQUFBLEVBQ0o7QUFBQSxFQUNBLFFBQVU7QUFBQSxJQUNOLFlBQWM7QUFBQSxNQUNWLE1BQVE7QUFBQSxJQUNaO0FBQUEsRUFDSjtBQUNKOzs7QUovR0EsT0FBTyxXQUFXO0FBUGxCLElBQU0sbUNBQW1DO0FBU3pDLElBQU0sRUFBRSxjQUFjLGlCQUFpQixNQUFNLFFBQVEsSUFBSTtBQUN6RCxJQUFNLGVBQWU7QUFBQSxFQUNqQixLQUFLLEVBQUUsY0FBYyxpQkFBaUIsTUFBTSxRQUFRO0FBQUEsRUFDcEQsZUFBZSxNQUFNLEVBQUUsT0FBTyxxQkFBcUI7QUFDdkQ7QUFHQSxJQUFPLHNCQUFRLGFBQWEsQ0FBQyxFQUFFLEtBQUssTUFBNkI7QUFDN0QsUUFBTSxPQUFPLFFBQVEsSUFBSTtBQUN6QixRQUFNLE1BQU0sUUFBUSxNQUFNLElBQUk7QUFDOUIsUUFBTSxVQUFVLFdBQVcsR0FBRztBQUU5QixTQUFPO0FBQUEsSUFDSCxNQUFNLFFBQVE7QUFBQSxJQUNkO0FBQUEsSUFDQSxTQUFTO0FBQUEsTUFDTCxPQUFPO0FBQUEsUUFDSCxLQUFLQyxTQUFRLGtDQUFXLE9BQU87QUFBQSxNQUNuQztBQUFBLElBQ0o7QUFBQSxJQUNBLFFBQVE7QUFBQSxNQUNKLGNBQWMsS0FBSyxVQUFVLFlBQVk7QUFBQSxJQUM3QztBQUFBLElBQ0EsS0FBSztBQUFBLE1BQ0QscUJBQXFCO0FBQUEsUUFDakIsTUFBTTtBQUFBLFVBQ0YsZ0JBQWdCO0FBQUEsUUFDcEI7QUFBQSxNQUNKO0FBQUEsSUFDSjtBQUFBLElBQ0EsUUFBUTtBQUFBLE1BQ0osTUFBTTtBQUFBLE1BQ04sTUFBTSxRQUFRO0FBQUEsTUFDZCxNQUFNLFFBQVE7QUFBQSxNQUNkLE1BQU07QUFBQTtBQUFBLE1BRU4sT0FBTyxZQUFZLFFBQVEsVUFBVTtBQUFBLElBQ3pDO0FBQUEsSUFDQSxTQUFTLGtCQUFrQixPQUFPO0FBQUEsSUFDbEMsU0FBUztBQUFBLE1BQ0wsTUFBTSxRQUFRLG9CQUFvQixDQUFDLGVBQWUsVUFBVSxJQUFJLENBQUM7QUFBQSxJQUNyRTtBQUFBLElBQ0EsT0FBTztBQUFBLE1BQ0gsUUFBUTtBQUFBLE1BQ1IsUUFBUTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLE1BVVIsc0JBQXNCO0FBQUE7QUFBQSxNQUV0Qix1QkFBdUI7QUFBQSxNQUN2QixlQUFlO0FBQUEsUUFDWCxRQUFRO0FBQUE7QUFBQSxVQUVKLGdCQUFnQjtBQUFBLFVBQ2hCLGdCQUFnQjtBQUFBLFVBQ2hCLGdCQUFnQjtBQUFBLFFBQ3BCO0FBQUEsTUFDSjtBQUFBLElBQ0o7QUFBQSxFQUNKO0FBQ0osQ0FBQzsiLAogICJuYW1lcyI6IFsicmVzb2x2ZSIsICJyZXNvbHZlIl0KfQo=