feat: 完善功能

This commit is contained in:
cnb.aUOqoEV4wEA 2025-11-11 17:40:08 +08:00
parent 510761b01c
commit e923af74a7
19 changed files with 386 additions and 107 deletions

3
.gitignore vendored
View File

@ -50,3 +50,6 @@ vite.config.ts.*
*.sw? *.sw?
.history .history
.cursor .cursor
.pnpm-store
node-compile-cache

View File

@ -26,6 +26,7 @@
"#/*": "./src/*" "#/*": "./src/*"
}, },
"dependencies": { "dependencies": {
"@vant/area-data": "^2.1.0",
"@vben/access": "workspace:*", "@vben/access": "workspace:*",
"@vben/common-ui": "workspace:*", "@vben/common-ui": "workspace:*",
"@vben/constants": "workspace:*", "@vben/constants": "workspace:*",
@ -43,6 +44,7 @@
"@vueuse/core": "catalog:", "@vueuse/core": "catalog:",
"dayjs": "catalog:", "dayjs": "catalog:",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"nanoid": "^5.1.6",
"pinia": "catalog:", "pinia": "catalog:",
"tdesign-vue-next": "^1.17.1", "tdesign-vue-next": "^1.17.1",
"vue": "catalog:", "vue": "catalog:",

View File

@ -61,6 +61,13 @@ const TimePicker = defineAsyncComponent(
const TreeSelect = defineAsyncComponent( const TreeSelect = defineAsyncComponent(
() => import('tdesign-vue-next/es/tree-select'), () => import('tdesign-vue-next/es/tree-select'),
); );
const Tree = defineAsyncComponent(
() => import('tdesign-vue-next/es/tree'),
)
const Cascader = defineAsyncComponent(
() => import('tdesign-vue-next/es/cascader'),
)
const Upload = defineAsyncComponent(() => import('tdesign-vue-next/es/upload')); const Upload = defineAsyncComponent(() => import('tdesign-vue-next/es/upload'));
const withDefaultPlaceholder = <T extends Component>( const withDefaultPlaceholder = <T extends Component>(
@ -100,10 +107,12 @@ const withDefaultPlaceholder = <T extends Component>(
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明 // 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type ComponentType = export type ComponentType =
| 'ApiSelect' | 'ApiSelect'
| 'ApiTree'
| 'ApiTreeSelect' | 'ApiTreeSelect'
| 'AutoComplete' | 'AutoComplete'
| 'Checkbox' | 'Checkbox'
| 'CheckboxGroup' | 'CheckboxGroup'
| 'Cascader'
| 'DatePicker' | 'DatePicker'
| 'DefaultButton' | 'DefaultButton'
| 'Divider' | 'Divider'
@ -122,6 +131,7 @@ export type ComponentType =
| 'Switch' | 'Switch'
| 'Textarea' | 'Textarea'
| 'TimePicker' | 'TimePicker'
| 'Tree'
| 'TreeSelect' | 'TreeSelect'
| 'Upload' | 'Upload'
| BaseFormComponentType; | BaseFormComponentType;
@ -152,16 +162,17 @@ async function initComponentAdapter() {
'select', 'select',
{ {
component: TreeSelect, component: TreeSelect,
fieldNames: { label: 'label', value: 'value', children: 'children' }, keys: { label: 'label', value: 'value', children: 'children' },
loadingSlot: 'suffixIcon', loadingSlot: 'suffixIcon',
modelPropName: 'value', modelPropName: 'value',
optionsPropName: 'treeData', optionsPropName: 'data',
visibleEvent: 'onVisibleChange', visibleEvent: 'onVisibleChange',
}, },
), ),
AutoComplete, AutoComplete,
Checkbox, Checkbox,
CheckboxGroup, CheckboxGroup,
Cascader,
DatePicker, DatePicker,
// 自定义默认按钮 // 自定义默认按钮
DefaultButton: (props, { attrs, slots }) => { DefaultButton: (props, { attrs, slots }) => {
@ -208,6 +219,22 @@ async function initComponentAdapter() {
TimePicker, TimePicker,
TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'), TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
Upload, Upload,
Tree,
ApiTree: withDefaultPlaceholder(
{
...ApiComponent,
name: 'ApiTree',
},
'select',
{
component: Tree,
keys: { label: 'label', value: 'value', children: 'children' },
loadingSlot: 'suffixIcon',
modelPropName: 'value',
optionsPropName: 'data',
visibleEvent: 'onVisibleChange',
},
)
}; };
// 将组件注册到全局共享状态中 // 将组件注册到全局共享状态中

View File

@ -73,11 +73,10 @@ export function useSearchFormSchema(): VbenFormSchema[] {
}, },
{ {
component: 'ApiSelect', component: 'ApiSelect',
fieldName: 'roleIds', fieldName: 'roleId',
defaultValue: [], defaultValue: '',
componentProps: { componentProps: {
api: getRoleOptions, api: getRoleOptions,
multiple: true,
clearable: true, clearable: true,
labelField: 'roleName', labelField: 'roleName',
valueField: 'id', valueField: 'id',

View File

@ -82,7 +82,7 @@ const onRefresh = () => {
const roleOptionsMap = computed(() => { const roleOptionsMap = computed(() => {
return toObject( return toObject(
GridApi.formApi.getFieldComponentRef('roleIds')?.getOptions() ?? [], GridApi.formApi.getFieldComponentRef('roleId')?.getOptions() ?? [],
'value', 'value',
'label', 'label',
); );
@ -100,7 +100,7 @@ const deptOptionsMap = computed(() => {
<Page auto-content-height> <Page auto-content-height>
<Grid table-title="用户列表"> <Grid table-title="用户列表">
<template #toolbar-tools> <template #toolbar-tools>
<TButton class="mr-2" type="primary" @click="addEvent"> <TButton class="mr-2" theme="primary" @click="addEvent">
新增用户 新增用户
</TButton> </TButton>
</template> </template>

View File

@ -18,7 +18,6 @@ export function useSubmitFormSchema(): VbenFormSchema[] {
defaultValue: [], defaultValue: [],
componentProps: { componentProps: {
api: getAdminOptions, api: getAdminOptions,
resultField: '',
multiple: true, multiple: true,
clearable: true, clearable: true,
labelField: 'displayName', labelField: 'displayName',
@ -33,6 +32,10 @@ export function useSubmitFormSchema(): VbenFormSchema[] {
defaultValue: [], defaultValue: [],
componentProps: { componentProps: {
api: getPointOptions, api: getPointOptions,
afterFetch: (res: any) =>{
return [{ displayName: '全选', checkAll: true},...res]
},
minCollapsedNum: 1,
resultField: '', resultField: '',
multiple: true, multiple: true,
clearable: true, clearable: true,

View File

@ -3,7 +3,15 @@ import { computed, onMounted, ref } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui'; import { Page, useVbenModal } from '@vben/common-ui';
import { NButton, NSpace, NTag } from 'naive-ui'; import {
Button as TButton,
Link as TLink,
Space as TSpace,
Switch as TSwitch,
Tag as TTag
} from 'tdesign-vue-next';
import { message } from '#/adapter/tdesign';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getAdminOptions } from '#/api'; import { getAdminOptions } from '#/api';
@ -62,24 +70,24 @@ onMounted(() => {
<Page auto-content-height> <Page auto-content-height>
<Grid table-title="部门列表"> <Grid table-title="部门列表">
<template #toolbar-tools> <template #toolbar-tools>
<NSpace> <TSpace>
<NButton type="primary" @click="addEvent">新增部门</NButton> <TButton theme="primary" @click="addEvent">新增部门</TButton>
<NButton @click="refresh">查询</NButton> <TButton @click="refresh">查询</TButton>
</NSpace> </TSpace>
</template> </template>
<template #adminIds="{ row }"> <template #adminIds="{ row }">
<NSpace> <TSpace>
<NTag v-for="id in row.adminIds" :key="id"> <TTag v-for="id in row.adminIds" :key="id">
{{ adminOptionsMap[id] }} {{ adminOptionsMap[id] }}
</NTag> </TTag>
</NSpace> </TSpace>
</template> </template>
<template #actions="{ row }"> <template #actions="{ row }">
<NSpace> <TSpace>
<NButton text type="primary" @click="editEvent(row)">编辑</NButton> <TLink theme="primary" @click="editEvent(row)">编辑</TLink>
</NSpace> </TSpace>
</template> </template>
</Grid> </Grid>

View File

@ -2,9 +2,15 @@
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { confirm, Page, useVbenModal } from '@vben/common-ui'; import { confirm, Page, useVbenModal } from '@vben/common-ui';
import {
Button as TButton,
Link as TLink,
Space as TSpace,
Switch as TSwitch,
Tag as TTag
} from 'tdesign-vue-next';
import { NButton, NSpace, NSwitch, NTag, useMessage } from 'naive-ui'; import { message } from '#/adapter/tdesign';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { changeMenuStatus, getMenuList, getRoleOptions } from '#/api'; import { changeMenuStatus, getMenuList, getRoleOptions } from '#/api';
import { toObject } from '#/enum'; import { toObject } from '#/enum';
@ -19,7 +25,6 @@ const [FormModel, formModelApi] = useVbenModal({
destroyOnClose: true, destroyOnClose: true,
}); });
const message = useMessage();
function onStatusChange(value: any, row: any) { function onStatusChange(value: any, row: any) {
confirm(`确认${value === 1 ? '启用' : '禁用'}权限`, `切换状态`) confirm(`确认${value === 1 ? '启用' : '禁用'}权限`, `切换状态`)
@ -112,43 +117,43 @@ onMounted(() => {
<Page auto-content-height> <Page auto-content-height>
<Grid table-title="权限列表"> <Grid table-title="权限列表">
<template #toolbar-tools> <template #toolbar-tools>
<NButton class="mr-2" type="primary" @click="addEvent"> <TButton class="mr-2" theme="primary" @click="addEvent">
新增权限 新增权限
</NButton> </TButton>
</template> </template>
<template #status="{ row }"> <template #status="{ row }">
<NSwitch <TSwitch
:value="row.status" :value="row.status"
:checked-value="true" :checked-value="true"
:unchecked-value="false" :unchecked-value="false"
:on-update:value="(value) => onStatusChange(value, row)" :on-update:value="(value) => onStatusChange(value, row)"
> >
{{ toObject(CommonStatusEnum, 'value', 'label')[row.status] }} {{ toObject(CommonStatusEnum, 'value', 'label')[row.status] }}
</NSwitch> </TSwitch>
</template> </template>
<template #menuType="{ row }"> <template #menuType="{ row }">
<NTag> <TTag>
{{ MenuTypeEnumMap[row.menuType] }} {{ MenuTypeEnumMap[row.menuType] }}
</NTag> </TTag>
</template> </template>
<template #roleIds="{ row }"> <template #roleIds="{ row }">
<NSpace> <TSpace>
<NTag v-for="id in row.roleIds" :key="id"> <TTag theme="primary" v-for="id in row.roleIds" :key="id">
{{ roleOptionsMap[id] }} {{ roleOptionsMap[id] }}
</NTag> </TTag>
</NSpace> </TSpace>
</template> </template>
<template #actions="{ row }"> <template #actions="{ row }">
<NSpace> <TSpace>
<NButton text type="primary" @click="addChildMenu(row)"> <TLink theme="primary" @click="addChildMenu(row)">
增加下级菜单 增加下级菜单
</NButton> </TLink>
<NButton text type="primary" @click="editEvent(row)">编辑</NButton> <TLink theme="primary" @click="editEvent(row)">编辑</TLink>
</NSpace> </TSpace>
</template> </template>
</Grid> </Grid>

View File

@ -31,20 +31,18 @@ export function useSubmitFormSchema(): VbenFormSchema[] {
}, },
}, },
{ {
component: 'ApiTreeSelect', component: 'ApiTree',
// 对应组件的参数 // 对应组件的参数
componentProps: { componentProps: {
// 菜单接口 // 菜单接口
api: getMenuTree, api: getMenuTree,
resultField: 'items', resultField: 'items',
childrenField: 'children', keys: { label: 'menuName', value: 'id'},
labelField: 'menuName', checkStrictly: true,
valueField: 'id', checkable: true,
maxTagCount: 'responsive', expandAll: true,
clearable: true, clearable: true,
multiple: true, multiple: true,
cascade: true,
checkable: true,
}, },
fieldName: 'menuIds', fieldName: 'menuIds',
label: '权限', label: '权限',

View File

@ -23,21 +23,16 @@ const [Model, modelApi] = useVbenModal({
if (!valid) return; if (!valid) return;
const values = await formApi.getValues(); const values = await formApi.getValues();
const menuIds = formApi
.getFieldComponentRef('menuIds')
.getComponentRef()
.getIndeterminateData().keys;
modelApi.lock(); modelApi.lock();
(id.value (id.value
? updateRole({ ? updateRole({
id: id.value, id: id.value,
...values, ...values,
menuIds: [...values.menuIds, ...menuIds],
}) })
: createRole({ : createRole({
...values, ...values,
menuIds: [...values.menuIds, ...menuIds],
}) })
) )
.then(() => { .then(() => {

View File

@ -3,7 +3,15 @@ import { computed, onMounted, ref } from 'vue';
import { confirm, Page, useVbenModal } from '@vben/common-ui'; import { confirm, Page, useVbenModal } from '@vben/common-ui';
import { NButton, NSpace, NSwitch, NTag, useMessage } from 'naive-ui'; import {
Button as TButton,
Link as TLink,
Space as TSpace,
Switch as TSwitch,
Tag as TTag
} from 'tdesign-vue-next';
import { message } from '#/adapter/tdesign';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { changeRoleStatus, getAdminOptions, getRoleList } from '#/api'; import { changeRoleStatus, getAdminOptions, getRoleList } from '#/api';
@ -12,7 +20,6 @@ import { toObject } from '#/enum';
import { useGridSchema } from './data'; import { useGridSchema } from './data';
import Form from './form.vue'; import Form from './form.vue';
const message = useMessage();
// //
const [FormModel, formModelApi] = useVbenModal({ const [FormModel, formModelApi] = useVbenModal({
@ -75,14 +82,14 @@ onMounted(() => {
<Page auto-content-height> <Page auto-content-height>
<Grid table-title="角色列表"> <Grid table-title="角色列表">
<template #toolbar-tools> <template #toolbar-tools>
<NSpace> <TSpace>
<NButton type="primary" @click="addEvent">新增角色</NButton> <TButton theme="primary" @click="addEvent">新增角色</TButton>
<NButton @click="refresh">查询</NButton> <TButton @click="refresh">查询</TButton>
</NSpace> </TSpace>
</template> </template>
<template #status="{ row }"> <template #status="{ row }">
<NSwitch <TSwitch
:value="row.status" :value="row.status"
:checked-value="true" :checked-value="true"
:unchecked-value="false" :unchecked-value="false"
@ -91,17 +98,17 @@ onMounted(() => {
</template> </template>
<template #adminIds="{ row }"> <template #adminIds="{ row }">
<NSpace> <TSpace>
<NTag v-for="id in row.adminIds" :key="id"> <TTag v-for="id in row.adminIds" :key="id">
{{ adminOptionsMap[id] }} {{ adminOptionsMap[id] }}
</NTag> </TTag>
</NSpace> </TSpace>
</template> </template>
<template #actions="{ row }"> <template #actions="{ row }">
<NSpace> <TSpace>
<NButton text type="primary" @click="editEvent(row)">编辑</NButton> <TLink theme="primary" @click="editEvent(row)">编辑</TLink>
</NSpace> </TSpace>
</template> </template>
</Grid> </Grid>

View File

@ -12,8 +12,11 @@ export function useSubmitFormSchema(): VbenFormSchema[] {
componentProps: { componentProps: {
api: getPointOptions, api: getPointOptions,
clearable: true, clearable: true,
labelField: 'displayName', filterable: true,
valueField: 'id', keys: {
label: 'displayName',
value: 'id'
}
}, },
label: '监测点', label: '监测点',
rules: 'required', rules: 'required',
@ -101,6 +104,12 @@ export function useSubmitFormSchema(): VbenFormSchema[] {
}, },
label: '纬度', label: '纬度',
}, },
{
component: 'flows',
defaultValue: [],
fieldName: 'flows',
label: '同步密钥'
}
]; ];
} }
@ -119,13 +128,13 @@ export function useSearchFormSchema(): VbenFormSchema[] {
}, },
{ {
component: 'ApiSelect', component: 'ApiSelect',
fieldName: 'productId', fieldName: 'productIds',
componentProps: { componentProps: {
api: getProductOptions, api: getProductOptions,
clearable: true, clearable: true,
multiple: true, multiple: true,
}, },
label: '监测点', label: '设备类型',
}, },
{ {
component: 'ApiSelect', component: 'ApiSelect',
@ -148,17 +157,26 @@ export function useGridSchema() {
width: 120, width: 120,
fixed: 'left', fixed: 'left',
}, },
{
field: 'status',
title: '状态',
slots: { default: 'status' },
width: 120,
fixed: 'left',
},
{ {
field: 'pointId', field: 'pointId',
title: '点位名称', title: '点位名称',
slots: { default: 'pointId' }, slots: { default: 'pointId' },
width: 300, width: 300,
treeNode: true, align: 'left'
}, },
{ {
field: 'displayName', field: 'displayName',
title: '设备名称', title: '设备名称',
width: 150, width: 150,
treeNode: true,
align: 'left'
}, },
{ {
field: 'productId', field: 'productId',

View File

@ -1,4 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { nanoid } from 'nanoid'
import { computed, nextTick, ref } from 'vue'; import { computed, nextTick, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui'; import { useVbenModal } from '@vben/common-ui';
@ -8,6 +10,10 @@ import { createDevice, updateDevice } from '#/api/core/device';
import { useSubmitFormSchema } from './data'; import { useSubmitFormSchema } from './data';
import { SendHandlerEnum} from '#/enum/SendHandler'
import { Table as TTable, Button as TButton, Popconfirm as TPopconfirm, Link as TLink, Input as TInput, Select as TSelect, Space as TSpace} from 'tdesign-vue-next';
const emits = defineEmits(['success']); const emits = defineEmits(['success']);
const formData = ref(); const formData = ref();
@ -28,9 +34,11 @@ const [Model, modelApi] = useVbenModal({
? updateDevice({ ? updateDevice({
id: id.value, id: id.value,
...values, ...values,
flows: flows.value
}) })
: createDevice({ : createDevice({
...values, ...values,
flows: flows.value
}) })
) )
.then(() => { .then(() => {
@ -50,6 +58,7 @@ const [Model, modelApi] = useVbenModal({
if (data) { if (data) {
formData.value = data; formData.value = data;
id.value = data.id; id.value = data.id;
flows.value = JSON.parse(JSON.stringify(data.flows))
} else { } else {
id.value = undefined; id.value = undefined;
} }
@ -66,10 +75,77 @@ const [Model, modelApi] = useVbenModal({
const getDrawerTitle = computed(() => { const getDrawerTitle = computed(() => {
return formData.value?.id ? '编辑设备' : '新建设备'; return formData.value?.id ? '编辑设备' : '新建设备';
}); });
const flows = ref([])
const flowColumns = [
{
colKey: 'id',
title: '序号',
width: 100,
},
{
colKey: 'sendHandlerClass',
title: '同步平台',
width: 150,
},
{
colKey: 'syncKey',
title: '编码',
width: 150
},
{
colKey: 'syncSecret',
title: '密钥',
width: 150
},
{
colKey: 'actions',
title: '操作',
width: 100,
},
];
const addRecord = () =>{
const lastItem = flows[flows.length-1]
flows.value.push({
id: `temp_${nanoid()}`,
sendHandlerClass: '',
syncKey: '',
syncSecret: '',
})
}
const delRecord = (index) =>{
flows.value.splice(index,1)
}
</script> </script>
<template> <template>
<Model :title="getDrawerTitle"> <Model :title="getDrawerTitle" class="w-[1000px]">
<Form /> <Form>
<template #flows>
<TSpace direction="vertical">
<TButton theme="primary" @click="addRecord" class="float-right">增加记录</TButton>
<TTable bordered row-key="id" :columns="flowColumns" :data="flows" layout="fixed">
<template #syncKey="{ row }">
<TInput v-model="row.syncKey" clearable> </TInput>
</template>
<template #syncSecret="{ row }">
<TInput v-model="row.syncSecret" clearable> </TInput>
</template>
<template #sendHandlerClass="{ row }">
<TSelect v-model="row.sendHandlerClass" clearable :options="SendHandlerEnum"> </TSelect>
</template>
<template #actions="{ rowIndex }">
<TPopconfirm theme="danger" content="确认删除?" @confirm="delRecord(rowIndex)">
<TLink theme="danger"> 删除</TLink>
</TPopconfirm>
</template>
</TTable>
</TSpace>
</template>
</Form>
</Model> </Model>
</template> </template>
<style scoped></style> <style scoped></style>

View File

@ -4,7 +4,16 @@ import { useRoute } from 'vue-router';
import { Page, useVbenModal } from '@vben/common-ui'; import { Page, useVbenModal } from '@vben/common-ui';
import { NButton, NSpace } from 'naive-ui';
import {
Button as TButton,
Link as TLink,
Space as TSpace,
Switch as TSwitch,
Tag as TTag
} from 'tdesign-vue-next';
import { message } from '#/adapter/tdesign';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getDeviceListByPage } from '#/api/core/device'; import { getDeviceListByPage } from '#/api/core/device';
@ -83,7 +92,6 @@ const editEvent = (row) => {
.open(); .open();
}; };
const onRefresh = () => { const onRefresh = () => {
GridApi.formApi.getFieldComponentRef('cardId')?.fetchApi();
GridApi.reload(); GridApi.reload();
}; };
@ -116,12 +124,18 @@ onMounted(() => {
<template> <template>
<Page auto-content-height> <Page auto-content-height>
<Grid table-title="监测点列表"> <Grid table-title="设备列表">
<template #toolbar-tools> <template #toolbar-tools>
<NButton class="mr-2" type="primary" @click="addEvent"> <TButton class="mr-2" theme="primary" @click="addEvent">
新增设备 新增设备
</NButton> </TButton>
</template> </template>
<template #status="{ row }">
<TTag :theme="row.status ? 'success' : 'danger'">
{{ row.status ? '在线':'离线' }}
</TTag>
</template>
<template #pointId="{ row }"> <template #pointId="{ row }">
{{ pointOptionsMap[row.pointId] }} {{ pointOptionsMap[row.pointId] }}
</template> </template>
@ -135,12 +149,12 @@ onMounted(() => {
</template> </template>
<template #actions="{ row }"> <template #actions="{ row }">
<NSpace> <TSpace>
<NButton text type="primary" @click="editEvent(row)">编辑</NButton> <TLink theme="primary" @click="editEvent(row)">编辑</TLink>
<NButton text type="primary" @click="addChildEvent(row)"> <TLink theme="primary" @click="addChildEvent(row)">
增加子设备 增加子设备
</NButton> </TLink>
</NSpace> </TSpace>
</template> </template>
</Grid> </Grid>

View File

@ -10,8 +10,11 @@ export function useSubmitFormSchema(): VbenFormSchema[] {
component: 'Cascader', component: 'Cascader',
componentProps: { componentProps: {
options: useCascaderAreaData(), options: useCascaderAreaData(),
labelField: 'text', keys:{
valueField: 'value', label: 'text',
value: 'value',
},
checkStrictly: true,
filterable: true, filterable: true,
clearable: true, clearable: true,
placeholder: '请选择行政区划', placeholder: '请选择行政区划',
@ -85,7 +88,8 @@ export function useGridSchema() {
field: 'displayName', field: 'displayName',
title: '点位名称', title: '点位名称',
slots: { default: 'displayName' }, slots: { default: 'displayName' },
width: 120, width: 350,
align: 'left'
}, },
{ {
field: 'locationName', field: 'locationName',

View File

@ -3,7 +3,15 @@ import { computed } from 'vue';
import { Page, useVbenModal } from '@vben/common-ui'; import { Page, useVbenModal } from '@vben/common-ui';
import { NButton, NSpace, NTag } from 'naive-ui'; import {
Button as TButton,
Link as TLink,
Space as TSpace,
Switch as TSwitch,
Tag as TTag
} from 'tdesign-vue-next';
import { message } from '#/adapter/tdesign';
import { useVbenVxeGrid } from '#/adapter/vxe-table'; import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { getPointListByPage } from '#/api'; import { getPointListByPage } from '#/api';
@ -83,28 +91,28 @@ const jumpToDevice = (row: any) => {
<Page auto-content-height> <Page auto-content-height>
<Grid table-title="监测点列表"> <Grid table-title="监测点列表">
<template #toolbar-tools> <template #toolbar-tools>
<NButton class="mr-2" type="primary" @click="addEvent"> <TButton class="mr-2" theme="primary" @click="addEvent">
新增监测点 新增监测点
</NButton> </TButton>
</template> </template>
<template #displayName="{ row }"> <template #displayName="{ row }">
<NButton type="primary" text @click="jumpToDevice(row)"> <TLink theme="primary" @click="jumpToDevice(row)">
{{ row.displayName }} {{ row.displayName }}
</NButton> </TLink>
</template> </template>
<template #deptIds="{ row }"> <template #deptIds="{ row }">
<NSpace> <TSpace>
<NTag v-for="id in row.deptIds" :key="id"> <TTag v-for="id in row.deptIds" :key="id">
{{ deptOptionsMap[id] }} {{ deptOptionsMap[id] }}
</NTag> </TTag>
</NSpace> </TSpace>
</template> </template>
<template #actions="{ row }"> <template #actions="{ row }">
<NSpace> <TSpace>
<NButton text type="primary" @click="editEvent(row)">编辑</NButton> <TLink theme="primary" @click="editEvent(row)">编辑</TLink>
</NSpace> </TSpace>
</template> </template>
</Grid> </Grid>

View File

@ -10,10 +10,11 @@ export default defineConfig(async () => {
changeOrigin: true, changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''), rewrite: (path) => path.replace(/^\/api/, ''),
// mock代理目标地址 // mock代理目标地址
target: 'http://localhost:7901/api', target: 'https://bm4289e5zy-7901.cnb.run/api',
ws: true, ws: true,
}, },
}, },
allowedHosts: ['ixpgm1rtma-6000.cnb.run']
}, },
}, },
}; };

View File

@ -336,7 +336,7 @@ function handleClosed() {
<component <component
:is="components.DefaultButton || VbenButton" :is="components.DefaultButton || VbenButton"
v-if="showCancelButton" v-if="showCancelButton"
variant="ghost" variant="outline"
:disabled="submitting" :disabled="submitting"
@click="() => modalApi?.onCancel()" @click="() => modalApi?.onCancel()"
> >

View File

@ -576,10 +576,10 @@ importers:
version: link:scripts/vsh version: link:scripts/vsh
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: 'catalog:' specifier: 'catalog:'
version: 6.0.1(vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.23(typescript@5.9.3)) version: 6.0.1(vite@7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.23(typescript@5.9.3))
'@vitejs/plugin-vue-jsx': '@vitejs/plugin-vue-jsx':
specifier: 'catalog:' specifier: 'catalog:'
version: 5.1.1(vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.23(typescript@5.9.3)) version: 5.1.1(vite@7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.23(typescript@5.9.3))
'@vue/test-utils': '@vue/test-utils':
specifier: 'catalog:' specifier: 'catalog:'
version: 2.4.6 version: 2.4.6
@ -621,10 +621,10 @@ importers:
version: 3.6.1(sass@1.93.3)(typescript@5.9.3)(vue-tsc@2.2.10(typescript@5.9.3))(vue@3.5.23(typescript@5.9.3)) version: 3.6.1(sass@1.93.3)(typescript@5.9.3)(vue-tsc@2.2.10(typescript@5.9.3))(vue@3.5.23(typescript@5.9.3))
vite: vite:
specifier: 'catalog:' specifier: 'catalog:'
version: 7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1) version: 7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)
vitest: vitest:
specifier: 'catalog:' specifier: 'catalog:'
version: 3.2.4(@types/node@24.10.0)(happy-dom@17.6.3)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1) version: 3.2.4(@types/node@24.10.0)(happy-dom@17.6.3)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)
vue: vue:
specifier: ^3.5.17 specifier: ^3.5.17
version: 3.5.23(typescript@5.9.3) version: 3.5.23(typescript@5.9.3)
@ -843,6 +843,9 @@ importers:
apps/web-tdesign: apps/web-tdesign:
dependencies: dependencies:
'@vant/area-data':
specifier: ^2.1.0
version: 2.1.0
'@vben/access': '@vben/access':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/effects/access version: link:../../packages/effects/access
@ -894,6 +897,9 @@ importers:
lodash-es: lodash-es:
specifier: ^4.17.21 specifier: ^4.17.21
version: 4.17.21 version: 4.17.21
nanoid:
specifier: ^5.1.6
version: 5.1.6
pinia: pinia:
specifier: ^3.0.3 specifier: ^3.0.3
version: 3.0.4(typescript@5.9.3)(vue@3.5.23(typescript@5.9.3)) version: 3.0.4(typescript@5.9.3)(vue@3.5.23(typescript@5.9.3))
@ -4731,6 +4737,9 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@vant/area-data@2.1.0':
resolution: {integrity: sha512-wx9PrUX7wSUJiFcz8UrcvZfTjV6sTc+7SHcbjGQQzEcv5y+EwOo5uV4ZKdfrR5Hzcw4MA08LQdvXPSEb4nWbug==}
'@vee-validate/zod@4.15.1': '@vee-validate/zod@4.15.1':
resolution: {integrity: sha512-329Z4TDBE5Vx0FdbA8S4eR9iGCFFUNGbxjpQ20ff5b5wGueScjocUIx9JHPa79LTG06RnlUR4XogQsjN4tecKA==} resolution: {integrity: sha512-329Z4TDBE5Vx0FdbA8S4eR9iGCFFUNGbxjpQ20ff5b5wGueScjocUIx9JHPa79LTG06RnlUR4XogQsjN4tecKA==}
peerDependencies: peerDependencies:
@ -13846,6 +13855,8 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.11.1': '@unrs/resolver-binding-win32-x64-msvc@1.11.1':
optional: true optional: true
'@vant/area-data@2.1.0': {}
'@vee-validate/zod@4.15.1(vue@3.5.23(typescript@5.9.3))(zod@3.25.76)': '@vee-validate/zod@4.15.1(vue@3.5.23(typescript@5.9.3))(zod@3.25.76)':
dependencies: dependencies:
type-fest: 4.41.0 type-fest: 4.41.0
@ -13877,6 +13888,18 @@ snapshots:
dependencies: dependencies:
vite-plugin-pwa: 1.1.0(vite@5.4.21(@types/node@24.10.0)(less@4.4.2)(sass@1.93.3)(terser@5.44.1))(workbox-build@7.3.0)(workbox-window@7.3.0) vite-plugin-pwa: 1.1.0(vite@5.4.21(@types/node@24.10.0)(less@4.4.2)(sass@1.93.3)(terser@5.44.1))(workbox-build@7.3.0)(workbox-window@7.3.0)
'@vitejs/plugin-vue-jsx@5.1.1(vite@7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.23(typescript@5.9.3))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5)
'@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5)
'@rolldown/pluginutils': 1.0.0-beta.47
'@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.5)
vite: 7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)
vue: 3.5.23(typescript@5.9.3)
transitivePeerDependencies:
- supports-color
'@vitejs/plugin-vue-jsx@5.1.1(vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.23(typescript@5.9.3))': '@vitejs/plugin-vue-jsx@5.1.1(vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.23(typescript@5.9.3))':
dependencies: dependencies:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
@ -13894,6 +13917,12 @@ snapshots:
vite: 5.4.21(@types/node@24.10.0)(less@4.4.2)(sass@1.93.3)(terser@5.44.1) vite: 5.4.21(@types/node@24.10.0)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)
vue: 3.5.23(typescript@5.9.3) vue: 3.5.23(typescript@5.9.3)
'@vitejs/plugin-vue@6.0.1(vite@7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.23(typescript@5.9.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.29
vite: 7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)
vue: 3.5.23(typescript@5.9.3)
'@vitejs/plugin-vue@6.0.1(vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.23(typescript@5.9.3))': '@vitejs/plugin-vue@6.0.1(vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))(vue@3.5.23(typescript@5.9.3))':
dependencies: dependencies:
'@rolldown/pluginutils': 1.0.0-beta.29 '@rolldown/pluginutils': 1.0.0-beta.29
@ -13908,13 +13937,13 @@ snapshots:
chai: 5.3.3 chai: 5.3.3
tinyrainbow: 2.0.0 tinyrainbow: 2.0.0
'@vitest/mocker@3.2.4(vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))': '@vitest/mocker@3.2.4(vite@7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))':
dependencies: dependencies:
'@vitest/spy': 3.2.4 '@vitest/spy': 3.2.4
estree-walker: 3.0.3 estree-walker: 3.0.3
magic-string: 0.30.21 magic-string: 0.30.21
optionalDependencies: optionalDependencies:
vite: 7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1) vite: 7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)
'@vitest/pretty-format@3.2.4': '@vitest/pretty-format@3.2.4':
dependencies: dependencies:
@ -19839,6 +19868,27 @@ snapshots:
dependencies: dependencies:
vite: 7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1) vite: 7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)
vite-node@3.2.4(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1):
dependencies:
cac: 6.7.14
debug: 4.4.3
es-module-lexer: 1.7.0
pathe: 2.0.3
vite: 7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)
transitivePeerDependencies:
- '@types/node'
- jiti
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
- tsx
- yaml
vite-node@3.2.4(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1): vite-node@3.2.4(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1):
dependencies: dependencies:
cac: 6.7.14 cac: 6.7.14
@ -19859,6 +19909,7 @@ snapshots:
- terser - terser
- tsx - tsx
- yaml - yaml
optional: true
vite-plugin-compression@0.5.1(vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)): vite-plugin-compression@0.5.1(vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)):
dependencies: dependencies:
@ -19992,6 +20043,23 @@ snapshots:
sass: 1.93.3 sass: 1.93.3
terser: 5.44.1 terser: 5.44.1
vite@7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1):
dependencies:
esbuild: 0.25.3
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
rollup: 4.52.5
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.0
fsevents: 2.3.3
jiti: 1.21.7
less: 4.4.2
sass: 1.93.3
terser: 5.44.1
yaml: 2.8.1
vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1): vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1):
dependencies: dependencies:
esbuild: 0.25.3 esbuild: 0.25.3
@ -20068,11 +20136,53 @@ snapshots:
- typescript - typescript
- universal-cookie - universal-cookie
vitest@3.2.4(@types/node@24.10.0)(happy-dom@17.6.3)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1):
dependencies:
'@types/chai': 5.2.3
'@vitest/expect': 3.2.4
'@vitest/mocker': 3.2.4(vite@7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
'@vitest/spy': 3.2.4
'@vitest/utils': 3.2.4
chai: 5.3.3
debug: 4.4.3
expect-type: 1.2.2
magic-string: 0.30.21
pathe: 2.0.3
picomatch: 4.0.3
std-env: 3.10.0
tinybench: 2.9.0
tinyexec: 0.3.2
tinyglobby: 0.2.15
tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)
vite-node: 3.2.4(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 24.10.0
happy-dom: 17.6.3
transitivePeerDependencies:
- jiti
- less
- lightningcss
- msw
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
- tsx
- yaml
vitest@3.2.4(@types/node@24.10.0)(happy-dom@17.6.3)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1): vitest@3.2.4(@types/node@24.10.0)(happy-dom@17.6.3)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1):
dependencies: dependencies:
'@types/chai': 5.2.3 '@types/chai': 5.2.3
'@vitest/expect': 3.2.4 '@vitest/expect': 3.2.4
'@vitest/mocker': 3.2.4(vite@7.2.1(@types/node@24.10.0)(jiti@2.6.1)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1)) '@vitest/mocker': 3.2.4(vite@7.2.1(@types/node@24.10.0)(jiti@1.21.7)(less@4.4.2)(sass@1.93.3)(terser@5.44.1)(yaml@2.8.1))
'@vitest/pretty-format': 3.2.4 '@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4 '@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4 '@vitest/snapshot': 3.2.4
@ -20109,6 +20219,7 @@ snapshots:
- terser - terser
- tsx - tsx
- yaml - yaml
optional: true
vooks@0.2.12(vue@3.5.23(typescript@5.9.3)): vooks@0.2.12(vue@3.5.23(typescript@5.9.3)):
dependencies: dependencies: