diff --git a/locales/en.yaml b/locales/en.yaml index e3915040f..f3773afaa 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -79,4 +79,5 @@ menus: hsDebounce: Debounce & Throttle hsFormDesign: Form Design hsBarcode: Barcode - hsQarcode: Qarcode + hsQrcode: Qrcode + hsCascader: Cascader diff --git a/locales/zh-CN.yaml b/locales/zh-CN.yaml index 8748e8cfb..a7c3dab82 100644 --- a/locales/zh-CN.yaml +++ b/locales/zh-CN.yaml @@ -79,4 +79,5 @@ menus: hsDebounce: 防抖节流 hsFormDesign: 表单设计器 hsBarcode: 条形码 - hsQarcode: 二维码 + hsQrcode: 二维码 + hsCascader: 级联选择器 diff --git a/package.json b/package.json index 8f60dde38..3aed50d58 100644 --- a/package.json +++ b/package.json @@ -39,12 +39,13 @@ "@wangeditor/editor-for-vue": "^5.1.10", "animate.css": "^4.1.1", "axios": "^0.26.1", + "china-area-data": "^5.0.1", "cropperjs": "^1.5.12", "css-color-function": "^1.3.3", "dayjs": "^1.11.0", "driver.js": "^0.9.8", "echarts": "^5.3.2", - "element-plus": "^2.1.10", + "element-plus": "^2.1.11", "element-resize-detector": "^1.2.3", "js-cookie": "^3.0.1", "jsbarcode": "^3.11.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 71871fb0c..14c401a79 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,13 +43,14 @@ specifiers: animate.css: ^4.1.1 autoprefixer: ^10.4.5 axios: ^0.26.1 + china-area-data: ^5.0.1 cropperjs: ^1.5.12 cross-env: 7.0.3 css-color-function: ^1.3.3 dayjs: ^1.11.0 driver.js: ^0.9.8 echarts: ^5.3.2 - element-plus: ^2.1.10 + element-plus: ^2.1.11 element-resize-detector: ^1.2.3 eslint: ^8.8.0 eslint-plugin-prettier: ^4.0.0 @@ -122,12 +123,13 @@ dependencies: "@wangeditor/editor-for-vue": 5.1.10_9016b5918024e821ee2af40b62ae7476 animate.css: 4.1.1 axios: 0.26.1 + china-area-data: 5.0.1 cropperjs: 1.5.12 css-color-function: 1.3.3 dayjs: 1.11.0 driver.js: 0.9.8 echarts: 5.3.2 - element-plus: 2.1.10_vue@3.2.33 + element-plus: 2.1.11_vue@3.2.33 element-resize-detector: 1.2.4 js-cookie: 3.0.1 jsbarcode: 3.11.5 @@ -942,20 +944,20 @@ packages: - supports-color dev: true - /@floating-ui/core/0.6.1: + /@floating-ui/core/0.6.2: resolution: { - integrity: sha512-Y30eVMcZva8o84c0HcXAtDO4BEzPJMvF6+B7x7urL2xbAqVsGJhojOyHLaoQHQYjb6OkqRq5kO+zeySycQwKqg== + integrity: sha512-jktYRmZwmau63adUG3GKOAVCofBXkk55S/zQ94XOorAHhwqFIOFAy1rSp2N0Wp6/tGbe9V3u/ExlGZypyY17rg== } dev: false - /@floating-ui/dom/0.4.4: + /@floating-ui/dom/0.4.5: resolution: { - integrity: sha512-0Ulu3B/dqQplUUSqnTx0foSrlYuMN+GTtlJWvNJwt6Fr7/PqmlR/Y08o6/+bxDWr6p3roBJRaQ51MDZsNmEhhw== + integrity: sha512-b+prvQgJt8pieaKYMSJBXHxX/DYwdLsAWxKYqnO5dO2V4oo/TYBZJAUQCVNjTWWsrs6o4VDrNcP9+E70HAhJdw== } dependencies: - "@floating-ui/core": 0.6.1 + "@floating-ui/core": 0.6.2 dev: false /@humanwhocodes/config-array/0.9.5: @@ -1278,13 +1280,6 @@ packages: fastq: 1.13.0 dev: true - /@popperjs/core/2.11.5: - resolution: - { - integrity: sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw== - } - dev: false - /@pureadmin/components/1.0.6_vue@3.2.33: resolution: { @@ -1363,6 +1358,13 @@ packages: nanopop: 2.1.0 dev: false + /@sxzz/popperjs-es/2.11.7: + resolution: + { + integrity: sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ== + } + dev: false + /@transloadit/prettier-bytes/0.0.7: resolution: { @@ -1427,10 +1429,10 @@ packages: integrity: sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g== } - /@types/lodash/4.14.181: + /@types/lodash/4.14.182: resolution: { - integrity: sha512-n3tyKthHJbkiWhDZs3DkhkCzt2MexYHXlX0td5iMplyfwketaOeKboEVBqzceH7juqvEg3q5oUoBFxSLu7zFag== + integrity: sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== } dev: false @@ -2835,6 +2837,13 @@ packages: supports-color: 7.2.0 dev: true + /china-area-data/5.0.1: + resolution: + { + integrity: sha512-BQDPpiv5Nn+018ekcJK2oSD9PAD+E1bvXB0wgabc//dFVS/KvRqCgg0QOEUt3vBkx9XzB5a9BmkJCEZDBxVjVw== + } + dev: false + /chokidar/3.5.3: resolution: { @@ -3370,6 +3379,13 @@ packages: } dev: false + /dayjs/1.11.1: + resolution: + { + integrity: sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA== + } + dev: false + /debug/2.6.9: resolution: { @@ -3587,23 +3603,23 @@ packages: } dev: true - /element-plus/2.1.10_vue@3.2.33: + /element-plus/2.1.11_vue@3.2.33: resolution: { - integrity: sha512-sS9OMgP20dlYipmzHlEEgCJU+ID7+03YpRpoJWNQEH736C6ArmDMLnGFe8DUjPvwbUEXRA2d0Eo5d0apFgkSqg== + integrity: sha512-s4X0I8s787tv+9UdekBC1g7v42Fj4bucPAmu03EjbgrGrV7BJvkoBGuK52lNfu4yC76bl6Uyjesd5Fu8CMakSw== } peerDependencies: vue: ^3.2.0 dependencies: "@ctrl/tinycolor": 3.4.1 "@element-plus/icons-vue": 1.1.4_vue@3.2.33 - "@floating-ui/dom": 0.4.4 - "@popperjs/core": 2.11.5 - "@types/lodash": 4.14.181 + "@floating-ui/dom": 0.4.5 + "@popperjs/core": /@sxzz/popperjs-es/2.11.7 + "@types/lodash": 4.14.182 "@types/lodash-es": 4.17.6 "@vueuse/core": 8.3.1_vue@3.2.33 async-validator: 4.0.7 - dayjs: 1.11.0 + dayjs: 1.11.1 escape-html: 1.0.3 lodash: 4.17.21 lodash-es: 4.17.21 @@ -8039,7 +8055,7 @@ packages: ace-builds: 1.4.14 ant-design-vue: 3.2.0_vue@3.2.33 core-js: 3.22.0 - element-plus: 2.1.10_vue@3.2.33 + element-plus: 2.1.11_vue@3.2.33 lodash: 4.17.21 uuid: 8.3.2 vue: 3.2.33 diff --git a/src/components/ReQrcode/src/index.tsx b/src/components/ReQrcode/src/index.tsx index 3c9edb401..6354f43f8 100644 --- a/src/components/ReQrcode/src/index.tsx +++ b/src/components/ReQrcode/src/index.tsx @@ -53,7 +53,7 @@ const props = { }; export default defineComponent({ - name: "epTableProBar", + name: "ReQrcode", props, emits: ["done", "click", "disabled-click"], setup(props, { emit }) { diff --git a/src/router/modules/able.ts b/src/router/modules/able.ts index 8c73ee1ad..7996dc95e 100644 --- a/src/router/modules/able.ts +++ b/src/router/modules/able.ts @@ -113,10 +113,19 @@ const ableRouter = { }, { path: "/able/qrcode", - name: "reQarcode", + name: "reQrcode", component: () => import("/@/views/able/qrcode.vue"), meta: { - title: $t("menus.hsQarcode"), + title: $t("menus.hsQrcode"), + i18n: true + } + }, + { + path: "/able/cascader", + name: "reCascader", + component: () => import("/@/views/able/cascader.vue"), + meta: { + title: $t("menus.hsCascader"), i18n: true } } diff --git a/src/style/sidebar.scss b/src/style/sidebar.scss index a352bad7c..be38e58a6 100644 --- a/src/style/sidebar.scss +++ b/src/style/sidebar.scss @@ -30,6 +30,11 @@ margin-left: $sideBarWidth; position: relative; background: #f0f2f5; + + .el-scrollbar__wrap { + overflow: auto; + height: 100%; + } } .fixed-header { @@ -483,11 +488,6 @@ } } - .el-scrollbar__wrap { - overflow: auto; - height: 100%; - } - .el-menu--collapse .el-menu .el-sub-menu { min-width: $sideBarWidth !important; } diff --git a/src/utils/chinaArea.ts b/src/utils/chinaArea.ts new file mode 100644 index 000000000..6dffb7d61 --- /dev/null +++ b/src/utils/chinaArea.ts @@ -0,0 +1,190 @@ +import REGION_DATA from "china-area-data"; +import { cloneDeep } from "lodash-unified"; + +interface ProvinceData { + value: string; + label: string; + children?: Array; +} + +// code转汉字大对象,例:CodeToText['110000']输出北京市 +const CodeToText = {}; +// 汉字转code大对象,例:TextToCode['北京市']['市辖区']['朝阳区'].code输出110105 +const TextToCode = {}; +// 省份对象 +const provinceObject = REGION_DATA["86"]; +// 省市区三级联动数据(不带“全部”选项) +const regionData = []; +// 省市二级联动数据(不带“全部”选项) +let provinceAndCityData = []; + +const ALL_TEXT = "全部"; + +CodeToText[""] = ALL_TEXT; + +// 计算省 +Object.keys(provinceObject).forEach(prop => { + const provinceText = provinceObject[prop]; + regionData.push({ + value: prop, // 省份code值 + label: provinceText // 省份汉字 + }); + CodeToText[prop] = provinceText; + TextToCode[provinceText] = { + code: prop + }; + TextToCode[provinceText][ALL_TEXT] = { + code: "" + }; +}); + +// 计算市 +regionData.forEach((item: ProvinceData) => { + const provinceCode = item.value; + const provinceText = item.label; + const provinceChildren = []; + const provinceData = REGION_DATA[provinceCode] ?? {}; + + Object.keys(provinceData).forEach(prop => { + provinceChildren.push({ + value: prop, + label: provinceData[prop] + }); + CodeToText[prop] = provinceData[prop]; + TextToCode[provinceText][provinceData[prop]] = { + code: prop + }; + TextToCode[provinceText][provinceData[prop]][ALL_TEXT] = { + code: "" + }; + }); + + if (provinceChildren.length) { + item.children = provinceChildren; + } +}); +provinceAndCityData = cloneDeep(regionData); + +// 计算区 +regionData.forEach((item: ProvinceData) => { + const province = item.children; + const provinceText = item.label; + + if (province) { + province.forEach(pItem => { + const cityCode = pItem.value; + const cityText = pItem.label; + const cityChildren = []; + const cityData = REGION_DATA[cityCode] ?? {}; + + Object.keys(cityData).forEach(prop => { + cityChildren.push({ + value: prop, + label: cityData[prop] + }); + CodeToText[prop] = cityData[prop]; + TextToCode[provinceText][cityText][cityData[prop]] = { + code: prop + }; + }); + + if (cityChildren.length) { + pItem.children = cityChildren; + } + }); + } +}); + +// 添加“全部”选项 +const provinceAndCityDataPlus = cloneDeep(provinceAndCityData); +provinceAndCityDataPlus.unshift({ + value: "", + label: ALL_TEXT +}); +provinceAndCityDataPlus.forEach((item: ProvinceData) => { + const province = item.children; + + if (province?.length) { + province.unshift({ + value: "", + label: ALL_TEXT + }); + + province.forEach(pItem => { + const city = pItem.children; + + if (city?.length) { + city.unshift({ + value: "", + label: ALL_TEXT + }); + } + }); + } +}); + +const regionDataPlus = cloneDeep(regionData); +regionDataPlus.unshift({ + value: "", + label: ALL_TEXT +}); +regionDataPlus.forEach((item: ProvinceData) => { + const province = item.children; + + if (province?.length) { + province.unshift({ + value: "", + label: ALL_TEXT + }); + province.forEach(pItem => { + const city = pItem.children; + + if (city?.length) { + city.unshift({ + value: "", + label: ALL_TEXT + }); + } + }); + } +}); + +/** + * 汉字转区域码 + * @param provinceText 省 + * @param cityText 市 + * @param regionText 区 + * @returns + */ +function convertTextToCode( + provinceText: string, + cityText: string, + regionText?: string +): string { + let code = ""; + if (provinceText && TextToCode[provinceText]) { + const province = TextToCode[provinceText]; + code = province.code; + + if (cityText && province[cityText]) { + const city = province[cityText]; + code = `${code}${cityText === ALL_TEXT ? "" : ", "}${city.code}`; + + if (regionText && city[regionText]) { + code = `${code}${regionText === ALL_TEXT ? "" : ", "}${ + city[regionText].code + }`; + } + } + } + return code; +} +export { + provinceAndCityData, + regionData, + provinceAndCityDataPlus, + regionDataPlus, + CodeToText, + TextToCode, + convertTextToCode +}; diff --git a/src/views/able/cascader.vue b/src/views/able/cascader.vue new file mode 100644 index 000000000..74748195c --- /dev/null +++ b/src/views/able/cascader.vue @@ -0,0 +1,148 @@ + + + + + diff --git a/src/views/list/card/components/DialogForm.vue b/src/views/list/card/components/DialogForm.vue index b4d515a4c..8f1f925fb 100644 --- a/src/views/list/card/components/DialogForm.vue +++ b/src/views/list/card/components/DialogForm.vue @@ -116,7 +116,6 @@ const rules = {