lvkun 2 лет назад
Родитель
Сommit
b38d1dabbe

+ 84 - 0
Artwork.cpp

@@ -0,0 +1,84 @@
+#include <iostream>
+#include <vector>
+#include <string>
+
+class Artwork {
+public:
+    Artwork(const std::string& author, const std::string& title, int birthYear, const std::string& category)
+        : author(author), title(title), birthYear(birthYear), category(category) {}
+
+    virtual void displayInfo() const {
+        std::cout << "Author: " << author << ", Title: " << title << ", Birth Year: " << birthYear << ", Category: " << category;
+    }
+
+    virtual ~Artwork() = default;
+
+private:
+    std::string author;
+    std::string title;
+    int birthYear;
+    std::string category;
+};
+
+class Painting : public Artwork {
+public:
+    Painting(const std::string& author, const std::string& title, int birthYear, const std::string& category, const std::string& size)
+        : Artwork(author, title, birthYear, category), size(size) {}
+
+    void displayInfo() const override {
+        Artwork::displayInfo();
+        std::cout << ", Size: " << size;
+    }
+
+private:
+    std::string size;
+};
+
+class Music : public Artwork {
+public:
+    Music(const std::string& author, const std::string& title, int birthYear, const std::string& category, const std::string& content)
+        : Artwork(author, title, birthYear, category), content(content) {}
+
+    void displayInfo() const override {
+        Artwork::displayInfo();
+        std::cout << ", Content: " << content;
+    }
+
+private:
+    std::string content;
+};
+
+class Chamber : public Music {
+public:
+    Chamber(const std::string& author, const std::string& title, int birthYear, const std::string& content, int numPerformers)
+        : Music(author, title, birthYear, "Chamber", content), numPerformers(numPerformers) {}
+
+    void displayInfo() const override {
+        Music::displayInfo();
+        std::cout << ", Number of Performers: " << numPerformers;
+    }
+
+private:
+    int numPerformers;
+};
+
+int main() {
+    std::vector<Artwork*> artworks;
+
+    artworks.push_back(new Painting("Artist", "Painting", 2020, "Painting", "30x40"));
+    artworks.push_back(new Music("Composer", "Music", 2021, "Music", "Symphony"));
+    artworks.push_back(new Chamber("Composer", "Chamber", 2022, "Quartet", 4));
+
+
+    for (const auto& artwork : artworks) {
+        artwork->displayInfo();
+        std::cout << std::endl;
+    }
+
+  
+    for (const auto& artwork : artworks) {
+        delete artwork;
+    }
+
+    return 0;
+}

+ 29 - 0
src/api/cvs/feature.ts

@@ -89,3 +89,32 @@ export const delFrockById = (id: string) => {
     method: 'DELETE'
   })
 }
+
+export const groupList = () => {
+  return request<CVS.Feature.Group[]>({
+    url: '/featureGroup/list',
+    method: 'GET'
+  })
+}
+
+export const addGroup = (data: CVS.Feature.Group) => {
+  return request<string>({
+    url: '/featureGroup',
+    method: 'POST',
+    data
+  })
+}
+
+export const uploadFile = ({
+  file,
+  type
+}: {
+  file: string,
+  type: 'FACE' | 'CAR' | 'FROCK' | 'MODEL' | ''
+}) => {
+  return request<string>({
+    url: '/file/upload',
+    method: 'POST',
+    data: { file, type }
+  })
+}

+ 8 - 0
src/api/cvs/operator.ts

@@ -31,6 +31,14 @@ export const delOperatorById = (aiId: string) => {
   })
 }
 
