From 2515caed35a015bdf1636c275f81e68d5d7f0ea4 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 22 Jan 2026 00:51:48 +0800 Subject: [PATCH 01/13] =?UTF-8?q?feat(iot):=E3=80=90=E7=BD=91=E5=85=B3?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=EF=BC=9A20%=E3=80=91=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=BD=91=E5=85=B3=E8=AE=BE=E5=A4=87=E7=BB=91=E5=AE=9A=E8=83=BD?= =?UTF-8?q?=E5=8A=9B=EF=BC=88=E6=9C=AA=E5=AE=8C=E6=88=90=EF=BC=89=EF=BC=8C?= =?UTF-8?q?=E5=9F=BA=E4=BA=8E=20breezy-doodling-starlight.md=20=E8=A7=84?= =?UTF-8?q?=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/iot/device/device/index.ts | 26 +++ .../device/detail/DeviceDetailsSubDevice.vue | 210 ++++++++++++++++++ src/views/iot/device/device/detail/index.vue | 9 +- 3 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue diff --git a/src/api/iot/device/device/index.ts b/src/api/iot/device/device/index.ts index 1804628c5..be5193c6d 100644 --- a/src/api/iot/device/device/index.ts +++ b/src/api/iot/device/device/index.ts @@ -158,5 +158,31 @@ export const DeviceApi = { // 发送设备消息 sendDeviceMessage: async (params: IotDeviceMessageSendReqVO) => { return await request.post({ url: `/iot/device/message/send`, data: params }) + }, + + // 绑定子设备到网关 + bindDeviceGateway: async (data: { ids: number[]; gatewayId: number }) => { + return await request.put({ url: `/iot/device/bind-gateway`, data }) + }, + + // 解绑子设备与网关 + unbindDeviceGateway: async (data: { ids: number[] }) => { + return await request.put({ url: `/iot/device/unbind-gateway`, data }) + }, + + // 获取网关的子设备列表 + getSubDeviceList: async (gatewayId: number) => { + return await request.get({ + url: `/iot/device/sub-device-list`, + params: { gatewayId } + }) + }, + + // 获取可绑定到网关的子设备列表 + getBindableSubDeviceList: async (gatewayId?: number) => { + return await request.get({ + url: `/iot/device/bindable-sub-device-list`, + params: { gatewayId } + }) } } diff --git a/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue b/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue new file mode 100644 index 000000000..16a406c4f --- /dev/null +++ b/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue @@ -0,0 +1,210 @@ + + + + diff --git a/src/views/iot/device/device/detail/index.vue b/src/views/iot/device/device/detail/index.vue index 3ec756b5c..f8949ecd5 100644 --- a/src/views/iot/device/device/detail/index.vue +++ b/src/views/iot/device/device/detail/index.vue @@ -17,7 +17,13 @@ :thing-model-list="thingModelList" /> - + + + @@ -50,6 +56,7 @@ import DeviceDetailsThingModel from './DeviceDetailsThingModel.vue' import DeviceDetailsMessage from './DeviceDetailsMessage.vue' import DeviceDetailsSimulator from './DeviceDetailsSimulator.vue' import DeviceDetailConfig from './DeviceDetailConfig.vue' +import DeviceDetailsSubDevice from './DeviceDetailsSubDevice.vue' defineOptions({ name: 'IoTDeviceDetail' }) From 2076a27a262b9af9985e97c307c1679a9eb6a6e7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 22 Jan 2026 09:53:01 +0800 Subject: [PATCH 02/13] =?UTF-8?q?feat(iot):=E3=80=90=E7=BD=91=E5=85=B3?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=EF=BC=9A30%=E3=80=91=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=BD=91=E5=85=B3=E8=AE=BE=E5=A4=87=E7=BB=91=E5=AE=9A=E8=83=BD?= =?UTF-8?q?=E5=8A=9B=EF=BC=88=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E5=9F=BA=E4=BA=8E=20optimized-pondering-dragon.md=20?= =?UTF-8?q?=E8=A7=84=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/iot/device/device/index.ts | 9 +- src/api/iot/product/product/index.ts | 4 +- .../device/detail/DeviceDetailsSubDevice.vue | 136 ++++++++++++------ 3 files changed, 100 insertions(+), 49 deletions(-) diff --git a/src/api/iot/device/device/index.ts b/src/api/iot/device/device/index.ts index be5193c6d..d41429e0b 100644 --- a/src/api/iot/device/device/index.ts +++ b/src/api/iot/device/device/index.ts @@ -178,11 +178,8 @@ export const DeviceApi = { }) }, - // 获取可绑定到网关的子设备列表 - getBindableSubDeviceList: async (gatewayId?: number) => { - return await request.get({ - url: `/iot/device/bindable-sub-device-list`, - params: { gatewayId } - }) + // 获取未绑定网关的子设备分页 + getUnboundSubDevicePage: async (params: any) => { + return await request.get({ url: `/iot/device/unbound-sub-device-page`, params }) } } diff --git a/src/api/iot/product/product/index.ts b/src/api/iot/product/product/index.ts index a34efaeb9..d491d3b28 100644 --- a/src/api/iot/product/product/index.ts +++ b/src/api/iot/product/product/index.ts @@ -68,8 +68,8 @@ export const ProductApi = { }, // 查询产品(精简)列表 - getSimpleProductList() { - return request.get({ url: '/iot/product/simple-list' }) + getSimpleProductList(deviceType?: number) { + return request.get({ url: '/iot/product/simple-list', params: { deviceType } }) }, // 根据 ProductKey 获取产品信息 diff --git a/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue b/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue index 16a406c4f..d24ad2995 100644 --- a/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue +++ b/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue @@ -62,40 +62,82 @@ - - - - - - - - - - - + + + + + + + + + + + + + 搜索 + + + 重置 + + + + + + + + + + + + + + + + + + + + + From 69d8224305b9eb17274acf5b64fdb7362833eb73 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 22 Jan 2026 09:55:00 +0800 Subject: [PATCH 03/13] =?UTF-8?q?feat(iot):=E3=80=90=E7=BD=91=E5=85=B3?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=EF=BC=9A30%=E3=80=91=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=BD=91=E5=85=B3=E8=AE=BE=E5=A4=87=E7=BB=91=E5=AE=9A=E8=83=BD?= =?UTF-8?q?=E5=8A=9B=EF=BC=88=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E5=9F=BA=E4=BA=8E=20optimized-pondering-dragon.md=20?= =?UTF-8?q?=E8=A7=84=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/components/ProductSelect.vue | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/views/iot/product/product/components/ProductSelect.vue diff --git a/src/views/iot/product/product/components/ProductSelect.vue b/src/views/iot/product/product/components/ProductSelect.vue new file mode 100644 index 000000000..fa288fa18 --- /dev/null +++ b/src/views/iot/product/product/components/ProductSelect.vue @@ -0,0 +1,65 @@ + + + + From dae0437ccd13a8a105bce8228ed44f58acaa3da4 Mon Sep 17 00:00:00 2001 From: LIUCX Date: Fri, 23 Jan 2026 11:06:34 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E7=99=BB=E9=99=86?= =?UTF-8?q?=E8=BF=87=E6=9C=9F=E5=90=8E=E5=8A=A0=E5=AF=86=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=BA=8C=E6=AC=A1=E5=8A=A0=E5=AF=86=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/axios/service.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config/axios/service.ts b/src/config/axios/service.ts index 9214bf8ea..dfaea75d6 100644 --- a/src/config/axios/service.ts +++ b/src/config/axios/service.ts @@ -85,7 +85,7 @@ service.interceptors.request.use( } } // 是否 API 加密 - if ((config!.headers || {}).isEncrypt) { + if ((config!.headers || {}).isEncrypt && !(config!.headers || {}).isEncrypted) { try { // 加密请求数据 if (config.data) { @@ -169,6 +169,9 @@ service.interceptors.response.use( cb() }) requestList = [] + if ((config!.headers || {}).isEncrypt){ + (config!.headers || {}).isEncrypted = true + } return service(config) } catch (e) { // 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。 From 2a0ce1fb66d1e47e15ccb3b0fb72b31d0929a88f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 25 Jan 2026 16:58:05 +0800 Subject: [PATCH 05/13] =?UTF-8?q?feat(iot):=E3=80=90=E7=BD=91=E5=85=B3?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=EF=BC=9A80%=E3=80=91=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E7=9A=84=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=EF=BC=88=E5=B7=B2=E6=B5=8B=E8=AF=95=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/iot/device/device/index.ts | 5 +- src/api/iot/product/product/index.ts | 2 + src/views/iot/device/device/DeviceForm.vue | 19 ------- .../device/detail/DeviceDetailsSubDevice.vue | 6 +-- src/views/iot/product/product/ProductForm.vue | 20 ++++++- .../product/detail/ProductDetailsInfo.vue | 35 ++++++++++++ src/views/iot/utils/constants.ts | 53 ++++++++++++++++++- 7 files changed, 112 insertions(+), 28 deletions(-) diff --git a/src/api/iot/device/device/index.ts b/src/api/iot/device/device/index.ts index d41429e0b..cf9f6d62d 100644 --- a/src/api/iot/device/device/index.ts +++ b/src/api/iot/device/device/index.ts @@ -21,7 +21,6 @@ export interface DeviceVO { mqttClientId: string // MQTT 客户端 ID mqttUsername: string // MQTT 用户名 mqttPassword: string // MQTT 密码 - authType: string // 认证类型 latitude?: number // 设备位置的纬度 longitude?: number // 设备位置的经度 areaId: number // 地区编码 @@ -161,12 +160,12 @@ export const DeviceApi = { }, // 绑定子设备到网关 - bindDeviceGateway: async (data: { ids: number[]; gatewayId: number }) => { + bindDeviceGateway: async (data: { subIds: number[]; gatewayId: number }) => { return await request.put({ url: `/iot/device/bind-gateway`, data }) }, // 解绑子设备与网关 - unbindDeviceGateway: async (data: { ids: number[] }) => { + unbindDeviceGateway: async (data: { subIds: number[]; gatewayId: number }) => { return await request.put({ url: `/iot/device/unbind-gateway`, data }) }, diff --git a/src/api/iot/product/product/index.ts b/src/api/iot/product/product/index.ts index d491d3b28..ba465efdc 100644 --- a/src/api/iot/product/product/index.ts +++ b/src/api/iot/product/product/index.ts @@ -5,6 +5,8 @@ export interface ProductVO { id: number // 产品编号 name: string // 产品名称 productKey: string // 产品标识 + productSecret?: string // 产品密钥 + registerEnabled?: boolean // 动态注册 protocolId: number // 协议编号 categoryId: number // 产品所属品类标识符 categoryName?: string // 产品所属品类名称 diff --git a/src/views/iot/device/device/DeviceForm.vue b/src/views/iot/device/device/DeviceForm.vue index 0ddbf2afb..fe75eed53 100644 --- a/src/views/iot/device/device/DeviceForm.vue +++ b/src/views/iot/device/device/DeviceForm.vue @@ -30,20 +30,6 @@ :disabled="formType === 'update'" /> - - - - - @@ -114,7 +100,6 @@ const formData = ref({ deviceName: undefined, nickname: undefined, picUrl: undefined, - gatewayId: undefined, deviceType: undefined as number | undefined, serialNumber: undefined, longitude: undefined as number | string | undefined, @@ -222,7 +207,6 @@ const formRules = reactive({ }) const formRef = ref() // 表单 Ref const products = ref([]) // 产品列表 -const gatewayDevices = ref([]) // 网关设备列表 const deviceGroups = ref([]) /** 打开弹窗 */ @@ -242,8 +226,6 @@ const open = async (type: string, id?: number) => { } } - // 加载网关设备列表 - gatewayDevices.value = await DeviceApi.getSimpleDeviceList(DeviceTypeEnum.GATEWAY) // 加载产品列表 products.value = await ProductApi.getSimpleProductList() // 加载设备分组列表 @@ -283,7 +265,6 @@ const resetForm = () => { deviceName: undefined, nickname: undefined, picUrl: undefined, - gatewayId: undefined, deviceType: undefined, serialNumber: undefined, longitude: undefined, diff --git a/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue b/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue index d24ad2995..290cd5cca 100644 --- a/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue +++ b/src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue @@ -225,7 +225,7 @@ const handleBindSubmit = async () => { bindFormLoading.value = true try { await DeviceApi.bindDeviceGateway({ - ids: bindSelectedIds.value, + subIds: bindSelectedIds.value, gatewayId: props.gatewayId }) message.success('绑定成功') @@ -240,7 +240,7 @@ const handleBindSubmit = async () => { const handleUnbind = async (id: number) => { try { await message.confirm('确定要解绑该子设备吗?') - await DeviceApi.unbindDeviceGateway({ ids: [id] }) + await DeviceApi.unbindDeviceGateway({ subIds: [id], gatewayId: props.gatewayId }) message.success('解绑成功') await getSubDeviceList() } catch {} @@ -250,7 +250,7 @@ const handleUnbind = async (id: number) => { const handleUnbindBatch = async () => { try { await message.confirm(`确定要解绑选中的 ${selectedIds.value.length} 个子设备吗?`) - await DeviceApi.unbindDeviceGateway({ ids: selectedIds.value }) + await DeviceApi.unbindDeviceGateway({ subIds: selectedIds.value, gatewayId: props.gatewayId }) message.success('批量解绑成功') selectedIds.value = [] await getSubDeviceList() diff --git a/src/views/iot/product/product/ProductForm.vue b/src/views/iot/product/product/ProductForm.vue index 32a7b2221..9cb7c5099 100644 --- a/src/views/iot/product/product/ProductForm.vue +++ b/src/views/iot/product/product/ProductForm.vue @@ -75,6 +75,20 @@ + + + + @@ -120,7 +134,8 @@ const formData = ref({ description: undefined, deviceType: undefined, netType: undefined, - codecType: CodecTypeEnum.ALINK + codecType: CodecTypeEnum.ALINK, + registerEnabled: false }) const formRules = reactive({ productKey: [{ required: true, message: 'ProductKey 不能为空', trigger: 'blur' }], @@ -194,7 +209,8 @@ const resetForm = () => { description: undefined, deviceType: undefined, netType: undefined, - codecType: CodecTypeEnum.ALINK + codecType: CodecTypeEnum.ALINK, + registerEnabled: false } formRef.value?.resetFields() } diff --git a/src/views/iot/product/product/detail/ProductDetailsInfo.vue b/src/views/iot/product/product/detail/ProductDetailsInfo.vue index feb7eb5dc..38c523b6e 100644 --- a/src/views/iot/product/product/detail/ProductDetailsInfo.vue +++ b/src/views/iot/product/product/detail/ProductDetailsInfo.vue @@ -21,6 +21,28 @@ > + + + {{ product.registerEnabled ? '已开启' : '已关闭' }} + + + +
+ {{ secretVisible ? product.productSecret : '******' }} + + + + + + +
+
{{ product.description }} @@ -29,6 +51,19 @@ import { DICT_TYPE } from '@/utils/dict' import { DeviceTypeEnum, ProductVO } from '@/api/iot/product/product' import { formatDate } from '@/utils/formatTime' +import { useClipboard } from '@vueuse/core' const { product } = defineProps<{ product: ProductVO }>() + +const message = useMessage() +const secretVisible = ref(false) +const { copy } = useClipboard() + +/** 复制产品密钥 */ +const copySecret = async () => { + if (product.productSecret) { + await copy(product.productSecret) + message.success('复制成功') + } +} diff --git a/src/views/iot/utils/constants.ts b/src/views/iot/utils/constants.ts index f25bb7de5..8b9c6722a 100644 --- a/src/views/iot/utils/constants.ts +++ b/src/views/iot/utils/constants.ts @@ -24,7 +24,41 @@ export const IotDeviceMessageMethodEnum = { // ========== 设备状态 ========== STATE_UPDATE: { method: 'thing.state.update', - name: '设备状态变更', + name: '设备状态更新', + upstream: true + }, + + // ========== 拓扑管理 ========== + TOPO_ADD: { + method: 'thing.topo.add', + name: '添加拓扑关系', + upstream: true + }, + TOPO_DELETE: { + method: 'thing.topo.delete', + name: '删除拓扑关系', + upstream: true + }, + TOPO_GET: { + method: 'thing.topo.get', + name: '获取拓扑关系', + upstream: true + }, + TOPO_CHANGE: { + method: 'thing.topo.change', + name: '拓扑关系变更通知', + upstream: false + }, + + // ========== 设备注册 ========== + DEVICE_REGISTER: { + method: 'thing.auth.register', + name: '设备动态注册', + upstream: true + }, + SUB_DEVICE_REGISTER: { + method: 'thing.auth.register.sub', + name: '子设备动态注册', upstream: true }, @@ -39,6 +73,11 @@ export const IotDeviceMessageMethodEnum = { name: '属性设置', upstream: false }, + PROPERTY_PACK_POST: { + method: 'thing.event.property.pack.post', + name: '批量上报(属性 + 事件 + 子设备)', + upstream: true + }, // ========== 设备事件 ========== EVENT_POST: { @@ -59,6 +98,18 @@ export const IotDeviceMessageMethodEnum = { method: 'thing.config.push', name: '配置推送', upstream: false + }, + + // ========== OTA 固件 ========== + OTA_UPGRADE: { + method: 'thing.ota.upgrade', + name: 'OTA 固件信息推送', + upstream: false + }, + OTA_PROGRESS: { + method: 'thing.ota.progress', + name: 'OTA 升级进度上报', + upstream: true } } From 7a7228aed8678280beaddcaa85dfd201873e89e5 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Tue, 27 Jan 2026 19:03:10 +0800 Subject: [PATCH 06/13] =?UTF-8?q?feat(bpm):=20=E8=A1=A8=E5=8D=95=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E5=99=A8=20UserSelect/DeptSelect=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=80=89=E4=B8=AD=E5=BD=93=E5=89=8D=E7=94=A8?= =?UTF-8?q?=E6=88=B7/=E9=83=A8=E9=97=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. UserSelect 新增 defaultCurrentUser 配置,默认选中当前登录用户 2. DeptSelect 新增 defaultCurrentDept 配置,默认选中当前用户所属部门 3. DeptSelect 改用 el-tree-select 实现树形层级显示 4. 支持单选/多选模式,预设值优先级高于默认值 --- .../FormCreate/src/components/DeptSelect.vue | 196 ++++++++++++++++++ .../src/components/useApiSelect.tsx | 54 ++++- .../FormCreate/src/config/useSelectRule.ts | 13 +- .../FormCreate/src/useFormCreateDesigner.ts | 16 +- src/plugins/formCreate/index.ts | 7 +- 5 files changed, 277 insertions(+), 9 deletions(-) create mode 100644 src/components/FormCreate/src/components/DeptSelect.vue diff --git a/src/components/FormCreate/src/components/DeptSelect.vue b/src/components/FormCreate/src/components/DeptSelect.vue new file mode 100644 index 000000000..2e18f4ad6 --- /dev/null +++ b/src/components/FormCreate/src/components/DeptSelect.vue @@ -0,0 +1,196 @@ + + + + diff --git a/src/components/FormCreate/src/components/useApiSelect.tsx b/src/components/FormCreate/src/components/useApiSelect.tsx index 89a7e8dbb..25e9d70d2 100644 --- a/src/components/FormCreate/src/components/useApiSelect.tsx +++ b/src/components/FormCreate/src/components/useApiSelect.tsx @@ -2,6 +2,7 @@ import request from '@/config/axios' import { isEmpty } from '@/utils/is' import { ApiSelectProps } from '@/components/FormCreate/src/type' import { jsonParse } from '@/utils' +import { useUserStoreWithOut } from '@/store/modules/user' export const useApiSelect = (option: ApiSelectProps) => { return defineComponent({ @@ -61,13 +62,62 @@ export const useApiSelect = (option: ApiSelectProps) => { returnType: { type: String, default: 'id' + }, + // 是否默认选中当前用户(仅 UserSelect 使用) + defaultCurrentUser: { + type: Boolean, + default: false } }, - setup(props) { + setup(props, { emit }) { const attrs = useAttrs() const options = ref([]) // 下拉数据 const loading = ref(false) // 是否正在从远程获取数据 const queryParam = ref() // 当前输入的值 + + // 检查是否有有效的预设值 + const hasValidPresetValue = (): boolean => { + const value = attrs.modelValue + if (value === undefined || value === null || value === '') { + return false + } + if (Array.isArray(value)) { + return value.length > 0 + } + return true + } + + // 设置默认当前用户(仅当 defaultCurrentUser 为 true 且无预设值时) + const setDefaultCurrentUser = () => { + console.log('[UserSelect] setDefaultCurrentUser called, defaultCurrentUser:', props.defaultCurrentUser) + + // 仅当组件名为 UserSelect 且 defaultCurrentUser 为 true 时处理 + if (option.name !== 'UserSelect' || !props.defaultCurrentUser) { + console.log('[UserSelect] skip - not UserSelect or defaultCurrentUser is false') + return + } + + // 检查是否已有预设值(预设值优先级高于默认当前用户) + if (hasValidPresetValue()) { + console.log('[UserSelect] has preset value, skip:', attrs.modelValue) + return + } + + // 获取当前用户 ID + const userStore = useUserStoreWithOut() + const user = userStore.getUser + const currentUserId = user?.id + + console.log('[UserSelect] current user:', user, 'userId:', currentUserId) + + if (currentUserId) { + // 根据多选/单选模式设置默认值 + const defaultValue = props.multiple ? [currentUserId] : currentUserId + console.log('[UserSelect] setting default value:', defaultValue) + emit('update:modelValue', defaultValue) + } + } + const getOptions = async () => { options.value = [] // 接口选择器 @@ -188,6 +238,8 @@ export const useApiSelect = (option: ApiSelectProps) => { onMounted(async () => { await getOptions() + // 设置默认当前用户(在数据加载完成后) + setDefaultCurrentUser() }) const buildSelect = () => { diff --git a/src/components/FormCreate/src/config/useSelectRule.ts b/src/components/FormCreate/src/config/useSelectRule.ts index e1d77fbcc..c95e047db 100644 --- a/src/components/FormCreate/src/config/useSelectRule.ts +++ b/src/components/FormCreate/src/config/useSelectRule.ts @@ -19,13 +19,24 @@ export const useSelectRule = (option: SelectRuleOption) => { name, event: option.event, rule() { - return { + // 构建基础规则 + const baseRule: any = { type: name, field: generateUUID(), title: label, info: '', $required: false } + // 将自定义 props 的默认值添加到 rule 的 props 中 + if (option.props && option.props.length > 0) { + baseRule.props = {} + option.props.forEach((prop: any) => { + if (prop.field && prop.value !== undefined) { + baseRule.props[prop.field] = prop.value + } + }) + } + return baseRule }, props(_, { t }) { if (!option.props) { diff --git a/src/components/FormCreate/src/useFormCreateDesigner.ts b/src/components/FormCreate/src/useFormCreateDesigner.ts index 4e87e432e..5769b4baa 100644 --- a/src/components/FormCreate/src/useFormCreateDesigner.ts +++ b/src/components/FormCreate/src/useFormCreateDesigner.ts @@ -52,7 +52,15 @@ export const useFormCreateDesigner = async (designer: Ref) => { const userSelectRule = useSelectRule({ name: 'UserSelect', label: '用户选择器', - icon: 'icon-user-o' + icon: 'icon-user-o', + props: [ + { + type: 'switch', + field: 'defaultCurrentUser', + title: '默认选中当前用户', + value: true + } + ] }) const deptSelectRule = useSelectRule({ name: 'DeptSelect', @@ -68,6 +76,12 @@ export const useFormCreateDesigner = async (designer: Ref) => { { label: '部门编号', value: 'id' }, { label: '部门名称', value: 'name' } ] + }, + { + type: 'switch', + field: 'defaultCurrentDept', + title: '默认选中当前部门', + value: true } ] }) diff --git a/src/plugins/formCreate/index.ts b/src/plugins/formCreate/index.ts index 01a57bebc..6e0a971fe 100644 --- a/src/plugins/formCreate/index.ts +++ b/src/plugins/formCreate/index.ts @@ -68,6 +68,7 @@ import { UploadFile, UploadImg, UploadImgs } from '@/components/UploadFile' import { useApiSelect } from '@/components/FormCreate' import { Editor } from '@/components/Editor' import DictSelect from '@/components/FormCreate/src/components/DictSelect.vue' +import DeptSelect from '@/components/FormCreate/src/components/DeptSelect.vue' const UserSelect = useApiSelect({ name: 'UserSelect', @@ -75,12 +76,6 @@ const UserSelect = useApiSelect({ valueField: 'id', url: '/system/user/simple-list' }) -const DeptSelect = useApiSelect({ - name: 'DeptSelect', - labelField: 'name', - valueField: 'id', - url: '/system/dept/simple-list' -}) const ApiSelect = useApiSelect({ name: 'ApiSelect' }) From c656f8757585e11baa44b146bb9850305115c0c1 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Wed, 28 Jan 2026 11:06:59 +0800 Subject: [PATCH 07/13] =?UTF-8?q?fix(mall):=20=E4=BF=AE=E5=A4=8D=E5=95=86?= =?UTF-8?q?=E5=93=81=20SKU=20=E5=90=8D=E7=A7=B0=E6=A0=A1=E9=AA=8C=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/mall/product/spu/components/SkuList.vue | 3 +++ src/views/mall/product/spu/form/SkuForm.vue | 1 + src/views/mall/product/spu/form/index.vue | 9 ++++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/views/mall/product/spu/components/SkuList.vue b/src/views/mall/product/spu/components/SkuList.vue index c41da4b2c..10d82319f 100644 --- a/src/views/mall/product/spu/components/SkuList.vue +++ b/src/views/mall/product/spu/components/SkuList.vue @@ -318,6 +318,7 @@ const props = defineProps({ const formData: Ref = ref() // 表单数据 const skuList = ref([ { + name: '', // SKU 名称 price: 0, // 商品价格 marketPrice: 0, // 市场价 costPrice: 0, // 成本价 @@ -449,6 +450,7 @@ const generateTableData = (propertyList: any[]) => { } for (const item of buildSkuList) { const row = { + name: '', // SKU 名称,提交时会自动使用 SPU 名称 properties: Array.isArray(item) ? item : [item], // 如果只有一个属性的话返回的是一个 property 对象 price: 0, marketPrice: 0, @@ -525,6 +527,7 @@ watch( if (props.isBatch) { skuList.value = [ { + name: '', // SKU 名称 price: 0, marketPrice: 0, costPrice: 0, diff --git a/src/views/mall/product/spu/form/SkuForm.vue b/src/views/mall/product/spu/form/SkuForm.vue index 18cd0296f..782d8ed48 100644 --- a/src/views/mall/product/spu/form/SkuForm.vue +++ b/src/views/mall/product/spu/form/SkuForm.vue @@ -173,6 +173,7 @@ const onChangeSpec = () => { // 重置sku列表 formData.skus = [ { + name: '', // SKU 名称,提交时会自动使用 SPU 名称 price: 0, marketPrice: 0, costPrice: 0, diff --git a/src/views/mall/product/spu/form/index.vue b/src/views/mall/product/spu/form/index.vue index c4e4b7b2d..bf4aa9341 100644 --- a/src/views/mall/product/spu/form/index.vue +++ b/src/views/mall/product/spu/form/index.vue @@ -62,6 +62,7 @@ import OtherForm from './OtherForm.vue' import SkuForm from './SkuForm.vue' import DeliveryForm from './DeliveryForm.vue' import { convertToInteger, floatToFixed2, formatToFraction } from '@/utils' +import { isEmpty } from '@/utils/is' defineOptions({ name: 'ProductSpuAdd' }) @@ -94,6 +95,7 @@ const formData = ref({ subCommissionType: false, // 分销类型 skus: [ { + name: '', // SKU 名称,提交时会自动使用 SPU 名称 price: 0, // 商品价格 marketPrice: 0, // 市场价 costPrice: 0, // 成本价 @@ -158,8 +160,13 @@ const submitForm = async () => { await unref(otherRef)?.validate() // 深拷贝一份, 这样最终 server 端不满足,不需要影响原始数据 const deepCopyFormData = cloneDeep(unref(formData.value)) as ProductSpuApi.Spu + // 校验商品名称不能为空(用于 SKU name) + if (isEmpty(deepCopyFormData.name)) { + message.error('商品名称不能为空') + return + } deepCopyFormData.skus!.forEach((item) => { - // 给sku name赋值 + // 给sku name赋值(使用商品名称作为 SKU 名称) item.name = deepCopyFormData.name // sku相关价格元转分 item.price = convertToInteger(item.price) From 0ee0065c6af1d007df7b8bff33605a5703bfcf93 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 29 Jan 2026 20:18:00 +0800 Subject: [PATCH 08/13] feat: update default selection settings for current user and department --- .../FormCreate/src/components/useApiSelect.tsx | 11 +---------- .../FormCreate/src/useFormCreateDesigner.ts | 4 ++-- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/components/FormCreate/src/components/useApiSelect.tsx b/src/components/FormCreate/src/components/useApiSelect.tsx index 25e9d70d2..847eb077c 100644 --- a/src/components/FormCreate/src/components/useApiSelect.tsx +++ b/src/components/FormCreate/src/components/useApiSelect.tsx @@ -89,31 +89,22 @@ export const useApiSelect = (option: ApiSelectProps) => { // 设置默认当前用户(仅当 defaultCurrentUser 为 true 且无预设值时) const setDefaultCurrentUser = () => { - console.log('[UserSelect] setDefaultCurrentUser called, defaultCurrentUser:', props.defaultCurrentUser) - // 仅当组件名为 UserSelect 且 defaultCurrentUser 为 true 时处理 if (option.name !== 'UserSelect' || !props.defaultCurrentUser) { - console.log('[UserSelect] skip - not UserSelect or defaultCurrentUser is false') return } - // 检查是否已有预设值(预设值优先级高于默认当前用户) if (hasValidPresetValue()) { - console.log('[UserSelect] has preset value, skip:', attrs.modelValue) return } - + // 获取当前用户 ID const userStore = useUserStoreWithOut() const user = userStore.getUser const currentUserId = user?.id - - console.log('[UserSelect] current user:', user, 'userId:', currentUserId) - if (currentUserId) { // 根据多选/单选模式设置默认值 const defaultValue = props.multiple ? [currentUserId] : currentUserId - console.log('[UserSelect] setting default value:', defaultValue) emit('update:modelValue', defaultValue) } } diff --git a/src/components/FormCreate/src/useFormCreateDesigner.ts b/src/components/FormCreate/src/useFormCreateDesigner.ts index 5769b4baa..0f528838e 100644 --- a/src/components/FormCreate/src/useFormCreateDesigner.ts +++ b/src/components/FormCreate/src/useFormCreateDesigner.ts @@ -58,7 +58,7 @@ export const useFormCreateDesigner = async (designer: Ref) => { type: 'switch', field: 'defaultCurrentUser', title: '默认选中当前用户', - value: true + value: false } ] }) @@ -81,7 +81,7 @@ export const useFormCreateDesigner = async (designer: Ref) => { type: 'switch', field: 'defaultCurrentDept', title: '默认选中当前部门', - value: true + value: false } ] }) From 04a69872113b23126849c2e60b3ff508cdba200d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 29 Jan 2026 23:49:33 +0800 Subject: [PATCH 09/13] =?UTF-8?q?(=E3=80=83'=E2=96=BD'=E3=80=83)=20v2026.0?= =?UTF-8?q?1=20=E5=8F=91=E5=B8=83=EF=BC=9A=E5=A4=A7=E5=A4=A7=E5=A4=A7?= =?UTF-8?q?=E5=A4=A7=E5=AE=8C=E5=96=84=20vben5=20=E7=9A=84=20antd=E3=80=81?= =?UTF-8?q?vben=20=E7=89=88=E6=9C=AC=E7=9A=84=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20IoT=20=E5=90=84=E7=A7=8D=E6=8E=A5=E5=85=A5?= =?UTF-8?q?=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a12256e9..8ef3b4ee6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "yudao-ui-admin-vue3", - "version": "2025.12-snapshot", + "version": "2026.01-snapshot", "description": "基于vue3、vite4、element-plus、typesScript", "author": "xingyu", "private": false, From 1678bf6e5781f81dce6ee3690b6a52b9f6a804e7 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 7 Feb 2026 16:42:23 +0800 Subject: [PATCH 10/13] =?UTF-8?q?fix:=20=E5=BF=98=E8=AE=B0=E5=AF=86?= =?UTF-8?q?=E7=A0=81=E9=A1=B5=E9=9D=A2=E6=9C=AA=E5=BC=80=E5=90=AF=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81=E6=97=B6=EF=BC=8C=E9=9A=90=E8=97=8F=20Verify?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=EF=BC=8C=E9=81=BF=E5=85=8D=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=20captcha/get=20=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/Login/components/ForgetPasswordForm.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/views/Login/components/ForgetPasswordForm.vue b/src/views/Login/components/ForgetPasswordForm.vue index f47b2299a..f5f41dc83 100644 --- a/src/views/Login/components/ForgetPasswordForm.vue +++ b/src/views/Login/components/ForgetPasswordForm.vue @@ -39,6 +39,7 @@ Date: Sat, 7 Feb 2026 21:07:31 +0800 Subject: [PATCH 11/13] =?UTF-8?q?fix(crm):=20=E4=BF=AE=E5=A4=8D=E7=BA=BF?= =?UTF-8?q?=E7=B4=A2=E8=AF=A6=E6=83=85=E9=A1=B5=E8=BD=AC=E5=8C=96=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=8C=89=E9=92=AE=E8=AF=AF=E6=98=BE=E7=A4=BA=EF=BC=8C?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=20https://t.zsxq.com/wq7ix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/crm/clue/detail/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/crm/clue/detail/index.vue b/src/views/crm/clue/detail/index.vue index 4c211e661..4841b0830 100644 --- a/src/views/crm/clue/detail/index.vue +++ b/src/views/crm/clue/detail/index.vue @@ -18,7 +18,7 @@ > 转化为客户 - 已转化客户 + 已转化客户 From a62251f900066434ace128e785e9f8bae421df29 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Sun, 8 Feb 2026 11:56:18 +0800 Subject: [PATCH 12/13] =?UTF-8?q?feat(form-create):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20iframe=20=E5=92=8C=E7=9C=81=E5=B8=82=E5=8C=BA=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E5=99=A8=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 iframe 网页嵌入组件,支持 URL 配置和实时预览 - 新增省市区三级联动选择器组件 --- .../FormCreate/src/components/AreaSelect.vue | 145 ++++++++++++++++++ .../src/components/IframeComponent.vue | 102 ++++++++++++ src/components/FormCreate/src/config/index.ts | 6 +- .../src/config/useAreaSelectRule.ts | 74 +++++++++ .../FormCreate/src/config/useIframeRule.ts | 74 +++++++++ .../FormCreate/src/useFormCreateDesigner.ts | 8 +- src/plugins/formCreate/index.ts | 4 + 7 files changed, 410 insertions(+), 3 deletions(-) create mode 100644 src/components/FormCreate/src/components/AreaSelect.vue create mode 100644 src/components/FormCreate/src/components/IframeComponent.vue create mode 100644 src/components/FormCreate/src/config/useAreaSelectRule.ts create mode 100644 src/components/FormCreate/src/config/useIframeRule.ts diff --git a/src/components/FormCreate/src/components/AreaSelect.vue b/src/components/FormCreate/src/components/AreaSelect.vue new file mode 100644 index 000000000..32ef3296a --- /dev/null +++ b/src/components/FormCreate/src/components/AreaSelect.vue @@ -0,0 +1,145 @@ + + + + diff --git a/src/components/FormCreate/src/components/IframeComponent.vue b/src/components/FormCreate/src/components/IframeComponent.vue new file mode 100644 index 000000000..49ac1a883 --- /dev/null +++ b/src/components/FormCreate/src/components/IframeComponent.vue @@ -0,0 +1,102 @@ + + + + + + diff --git a/src/components/FormCreate/src/config/index.ts b/src/components/FormCreate/src/config/index.ts index b1e2ddea5..d4d384c31 100644 --- a/src/components/FormCreate/src/config/index.ts +++ b/src/components/FormCreate/src/config/index.ts @@ -4,6 +4,8 @@ import { useUploadImgsRule } from './useUploadImgsRule' import { useDictSelectRule } from './useDictSelectRule' import { useEditorRule } from './useEditorRule' import { useSelectRule } from './useSelectRule' +import { useIframeRule } from './useIframeRule' +import { useAreaSelectRule } from './useAreaSelectRule' export { useUploadFileRule, @@ -11,5 +13,7 @@ export { useUploadImgsRule, useDictSelectRule, useEditorRule, - useSelectRule + useSelectRule, + useIframeRule, + useAreaSelectRule } diff --git a/src/components/FormCreate/src/config/useAreaSelectRule.ts b/src/components/FormCreate/src/config/useAreaSelectRule.ts new file mode 100644 index 000000000..59405da6a --- /dev/null +++ b/src/components/FormCreate/src/config/useAreaSelectRule.ts @@ -0,0 +1,74 @@ +import { generateUUID } from '@/utils' +import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils' + +/** + * 省市区选择器规则 + */ +export const useAreaSelectRule = () => { + const label = '省市区选择器' + const name = 'AreaSelect' + + return { + icon: 'icon-location', + label, + name, + rule() { + return { + type: name, + field: generateUUID(), + title: label, + info: '', + $required: false + } + }, + props(_, { t }) { + return localeProps(t, name + '.props', [ + makeRequiredRule(), + { + type: 'select', + field: 'level', + title: '选择层级', + value: 3, + options: [ + { label: '省', value: 1 }, + { label: '省/市', value: 2 }, + { label: '省/市/区', value: 3 } + ], + info: '限制可选择的地区层级' + }, + { + type: 'input', + field: 'placeholder', + title: '占位符', + value: '请选择省市区' + }, + { + type: 'switch', + field: 'clearable', + title: '是否可清空', + value: true + }, + { + type: 'switch', + field: 'showAllLevels', + title: '显示完整路径', + value: true, + info: '输入框中是否显示选中值的完整路径' + }, + { + type: 'input', + field: 'separator', + title: '分隔符', + value: '/', + info: '选项分隔符' + }, + { + type: 'switch', + field: 'disabled', + title: '是否禁用', + value: false + } + ]) + } + } +} diff --git a/src/components/FormCreate/src/config/useIframeRule.ts b/src/components/FormCreate/src/config/useIframeRule.ts new file mode 100644 index 000000000..5a3e47871 --- /dev/null +++ b/src/components/FormCreate/src/config/useIframeRule.ts @@ -0,0 +1,74 @@ +import { generateUUID } from '@/utils' +import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils' + +/** + * iframe 组件规则 + */ +export const useIframeRule = () => { + const label = '网页 iframe' + const name = 'IframeComponent' + + return { + icon: 'icon-link', + label, + name, + rule() { + return { + type: name, + field: generateUUID(), + title: label, + info: '', + $required: false + } + }, + props(_, { t }) { + return localeProps(t, name + '.props', [ + makeRequiredRule(), + { + type: 'input', + field: 'url', + title: 'URL 地址', + value: '', + info: '请输入完整的 HTTP 或 HTTPS 地址' + }, + { + type: 'input', + field: 'height', + title: 'iframe 高度', + value: '500px', + info: '支持 px、%、vh 等单位' + }, + { + type: 'input', + field: 'width', + title: 'iframe 宽度', + value: '100%', + info: '支持 px、%、vw 等单位' + }, + { + type: 'select', + field: 'loading', + title: '加载方式', + value: 'lazy', + options: [ + { label: '懒加载', value: 'lazy' }, + { label: '立即加载', value: 'eager' } + ] + }, + { + type: 'switch', + field: 'allowfullscreen', + title: '允许全屏', + value: true + }, + { + type: 'input', + field: 'sandbox', + title: 'sandbox 属性', + value: '', + info: '安全沙箱限制,如:allow-scripts allow-same-origin' + } + ]) + } + } +} diff --git a/src/components/FormCreate/src/useFormCreateDesigner.ts b/src/components/FormCreate/src/useFormCreateDesigner.ts index 5769b4baa..9658f8b76 100644 --- a/src/components/FormCreate/src/useFormCreateDesigner.ts +++ b/src/components/FormCreate/src/useFormCreateDesigner.ts @@ -4,7 +4,9 @@ import { useSelectRule, useUploadFileRule, useUploadImgRule, - useUploadImgsRule + useUploadImgsRule, + useIframeRule, + useAreaSelectRule } from './config' import { Ref } from 'vue' import { Menu } from '@/components/FormCreate/src/type' @@ -36,7 +38,9 @@ export const useFormCreateDesigner = async (designer: Ref) => { designer.value?.removeMenuItem('upload') // 移除自带的富文本组件规则,使用 editorRule 替代 designer.value?.removeMenuItem('fcEditor') - const components = [editorRule, uploadFileRule, uploadImgRule, uploadImgsRule] + const iframeRule = useIframeRule() + const areaSelectRule = useAreaSelectRule() + const components = [editorRule, uploadFileRule, uploadImgRule, uploadImgsRule, iframeRule, areaSelectRule] components.forEach((component) => { // 插入组件规则 designer.value?.addComponent(component) diff --git a/src/plugins/formCreate/index.ts b/src/plugins/formCreate/index.ts index 6e0a971fe..425930509 100644 --- a/src/plugins/formCreate/index.ts +++ b/src/plugins/formCreate/index.ts @@ -69,6 +69,8 @@ import { useApiSelect } from '@/components/FormCreate' import { Editor } from '@/components/Editor' import DictSelect from '@/components/FormCreate/src/components/DictSelect.vue' import DeptSelect from '@/components/FormCreate/src/components/DeptSelect.vue' +import IframeComponent from '@/components/FormCreate/src/components/IframeComponent.vue' +import AreaSelect from '@/components/FormCreate/src/components/AreaSelect.vue' const UserSelect = useApiSelect({ name: 'UserSelect', @@ -114,6 +116,8 @@ const components = [ DeptSelect, ApiSelect, Editor, + IframeComponent, + AreaSelect, ElCollapse, ElCollapseItem, ElCard From c153ff93c73a305637828b0a3b83906ece6e9067 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 8 Feb 2026 14:37:55 +0800 Subject: [PATCH 13/13] =?UTF-8?q?review=EF=BC=9A=E2=80=9C=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20iframe=20=E5=92=8C=E7=9C=81=E5=B8=82=E5=8C=BA?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=99=A8=E7=BB=84=E4=BB=B6=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FormCreate/src/components/AreaSelect.vue | 39 ++++++++----------- .../src/components/IframeComponent.vue | 12 +++--- .../src/config/useAreaSelectRule.ts | 1 - .../FormCreate/src/config/useIframeRule.ts | 1 - 4 files changed, 22 insertions(+), 31 deletions(-) diff --git a/src/components/FormCreate/src/components/AreaSelect.vue b/src/components/FormCreate/src/components/AreaSelect.vue index 32ef3296a..1633d7a9d 100644 --- a/src/components/FormCreate/src/components/AreaSelect.vue +++ b/src/components/FormCreate/src/components/AreaSelect.vue @@ -18,6 +18,7 @@