|
|
@@ -0,0 +1,358 @@
|
|
|
+<template>
|
|
|
+
|
|
|
+<a-row :gutter="[8, 8]" >
|
|
|
+ <a-col :span="4" >
|
|
|
+ <a-card title="分组" style="height: 100%;" >
|
|
|
+ <template #extra >
|
|
|
+ <a-button type="primary" @click="state.groupVisible = true" >添加分组</a-button>
|
|
|
+ </template>
|
|
|
+ <a-tree
|
|
|
+ v-model:expandedKeys="expandedKeys"
|
|
|
+ v-model:selectedKeys="state.treeActiveKey"
|
|
|
+ :tree-data="state.groupList"
|
|
|
+ defaultExpandAll
|
|
|
+ autoExpandParent
|
|
|
+ :field-names="{
|
|
|
+ key: 'id',
|
|
|
+ title: 'groupName',
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <template #title="record">
|
|
|
+ <a-space @click="changeTreeActiveKey(record.key)" >
|
|
|
+ <div class="group-label" > {{ record.groupName }} </div>
|
|
|
+ <template v-if="state.treeActiveKey[0] === record.id && record.id" >
|
|
|
+ <plus-circle-outlined @click="openGroupModal('add', record)"/>
|
|
|
+ <!-- <delete-outlined @click="openGroupModal('del', record)"/> -->
|
|
|
+ </template>
|
|
|
+ </a-space>
|
|
|
+ </template>
|
|
|
+ </a-tree>
|
|
|
+ </a-card>
|
|
|
+ </a-col>
|
|
|
+ <a-col :span="20">
|
|
|
+ <a-card
|
|
|
+ :tab-list="tabList"
|
|
|
+ style="height: 100%;"
|
|
|
+ :active-tab-key="tabKey"
|
|
|
+ @tabChange="onChangeTab"
|
|
|
+ >
|
|
|
+ <table-pro
|
|
|
+ :service="serviceMap!.service"
|
|
|
+ :serviceParams="{[serviceMap!.paramsKey!.name]: searchName}"
|
|
|
+ :columns="serviceMap?.columns"
|
|
|
+ @add="openModal"
|
|
|
+ ref="tableProDom"
|
|
|
+ >
|
|
|
+ <template #search >
|
|
|
+ <a-space>
|
|
|
+ <input-tsx v-model:value="searchName" :placeholder="serviceMap!.placeholder" />
|
|
|
+ <a-button type="primary" @click="search" >搜索</a-button>
|
|
|
+ </a-space>
|
|
|
+ </template>
|
|
|
+ <template #render="{column, record}" >
|
|
|
+ <template v-if="column.key === 'sex'" >
|
|
|
+ <a-tag :color="record.sex === 0 ? 'pink' : record.sex === 1 ? 'blue' : 'grey'" >{{record.sex === 0 ? '女' : record.sex === 1 ? '男' : '其他'}}</a-tag>
|
|
|
+ </template>
|
|
|
+ <template v-if="column.key === 'carUrl'" > <a-image :width="86" :src="record.carUrl"/> </template>
|
|
|
+ <template v-if="column.key === 'faceUrl'" > <a-image :width="86" :src="record.faceUrl"/> </template>
|
|
|
+ <template v-if="column.key === 'frockUrl'" > <a-image :width="86" :src="record.frockUrl"/> </template>
|
|
|
+ <template v-if="column.key === 'action'" >
|
|
|
+ <a @click="delData(record)" >删除</a>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </table-pro>
|
|
|
+ </a-card>
|
|
|
+ </a-col>
|
|
|
+</a-row>
|
|
|
+
|
|
|
+<modal-pro
|
|
|
+ width="700px"
|
|
|
+ :title="serviceMap?.title"
|
|
|
+ :open="state.visible"
|
|
|
+ @cancel="closeModal"
|
|
|
+ @ok="submit"
|
|
|
+>
|
|
|
+ <a-form style="width: 100%;" :labelCol="{span: 3}" :wrapperCol="{span: 14}" >
|
|
|
+ <a-form-item label="名称" v-bind="validateInfos.name" >
|
|
|
+ <InputTsx allowClear placeholder="请输入名称" v-model:value="formState.name" />
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="性别" v-if="tabKey === 'face'" >
|
|
|
+ <a-radio-group v-model:value="formState.sex" button-style="solid">
|
|
|
+ <a-radio-button :value="0">女</a-radio-button>
|
|
|
+ <a-radio-button :value="1">男</a-radio-button>
|
|
|
+ <a-radio-button :value="2">其他</a-radio-button>
|
|
|
+ </a-radio-group>
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="图片" v-bind="validateInfos.url">
|
|
|
+ <UploadPro action="/cvss/file/upload" accept=".png,.jpg,.jpeg" @done="uploadDone" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-form>
|
|
|
+</modal-pro>
|
|
|
+
|
|
|
+ <modal-pro
|
|
|
+ width="700px"
|
|
|
+ title='创建分组'
|
|
|
+ :open="state.groupVisible"
|
|
|
+ @cancel="state.groupVisible = false"
|
|
|
+ @ok="addGroup"
|
|
|
+ >
|
|
|
+ <a-form style="width: 100%;" :labelCol="{span: 3}" :wrapperCol="{span: 14}" >
|
|
|
+ <a-form-item label="群组名称" v-bind="groupValidateInfos.groupName" >
|
|
|
+ <InputTsx allowClear placeholder="请输入设备名称" v-model:value="groupState.groupName" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-form>
|
|
|
+ </modal-pro>
|
|
|
+</template>
|
|
|
+<script lang='ts' setup >
|
|
|
+import { FeatureController } from '@/controller'
|
|
|
+import { computed, nextTick, onMounted, reactive, ref, toRef, toRefs } from 'vue'
|
|
|
+import { InputTsx } from '@/components/MicroComponents'
|
|
|
+import { Form } from 'ant-design-vue'
|
|
|
+import UploadPro from '@/components/UploadPro/index'
|
|
|
+import { PlusCircleOutlined } from '@ant-design/icons-vue'
|
|
|
+
|
|
|
+const tabList = [{ key: 'car', tab: '车辆库' }, { key: 'face', tab: '人脸库' }, { key: 'frock', tab: '工装库' }]
|
|
|
+
|
|
|
+const tabKey = ref('car')
|
|
|
+
|
|
|
+const carColumns = [
|
|
|
+ {
|
|
|
+ title: '车辆ID',
|
|
|
+ dataIndex: 'id',
|
|
|
+ key: 'id'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '车牌号',
|
|
|
+ dataIndex: 'carNo',
|
|
|
+ key: 'carNo'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '车辆图片',
|
|
|
+ dataIndex: 'carUrl',
|
|
|
+ key: 'carUrl'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ dataIndex: 'action',
|
|
|
+ key: 'action'
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+const faceColumns = [
|
|
|
+ {
|
|
|
+ title: '人脸ID',
|
|
|
+ dataIndex: 'id',
|
|
|
+ key: 'id'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '人脸名称',
|
|
|
+ dataIndex: 'faceName',
|
|
|
+ key: 'faceName'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '性别',
|
|
|
+ dataIndex: 'sex',
|
|
|
+ key: 'sex'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '人脸图片',
|
|
|
+ dataIndex: 'faceUrl',
|
|
|
+ key: 'faceUrl'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ dataIndex: 'action',
|
|
|
+ key: 'action'
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+const frockColumns = [
|
|
|
+ {
|
|
|
+ title: '工装ID',
|
|
|
+ dataIndex: 'id',
|
|
|
+ key: 'id'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '工装名称',
|
|
|
+ dataIndex: 'faceName',
|
|
|
+ key: 'faceName'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '工装图片',
|
|
|
+ dataIndex: 'frockUrl',
|
|
|
+ key: 'frockUrl'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ dataIndex: 'action',
|
|
|
+ key: 'action'
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+const useForm = Form.useForm
|
|
|
+
|
|
|
+const searchName = ref('')
|
|
|
+
|
|
|
+const tableProDom = ref()
|
|
|
+
|
|
|
+const state = reactive<{
|
|
|
+ visible: boolean,
|
|
|
+ groupVisible: boolean,
|
|
|
+ groupList: CVS.Feature.Group[]
|
|
|
+ treeActiveKey: number[]
|
|
|
+}>({
|
|
|
+ visible: false,
|
|
|
+ groupVisible: false,
|
|
|
+ groupList: [],
|
|
|
+ treeActiveKey: [0]
|
|
|
+})
|
|
|
+
|
|
|
+const expandedKeys = ref<string[]>([])
|
|
|
+
|
|
|
+const groupState = reactive({
|
|
|
+ groupName: '',
|
|
|
+ upGroupId: 0,
|
|
|
+ key: ''
|
|
|
+})
|
|
|
+
|
|
|
+const dataMap = new Map([
|
|
|
+ ['car', { placeholder: '请输入车牌号', service: FeatureController.carPage, paramsKey: { name: 'carNo', url: 'carUrl' }, columns: carColumns, title: '创建车辆', post: FeatureController.addCar, del: FeatureController.delCarById }],
|
|
|
+ ['face', { placeholder: '请输入人脸名称', service: FeatureController.facePage, paramsKey: { name: 'faceName', url: 'faceUrl' }, columns: faceColumns, title: '创建人脸', post: FeatureController.addFace, del: FeatureController.delFaceById }],
|
|
|
+ ['frock', { placeholder: '请输入工装名称', service: FeatureController.frockPage, paramsKey: { name: 'frockName', url: 'frockUrl' }, columns: frockColumns, title: '创建工装', post: FeatureController.addFrock, del: FeatureController.delFrockById }]
|
|
|
+])
|
|
|
+
|
|
|
+const serviceMap = computed(() => dataMap.get(tabKey.value))
|
|
|
+
|
|
|
+const formState = reactive({
|
|
|
+ sex: 0,
|
|
|
+ name: '',
|
|
|
+ url: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F26a3b3c9-1833-4385-a294-8d4f12afacd6%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1704166834&t=dbe51dba1f1fb8c6536e6dfa5337b0e7'
|
|
|
+})
|
|
|
+
|
|
|
+const { resetFields, validate, validateInfos } = useForm(formState, {
|
|
|
+ name: [{ required: true, message: '请填写' }],
|
|
|
+ url: [{ required: true, message: '请上传' }]
|
|
|
+})
|
|
|
+
|
|
|
+const { resetFields: groupResetFields, validate: groupValidate, validateInfos: groupValidateInfos } = useForm(groupState, {
|
|
|
+ groupName: [{ required: true, message: '请填写群组名称' }]
|
|
|
+})
|
|
|
+
|
|
|
+const delData = async (record) => {
|
|
|
+ await serviceMap.value?.del(record.id)
|
|
|
+ tableProDom.value.reload()
|
|
|
+}
|
|
|
+
|
|
|
+const onChangeTab = (key) => {
|
|
|
+ tabKey.value = key
|
|
|
+ nextTick(() => {
|
|
|
+ tableProDom.value.reload({ page: 0 })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const changeTreeActiveKey = (id: string, e?: TouchEvent) => {
|
|
|
+ e && e.stopPropagation && e.stopPropagation()
|
|
|
+ state.treeActiveKey[0] = id
|
|
|
+ console.log(state.treeActiveKey)
|
|
|
+ getGroupList()
|
|
|
+ tableProDom.value.reload({ page: 0 })
|
|
|
+// state.groupList = state.groupList.find(item => item.upGroupId === state.treeActiveKey)
|
|
|
+}
|
|
|
+
|
|
|
+const uploadDone = (url: string) => {
|
|
|
+ console.log(url)
|
|
|
+}
|
|
|
+
|
|
|
+const submit = () => {
|
|
|
+ validate().then(async () => {
|
|
|
+ await serviceMap.value?.post({
|
|
|
+ ...{
|
|
|
+ [serviceMap.value.paramsKey.name]: formState.name,
|
|
|
+ [serviceMap.value.paramsKey.url]: formState.url,
|
|
|
+ sex: formState.sex
|
|
|
+ },
|
|
|
+ groupId: state.treeActiveKey[0]
|
|
|
+ })
|
|
|
+ closeModal()
|
|
|
+ tableProDom.value.reload()
|
|
|
+ }).catch(() => {})
|
|
|
+}
|
|
|
+
|
|
|
+const openModal = () => {
|
|
|
+ resetFields({})
|
|
|
+ state.visible = true
|
|
|
+}
|
|
|
+
|
|
|
+const closeModal = () => state.visible = false
|
|
|
+
|
|
|
+const search = () => tableProDom.value.reload()
|
|
|
+
|
|
|
+const addGroup = () => {
|
|
|
+ groupValidate().then(async () => {
|
|
|
+ await FeatureController.addGroup(groupState)
|
|
|
+ state.groupVisible = false
|
|
|
+ getGroupList()
|
|
|
+ }).catch(() => {})
|
|
|
+}
|
|
|
+
|
|
|
+interface TreeNode {
|
|
|
+ id: string;
|
|
|
+ createAt: number;
|
|
|
+ updateAt: number | null;
|
|
|
+ deleted: boolean;
|
|
|
+ groupName: string;
|
|
|
+ upGroupId: string;
|
|
|
+ tenantId: string;
|
|
|
+ children?: TreeNode[];
|
|
|
+}
|
|
|
+
|
|
|
+function buildTree (data: TreeNode[], upGroupId: string): TreeNode[] {
|
|
|
+ const tree: TreeNode[] = []
|
|
|
+ for (const node of data) {
|
|
|
+ if (node.upGroupId === upGroupId) {
|
|
|
+ const children = buildTree(data, node.id)
|
|
|
+ if (children.length) {
|
|
|
+ node.children = children
|
|
|
+ }
|
|
|
+ tree.push({
|
|
|
+ ...node,
|
|
|
+ key: node.id,
|
|
|
+ hasChildren: !!node.children?.length
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return tree
|
|
|
+}
|
|
|
+
|
|
|
+const openGroupModal = (type: 'add', record) => {
|
|
|
+ console.log('record:', record)
|
|
|
+
|
|
|
+ groupState.groupName = ''
|
|
|
+ groupState.upGroupId = ''
|
|
|
+ state.groupVisible = true
|
|
|
+ groupState.upGroupId = record.upGroupId
|
|
|
+}
|
|
|
+
|
|
|
+const getGroupList = async () => {
|
|
|
+ const data = await FeatureController.groupList()
|
|
|
+ state.groupList = [
|
|
|
+ {
|
|
|
+ groupName: '所有分组',
|
|
|
+ key: '',
|
|
|
+ id: '',
|
|
|
+ children: buildTree(data, 0)
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ expandedKeys.value = state.groupList[0].children.map(item => item.id)
|
|
|
+ console.log('expandedKeys.value[0].id:', expandedKeys.value[0])
|
|
|
+
|
|
|
+ state.treeActiveKey[0] = expandedKeys.value[0]
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ getGroupList()
|
|
|
+})
|
|
|
+
|
|
|
+</script>
|
|
|
+<style lang='less' scoped >
|
|
|
+</style>
|