+export const addOperator = (data: CVS.Operator) => {
+  return request<string>({
+    url: '/model',
+    method: 'POST',
+    data
+  })
+}
+
 export const updateOperatorName = (aiId: string, aiName: string) => {
   return request<string>({
     url: `/model/aiName?aiId=${aiId}&aiName=${aiName}`,

+ 8 - 6
src/components/TableProV2/index.tsx

@@ -5,7 +5,8 @@ import {
 import { DownOutlined } from '@ant-design/icons-vue'
 import {
   PropType, computed, defineComponent, reactive, ref, defineEmits, FunctionalComponent,
-  onMounted
+  onMounted,
+  toRefs
 } from 'vue'
 
 /**
@@ -174,13 +175,13 @@ const TablePro = defineComponent({
   },
   emits: ['add'],
   setup (props, ctx) {
-    const { columns, service, pagination, serviceParams } = props
+    const { columns, service, pagination, serviceParams } = toRefs(props)
 
     const loading = ref<boolean>(false)
 
     const paginationRef = ref({
       current: 1,
-      pageSize: pagination.pageSize ? pagination.pageSize : 10,
+      pageSize: pagination.value.pageSize ? pagination.value.pageSize : 10,
       total: 0
     })
 
@@ -190,12 +191,13 @@ const TablePro = defineComponent({
       if (params?.page) {
         paginationRef.value.current = params.page
       }
+      console.log('service:', service)
       dispatchRequest()
     }
     const dispatchRequest = async () => {
       loading.value = true
-      const { data, sum } = await service({
-        ...serviceParams,
+      const { data, sum } = await service.value({
+        ...serviceParams.value,
         page: paginationRef.value.current,
         pageSize: paginationRef.value.pageSize
       })
@@ -246,7 +248,7 @@ const TablePro = defineComponent({
         <Col span={24} >
           <Table
             style={{ marginTop: '20px' }}
-            columns={columns}
+            columns={columns.value}
             loading={loading.value}
             pagination={{ ...paginationRef.value, onChange: onChangePage }}
             dataSource={dataSource.value}

+ 1 - 0
src/components/UploadPro/index.tsx

@@ -43,6 +43,7 @@ export default defineComponent({
               accept={props.accept}
               value="fileList"
               name="file"
+              data={{ type: 'CAR' }}
               action={props.action}
               onChange={handleChange}
               maxCount={1}

+ 12 - 1
src/controller/cvs/featureController.ts

@@ -1,4 +1,4 @@
-import { addCar, addFace, addFrock, delCarById, delFaceById, delFrockById, getCarById, getCarPage, getFaceById, getFacePage, getFrockById, getFrockPage } from '@/api/cvs/feature'
+import { addCar, addFace, addFrock, addGroup, delCarById, delFaceById, delFrockById, getCarById, getCarPage, getFaceById, getFacePage, getFrockById, getFrockPage, groupList } from '@/api/cvs/feature'
 import { message } from 'ant-design-vue'
 
 export class FeatureController {
@@ -64,4 +64,15 @@ export class FeatureController {
     const { code, msg } = await delFrockById(id)
     code === 200 ? message.success('删除成功') : message.error(msg)
   }
+
+  static async groupList () {
+    const { code, data } = await groupList()
+
+    return code === 200 ? data : []
+  }
+
+  static async addGroup (data: CVS.Feature.Group) {
+    const { code, msg } = await addGroup(data)
+    code === 200 ? message.success('新增成功') : message.error(msg)
+  }
 }

+ 6 - 1
src/controller/cvs/operatorController.ts

@@ -1,4 +1,4 @@
-import { addOperatorVersion, delOperatorById, delOperatorVersion, getOperatorById, getOperatorPage, getOperatorType, updateOperatorName } from '@/api/cvs/operator'
+import { addOperator, addOperatorVersion, delOperatorById, delOperatorVersion, getOperatorById, getOperatorPage, getOperatorType, updateOperatorName } from '@/api/cvs/operator'
 import { message } from 'ant-design-vue'
 
 export class OperatorController {
@@ -21,6 +21,11 @@ export class OperatorController {
     code === 200 ? message.success('删除成功') : message.error(msg)
   }
 
+  static async add (data: CVS.Operator) {
+    const { msg, code } = await addOperator(data)
+    code === 200 ? message.success('新增成功') : message.error(msg)
+  }
+
   static async upadteName (aiId: string, aiName: string) {
     const { code, msg } = await updateOperatorName(aiId, aiName)
     code === 200 ? message.success('修改成功') : message.error(msg)

+ 6 - 0
src/controller/index.ts

@@ -14,3 +14,9 @@ export { UserController } from './user/index'
 export { DataSourceController } from './schedule/dataSource'
 
 export { SpaceController } from './cvs/spaceController'
+
+export { ProjectController } from './cvs/projectController'
+
+export { OperatorController } from './cvs/operatorController'
+
+export { FeatureController } from './cvs/featureController'

+ 0 - 1
src/pages/Iot/device/group.vue

@@ -557,7 +557,6 @@ const getDeviceGroup = async () => {
   ]
   state.groupData = data
   state.groupLoading = false
-  console.log('expand:', state.groupTreeData[0].children.map(item => item.id))
 
   expandedKeys.value = state.groupTreeData[0].children.map(item => item.id)
 }

+ 0 - 9
src/pages/cvs/dataServer/car.vue

@@ -1,9 +0,0 @@
-<template>
-<a-card>
-    car
-</a-card>
-</template>
-<script lang='ts' setup >
-</script>
-<style lang='less' scoped >
-</style>

+ 0 - 9
src/pages/cvs/dataServer/face.vue

@@ -1,9 +0,0 @@
-<template>
-<a-card>
-  face
-</a-card>
-</template>
-<script lang='ts' setup >
-</script>
-<style lang='less' scoped >
-</style>

+ 0 - 9
src/pages/cvs/dataServer/frock.vue

@@ -1,9 +0,0 @@
-<template>
-<a-card>
-  frock
-</a-card>
-</template>
-<script lang='ts' setup >
-</script>
-<style lang='less' scoped >
-</style>

+ 358 - 0
src/pages/cvs/dataServer/template.vue

@@ -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>

+ 159 - 3
src/pages/cvs/operator/manage.vue

@@ -1,9 +1,165 @@
 <template>
-<a-card>
-    operator
-</a-card>
+    <a-card title="算子管理" >
+                <table-pro
+                    :service="OperatorController.page"
+                    :serviceParams="{aiName}"
+                    :columns="columns"
+                    ref="tableProDom"
+                    @add="openModal"
+                >
+                    <template #search >
+                        <a-space>
+                            <input-tsx v-model:value="aiName" placeholder="请输入算子名称" />
+                            <a-button type="primary" @click="search" >搜索</a-button>
+                        </a-space>
+                    </template>
+                    <template #render="{column, record}"  >
+                        <template v-if="column.key === 'action'" >
+                          <a-space>
+                            <a>算子详情</a>
+                            <a @click="pushVersion(record)" >新增版本</a>
+                            <a @click="delOperator(record)" >删除</a>
+                          </a-space>
+                        </template>
+                    </template>
+                </table-pro>
+            </a-card>
+<modal-pro
+    width="800px"
+    label="创建算子"
+    :open="state.visible"
+    @cancel="closeModal"
+    @ok="submit"
+>
+    <a-form  style="width: 100%;" :labelCol="{span: 3}" :wrapperCol="{span: 14}" >
+      <a-form-item label="算子ID"  v-bind="validateInfos.aiId" extra="仅支持小写字母、数字、中划线,64字符以内,小写字母开头"  >
+        <InputTsx allowClear placeholder="请输入算子ID" v-model:value="operatorState.aiId" />
+      </a-form-item>
+      <a-form-item label="算子名称"  v-bind="validateInfos.aiName"  >
+        <InputTsx allowClear placeholder="请输入算子名称" v-model:value="operatorState.aiName" />
+      </a-form-item>
+      <a-form-item label="算子类型"  v-bind="validateInfos.aiModelType"  >
+        <a-select
+          ref="select"
+          v-model:value="operatorState.aiModelType"
+          style="width: 120px"
+          @change="onChangeOperatorType"
+        >
+          <a-select-option v-for="item in state.type" :key="item.code" :value="item.code">{{item.name}}</a-select-option>
+        </a-select>
+      </a-form-item>
+    </a-form>
+</modal-pro>
 </template>
 <script lang='ts' setup >
+import { OperatorController } from '@/controller'
+import { onMounted, reactive, ref } from 'vue'
+import { Form } from 'ant-design-vue'
+import { InputTsx, SelectTsx } from '@/components/MicroComponents'
+import { useRouter } from 'vue-router'
+
+const useForm = Form.useForm
+
+const router = useRouter()
+
+const aiName = ref('')
+
+const tableProDom = ref()
+
+const columns = [
+  {
+    title: '算子ID',
+    dataIndex: 'aiId',
+    key: 'aiId'
+  },
+  {
+    title: '算子名称',
+    dataIndex: 'aiName',
+    key: 'aiName'
+  },
+  {
+    title: '来源',
+    dataIndex: 'aiSourceType',
+    key: 'aiSourceType'
+  },
+  {
+    title: '业务类型',
+    dataIndex: 'aiModelType',
+    key: 'aiModelType'
+  },
+  {
+    title: '最近版本',
+    dataIndex: 'recentlyAiVersion',
+    key: 'recentlyAiVersion'
+  },
+  {
+    title: '操作',
+    dataIndex: 'action',
+    key: 'action'
+  }
+]
+
+const state = reactive<{
+  visible: boolean,
+  type: {code: string; name: string;}[]
+}>({
+  visible: false,
+  type: []
+})
+
+const operatorState = reactive<CVS.Operator>({
+  aiId: '',
+  aiName: '',
+  aiModelType: null
+})
+
+const { resetFields, validate, validateInfos } = useForm(operatorState, {
+  aiId: [{ required: true, message: '请填写aiId' }],
+  aiName: [{ required: true, message: '请填写算子名称' }],
+  aiModelType: [{ required: true, message: '请选择算子类型' }]
+})
+
+const onChangeOperatorType = () => {
+
+}
+
+const submit = () => {
+  validate().then(async () => {
+    await OperatorController.add(operatorState)
+    closeModal()
+    tableProDom.value.reload()
+  }).catch(() => {})
+}
+
+const delOperator = async (record) => {
+  await OperatorController.del(record.id)
+  tableProDom.value.reload()
+}
+
+const search = () => {
+  tableProDom.value.reload()
+}
+
+const closeModal = () => {
+  state.visible = false
+}
+
+const openModal = () => {
+  state.visible = true
+}
+
+const getOperatorType = async () => {
+  state.type = await OperatorController.type()
+}
+
+const pushVersion = (record) => {
+  router.push({ path: '/cvs/operator/version', query: { aiId: record.aiId } })
+}
+
+onMounted(() => {
+  getOperatorType()
+})
+
 </script>
 <style lang='less' scoped >
 </style>

+ 52 - 0
src/pages/cvs/operator/version.vue

@@ -0,0 +1,52 @@
+<template>
+<a-card title="算子版本" >
+  <table-pro
+    :columns="columns"
+  >
+
+  </table-pro>
+</a-card>
+</template>
+<script lang='ts' setup >
+
+const columns = [
+  {
+    title: '算子版本',
+    dataIndex: 'aiVersion',
+    key: 'aiVersion'
+  },
+  {
+    title: 'CPU架构',
+    dataIndex: 'architecture',
+    key: 'architecture'
+  },
+  {
+    title: '芯片品牌',
+    dataIndex: 'brand',
+    key: 'brand'
+  },
+  {
+    title: '芯片型号',
+    dataIndex: 'chipModel',
+    key: 'chipModel'
+  },
+  {
+    title: '版本地址',
+    dataIndex: 'aiVersionPkgUrl',
+    key: 'aiVersionPkgUrl'
+  },
+  {
+    title: '版本说明',
+    dataIndex: 'aiVersionComment',
+    key: 'aiVersionComment'
+  },
+  {
+    title: '操作',
+    dataIndex: 'action',
+    key: 'action'
+  }
+]
+
+</script>
+<style lang='less' scoped >
+</style>

+ 61 - 0
src/pages/cvs/project/index.vue

@@ -0,0 +1,61 @@
+<template>
+<a-card title="项目管理" >
+
+  <table-pro
+    :service="ProjectController.page"
+    :serviceParams="{projectName}"
+    :columns="columns"
+    ref="tableProDom"
+  >
+    <template #search >
+      <a-space>
+        <input-tsx v-model:value="projectName" placeholder="请输入项目名称" />
+        <a-button type="primary" @click="search" >搜索</a-button>
+      </a-space>
+    </template>
+    <template #render="{column, record}" >
+      <template v-if="column.key === 'action'" >
+        <a>详情</a>
+      </template>
+    </template>
+  </table-pro>
+</a-card>
+</template>
+<script lang='ts' setup >
+import { ProjectController } from '@/controller'
+import { ref } from 'vue'
+import { InputTsx } from '@/components/MicroComponents'
+
+const tableProDom = ref()
+
+const projectName = ref('')
+
+const columns = [
+  {
+    title: '项目ID',
+    dataIndex: 'projectId',
+    key: 'projectId'
+  },
+  {
+    title: '项目名称',
+    dataIndex: 'projectName',
+    key: 'projectName'
+  },
+  {
+    title: '项目名称',
+    dataIndex: 'description',
+    key: 'description'
+  },
+  {
+    title: '操作',
+    dataIndex: 'key',
+    key: 'key'
+  }
+]
+
+const search = () => {
+  tableProDom.value.reload()
+}
+</script>
+<style lang='less' scoped >
+</style>

+ 18 - 15
src/router/index.ts

@@ -341,17 +341,32 @@ const cvs = {
         }
       ]
     },
+    {
+      path: '/cvs/project',
+      name: '项目管理',
+      icon: '',
+      component: () => import('@/pages/cvs/project/index.vue')
+    },
     {
       path: '/cvs/operator',
       name: '算子仓库',
       icon: '',
+      redirect: '/cvs/operator/manage',
       children: [
         {
           path: '/cvs/operator/manage',
           name: '算子管理',
           icon: '',
           component: () => import('@/pages/cvs/operator/manage.vue')
+        },
+        {
+          path: '/cvs/operator/version',
+          name: '算子版本',
+          icon: '',
+          hidden: true,
+          component: () => import('@/pages/cvs/operator/version.vue')
         }
+
       ]
     },
     {
@@ -360,22 +375,10 @@ const cvs = {
       icon: '',
       children: [
         {
-          path: '/cvs/dataSever/car',
-          name: '车辆库',
-          icon: '',
-          component: () => import('@/pages/cvs/dataServer/car.vue')
-        },
-        {
-          path: '/cvs/dataSever/face',
-          name: '人脸库',
-          icon: '',
-          component: () => import('@/pages/cvs/dataServer/face.vue')
-        },
-        {
-          path: '/cvs/dataSever/frock',
-          name: '工装库',
+          path: '/cvs/dataSever/template',
+          name: '模版管理',
           icon: '',
-          component: () => import('@/pages/cvs/dataServer/frock.vue')
+          component: () => import('@/pages/cvs/dataServer/template.vue')
         }
       ]
     },

+ 14 - 5
src/type/cvs.d.ts

@@ -60,12 +60,12 @@ declare namespace CVS {
   }
 
   interface Operator {
-    id: number // 序列化id
+    id?: number // 序列化id
     aiId: string // 算子id
     aiName: string // 算子名称
-    aiSourceType: string // 来源 SYSTEM 系统预置 USER 自定义
-    aiModelType: string // 算子业务类型 //需要接口查询 返回 code 和业务实际的指
-    recentlyAiVersion: string
+    aiSourceType?: string // 来源 SYSTEM 系统预置 USER 自定义
+    aiModelType?: string // 算子业务类型 //需要接口查询 返回 code 和业务实际的指
+    recentlyAiVersion?: string // 最后一个版本
   }
 
   interface OperatorVersion {
@@ -93,7 +93,7 @@ declare namespace CVS {
     }
 
     interface Car {
-      id: number // 车辆id;
+      id?: number // 车辆id;
       carNo: string // 车辆车牌号
       carUrl: string // 车辆图片地址
     }
@@ -103,6 +103,15 @@ declare namespace CVS {
       frockName: string// 工装名称
       frockUrl: string // 工装图片地址
     }
+
+    interface Group {
+      id: string,
+      key: string,
+      groupName: string // 组名
+      upGroupId: number // 上次分组id
+      hasSubGroup?: boolean // 是否有子级别分组
+    }
+
   }
 
 }