Przeglądaj źródła

feat(固件关联): 新增

tangning 3 lat temu
rodzic
commit
8c9acc51d4

+ 51 - 0
src/api/product/index.ts

@@ -0,0 +1,51 @@
+import { defHttp } from '/@/utils/http/axios';
+import { PageParams, RentListGetResultModel,InvoiceListResul, addCameraParams, updateParams,getItemParams } from './model';
+import { Result,UploadFileParams } from '/#/axios';
+import { ContentTypeEnum } from '/@/enums/httpEnum';
+
+enum Api {
+  cameraVersionList = '/newV4/service/manage/cameraVersion/list',
+  upload = '/newV4/service/manage/common/upload/files',
+  addAndUpload = '/newV4/service/manage/cameraVersion/addAndUpload',
+}
+
+/**
+ * @description: Get sample list value
+ */
+
+export const CameraList = (params: PageParams) =>
+  defHttp.post<Result>({
+    url: Api.cameraVersionList,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
+export const AddAndUpload = (params: PageParams) =>
+  defHttp.post<Result>({
+    url: Api.addAndUpload,
+    params: params,
+    // data: params,
+    headers: {
+      // @ts-ignore
+        'Content-type': ContentTypeEnum.FORM_DATA,
+        // @ts-ignore
+        ignoreCancelToken: true,
+    },
+  });
+
+export function uploadApi(
+  params: UploadFileParams,
+  onUploadProgress: (progressEvent: ProgressEvent) => void,
+) {
+  return defHttp.uploadFile<Result>(
+    {
+      url: Api.upload,
+      onUploadProgress,
+    },
+    params,
+  );
+ }

+ 92 - 0
src/api/product/model.ts

@@ -0,0 +1,92 @@
+import { BasicPageParams, BasicFetchResult } from '/@/api/model/baseModel';
+/**
+ * @description: Request list interface parameters
+ */
+export type PageParams = BasicPageParams;
+
+export interface addCameraParams {
+  address: string;
+  balance: string;
+  cameraType: string;
+  childName: string;
+  companyId?: string;
+  orderSn?: string;
+  own: string;
+  snCode?: string;
+  wifiName: string;
+}
+export interface updateParams {
+  id: number;
+  canShow: number;
+  liveRoomCapacities: number;
+}
+export interface getItemParams {
+  id: number;
+}
+export interface DeviceListItem {
+  id: number;
+  activatedTime: string;
+  address: string;
+  agentFrameworkId: string;
+  agentFrameworkName: string;
+  agentName: string;
+  balance: string;
+  cameraType: number;
+  childName: string;
+  companyId: string;
+  companyName: string;
+  cooperationUser: string;
+  cooperationUserName: string;
+  country: number;
+  createTime: string;
+  goodsId: number;
+  goodsName: string;
+  imageUrl: string;
+  inTime: string;
+  isExpire: string;
+  lastTime: string;
+  nickName: string;
+  orderSn: string;
+  outTime: string;
+  own: number;
+  pic: string;
+  recStatus: string;
+  responseUserIncrement: string;
+  sceneNum: string;
+  snCode: string;
+  space: string;
+  spaceContent: string;
+  spaceEndStr: string;
+  spaceEndTime: string;
+  spaceId: string;
+  spaceStr: string;
+  surplusDate: string;
+  totalSpace: number;
+  totalSpaceStr: string;
+  type: string;
+  usedSpace: number;
+  usedSpaceStr: string;
+  userId: string;
+  userIncrementId: string;
+  userName: string;
+  wifiName: string;
+}
+
+export interface InvoiceList {
+  orderSn: string;
+  payTimeStart	: string;
+  payTimeEnd: string;
+  invoiceTimeStart: string;
+  invoiceTimeEnd: string;
+  orderBy: string;
+  sortBy: string;
+  pageSize: number;
+  pageNum: number;
+}
+
+
+export type InvoiceListResul = BasicPageParams<InvoiceList>
+/**
+ * @description: Request list return value
+ */
+export type RentListGetResultModel = BasicFetchResult<DeviceListItem>;

+ 6 - 1
src/components/Upload/src/UploadModal.vue

@@ -179,7 +179,7 @@
       // }
 
       async function uploadApiByItem(item: FileItem) {
-        const { api } = props;
+        const { api, afterFetch } = props;
         if (!api || !isFunction(api)) {
           return warn('upload api must exist and be a function');
         }
@@ -201,6 +201,11 @@
           );
           item.status = UploadResultStatus.SUCCESS;
           item.responseData = data;
+          
+          if (afterFetch && isFunction(afterFetch)) {
+            item.responseData = (await afterFetch(data)) || data;
+          }
+          
           return {
             success: true,
             error: null,

+ 4 - 0
src/components/Upload/src/props.ts

@@ -42,6 +42,10 @@ export const basicProps = {
     type: String as PropType<string>,
     default: null,
   },
+  afterFetch: {
+    type: Function as PropType<Fn>,
+    default: null,
+  },
 };
 
 export const uploadContainerProps = {

+ 37 - 2
src/locales/lang/zh-CN/common.ts

@@ -2,19 +2,54 @@ export default {
   okText: '确认',
   closeText: '关闭',
   cancelText: '取消',
+  EditorNot: '是否取消编辑',
   loadingText: '加载中...',
   saveText: '保存',
   delText: '删除',
+  operating: '操作',
   resetText: '重置',
   searchText: '搜索',
   queryText: '查询',
 
   inputText: '请输入',
   chooseText: '请选择',
-
+  edit: '编辑',
   redo: '刷新',
   back: '返回',
-
+  checkTips: '验证提示',
   light: '亮色主题',
   dark: '黑暗主题',
+  unbind: '解绑',
+  details: '详情',
+  bind: '绑定',
+  yes: '是',
+  no: '否',
+  roleName: '角色',
+  roleNameText: '角色名称',
+  addRoleName: '新增角色',
+  editRoleName: '编辑角色',
+  submitState: '提交成功!',
+
+  unusual: '异常',
+  operation: '操作',
+  normal: '正常',
+  unNormal: '非正常',
+  state: '状态',
+  type: '类型',
+  fullName: '员工名称',
+  print: '打印',
+  all: '全部',
+  tips: '提示',
+  optSuccess: '操作成功!',
+  optFail: '操作失败!',
+  notConnect: '暂未接入',
+  delConfirm: '是否确认删除',
+  mobile: '手机',
+  phone: '请填写您的手机号码!',
+  phoneError: '请正确填写您的手机号码!',
+  staffPhoneError: '请正确填写您的企业账户!',
+  uploadMessge: '请选择上传文件',
+  userNick: '请输入员工名称',
+  userCorrectNameNick: '请输入正确的员工名称',
+  warning: '警告',
 };

+ 4 - 2
src/locales/lang/zh-CN/routes/dashboard.ts

@@ -28,12 +28,14 @@ export default {
   scenesLive: '直播',
   scenesRoom: '房间管理',
   devices: '设备管理',
-  product: '商品管理',
+  product: '产品管理',
+  firmware:'固件管理',
+  sdk:'Space Target SDK',
+  app:'App管理',
   productRef: '商品属性',
   productList: '商品列表',
   productCategory: '商品分类',
   order: '订单管理',
-  orderList: '订单列表',
   cameraList: '相机订单列表',
   downloadList: '下载订单列表',
   equityList: '权益订单列表',

+ 19 - 0
src/locales/lang/zh-CN/routes/product.ts

@@ -0,0 +1,19 @@
+export default {
+  addVstive:'新增版本',
+  newsTitle:'新闻标题',
+  newsAdd:'新增新闻',
+  source:'来源',
+  objTitle:'职位名称',
+  submitTitle:'提交时间',
+  mesgContent:'留言内容',
+  types:'设备类型',
+  minVersion:'最低版本号',
+  version:'版本号',
+  description:'版本更新说明',
+  file:'文件',
+  type:{
+    1:'四维看看',
+    2:'四维看见',
+    3:'四维深时',
+  }
+};

+ 1 - 1
src/router/routes/modules/invoice.ts

@@ -17,7 +17,7 @@ export const InvoiceRoute: AppRouteRecordRaw = {
     {
       path: 'list',
       name: 'List',
-      component: () => import('/@/views/invoice/index.vue'),
+      component: () => import('../../../views/invoice/index.vue'),
       meta: {
         title: t('routes.dashboard.invoice'),
       },

+ 22 - 6
src/router/routes/modules/product.ts

@@ -5,20 +5,36 @@ import { LAYOUT } from '/@/router/constant';
 export const ProductRoute: AppRouteRecordRaw = {
   path: '/product',
   name: 'Product',
-  redirect: '/product/index',
+  redirect: '/product/firmware',
   component: LAYOUT,
   meta: {
     title: t('routes.dashboard.product'),
     icon: 'la:file-invoice-dollar',
-    orderNo: 20,
+    orderNo: 90,
   },
   children: [
     {
-      path: 'index',
-      name: 'index',
-      component: () => import('/@/views/invoice/index.vue'),
+      path: 'firmware',
+      name: 'Firmware',
+      component: () => import('/@/views/product/firmware/index.vue'),
       meta: {
-        title: t('routes.dashboard.product'),
+        title: t('routes.dashboard.firmware'),
+      },
+    },
+    {
+      path: 'sdk',
+      name: 'Sdk',
+      component: () => import('/@/views/product/sdk/index.vue'),
+      meta: {
+        title: t('routes.dashboard.sdk'),
+      },
+    },
+    {
+      path: 'app',
+      name: 'App',
+      component: () => import('/@/views/product/app/index.vue'),
+      meta: {
+        title: t('routes.dashboard.app'),
       },
     },
   ],

+ 4 - 4
src/views/invoice/index.vue

@@ -37,7 +37,7 @@
   import { useI18n } from '/@/hooks/web/useI18n';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { Switch } from 'ant-design-vue';
-  import { DownList,DownExport } from '/@/api/order'
+  import { InvoiceList,DownExport } from '/@/api/order'
 
   export default defineComponent({
     components: { 
@@ -136,7 +136,7 @@
         ],
       };
       const [registerTable] = useTable({
-        api: DownList,
+        api: InvoiceList,
         title: '发票列表',
         // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
         columns: columns,
@@ -146,8 +146,8 @@
         rowKey: 'id',
         fetchSetting: {
           pageField: 'pageNum',
-          sizeField: 'pageSize',
-          listField: 'list',
+          sizeField: 'size',
+          listField: 'records',
           totalField: 'total',
         },
         canResize: false,

+ 4 - 4
src/views/operate/newsList.vue

@@ -175,8 +175,8 @@
               showTime: true,
             },
             colProps: {
-              xl: 8,
-              xxl: 8,
+              xl: 11,
+              xxl: 11,
             },
           },
           {
@@ -184,8 +184,8 @@
             label: t('routes.operate.newsTitle'),
             component: 'Input',
             colProps: {
-              xl: 7,
-              xxl: 7,
+              xl: 6,
+              xxl: 6,
             },
           },
         ],

+ 256 - 0
src/views/product/AddModal.vue

@@ -0,0 +1,256 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="新增相机"
+    @visible-change="handleVisibleChange"
+    @cancel="resetFields"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <BasicForm @register="registerForm" :model="model" >
+        <template #text="{ model, field }">
+          {{ model[field]  }}
+        </template>
+      </BasicForm>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, nextTick, onMounted } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { uploadApi, AddAndUpload } from '/@/api/product/index';
+  import { useI18n } from '/@/hooks/web/useI18n';
+
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const modelRef = ref({});
+      const { createMessage } = useMessage();
+      const schemas: FormSchema[] = [
+        {
+          field: 'type',
+          component: 'Input',
+          label: t('routes.product.types'),
+          slot: 'text',
+          colProps: {
+            span: 24,
+          },
+          // required: true,
+        },
+        {
+          field: 'version',
+          component: 'Input',
+          label: t('routes.product.version'),
+          required: true,
+          colProps: {
+            span: 24,
+          },
+          rules: [
+            {
+              required: true,
+              // @ts-ignore
+              validator: async (rule, value) => {
+                if (!value) {
+                  return Promise.reject(t('common.inputText')+t('routes.product.version'));
+                }
+                if(/.*[\u4e00-\u9fa5]+.*$/.test(value)){
+                  /* eslint-disable-next-line */
+                  return Promise.reject('不支持中文字符');
+                }
+                return Promise.resolve();
+              },
+              trigger: 'change',
+            },
+          ],
+          componentProps: {
+            maxLength: 15,
+            onChange: (data) => {
+              console.log('data', data);
+            },
+          },
+        },
+        {
+          field: 'minVersion',
+          component: 'Input',
+          label: t('routes.product.minVersion'),
+          required: true,
+          rules: [
+            {
+              required: true,
+              // @ts-ignore
+              validator: async (rule, value) => {
+                const regPos = /.*[\u4e00-\u9fa5]+.*$/; // 非中文
+                if (!value) {
+                  return Promise.reject(t('common.inputText')+t('routes.product.minVersion'));
+                }
+                if (regPos.test(value)) {
+                  /* eslint-disable-next-line */
+                  return Promise.reject('不支持中文字符');
+                }
+                return Promise.resolve();
+              },
+              trigger: 'change',
+            },
+          ],
+          colProps: {
+            span: 24,
+          },
+        },
+        {
+          field: 'description',
+          component: 'InputTextArea',
+          required: true,
+          label: t('routes.product.description'),
+          colProps: {
+            span: 24,
+          },
+        },
+        {
+          field: 'file',
+          component: 'Upload',
+          label: t('routes.product.file'),
+          required: true,
+          rules: [{ required: true, message: t('common.uploadMessge') }],
+          // helpMessage: t('routes.corporation.uploadHelp'),
+          itemProps: {
+            validateTrigger: 'onBlur',
+          },
+          componentProps: {
+            api: uploadApi,
+            maxNumber: 1,
+            maxSize: 1000,
+            accept: ['4dage'],
+            afterFetch: function (data) {
+              Reflect.set(data, 'url', data.data);
+              console.log('uploadApi',data)
+              return data;
+            },
+          },
+
+          colProps: {
+            span: 22,
+          },
+        },
+        // {
+        //   field: 'orderSn',
+        //   component: 'Input',
+        //   label: t('routes.devices.orderSn'),
+        //   colProps: {
+        //     span: 24,
+        //   },
+        // },
+        // {
+        //   field: 'companyId',
+        //   component: 'ApiSelect',
+        //   label: t('routes.devices.companyId'),
+        //   itemProps: {
+        //     validateTrigger: 'blur',
+        //   },
+        //   componentProps: {
+        //     api: allCompanyApi,
+        //     numberToString: true,
+        //     labelField: 'name',
+        //     valueField: 'id',
+        //     immediate: true,
+        //     params: {
+        //       page: 1,
+        //       limit: 1000,
+        //     },
+        //   },
+        //   colProps: {
+        //     span: 24,
+        //   },
+        // },
+      ];
+      const [registerForm, { validate, resetFields, setFieldsValue }] = useForm({
+        labelWidth: 120,
+        schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function renderOwnTypeLabel(type: number): string {
+        switch (type) {
+          case 2:
+            return t('routes.product.type.2');
+          case 1:
+            return t('routes.product.type.1');
+          case 3:
+            return t('routes.product.type.3');
+          default:
+            return '';
+        }
+      }
+      function rendercameraTypeLabel(cameraType: number): string {
+        switch (cameraType) {
+          case 4:
+            return t('routes.devices.cameraName.4');
+          case 1:
+            return t('routes.devices.cameraName.1');
+          case 9:
+            return t('routes.devices.cameraName.9');
+          case 10:
+            return t('routes.devices.cameraName.10');
+          case 6:
+            return t('routes.devices.cameraName.6');
+          default:
+            return '';
+        }
+      }
+      function onDataReceive(data) {
+        modelRef.value = data
+        resetFields();
+        setFieldsValue({
+          type:renderOwnTypeLabel(Number(data)),
+        });
+      }
+      const handleSubmit = async () => {
+        try {
+          const params = await validate();
+          console.log('res', params);
+          const res = await AddAndUpload({
+            ...params as any,
+            type:modelRef.value,
+          });
+          console.log('res', res);
+          closeModal();
+          resetFields();
+          createMessage.success(res);
+          emit('update');
+        } catch (error) {
+          console.log('not passing', error);
+        }
+      };
+      function handleVisibleChange(v) {
+        v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+      return {
+        register,
+        rendercameraTypeLabel,
+        renderOwnTypeLabel,
+        schemas,
+        registerForm,
+        model: modelRef,
+        handleVisibleChange,
+        handleSubmit,
+        addListFunc,
+        resetFields,
+        t,
+      };
+    },
+  });
+</script>

+ 278 - 0
src/views/product/EditModal.vue

@@ -0,0 +1,278 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    :title="t('routes.devices.editCamera')"
+    @visible-change="handleVisibleChange"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <BasicForm @register="registerForm" />
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, ref, nextTick, onMounted } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  // allCompanyApi
+  import { editCameraApi } from '/@/api/device/list';
+  import { useI18n } from '/@/hooks/web/useI18n';
+
+  //   address: "11111"
+  // balance: "111"
+  // cameraType: "4"
+  // childName: "11111"
+  // companyId: 1146
+  // orderSn: "1111"
+  // own: "0"
+  // rnd: 0.9923218970879999
+  // snCode: "1111"
+  // wifiName: "1111"
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const modelRef = ref({});
+      const { createMessage } = useMessage();
+      const schemas: FormSchema[] = [
+        {
+          field: 'cameraId',
+          component: 'Input',
+          label: 'id',
+          show: false,
+        },
+        {
+          field: 'own',
+          component: 'Select',
+          label: t('routes.devices.own'),
+          colProps: {
+            span: 24,
+          },
+          componentProps: {
+            // disabled: true,
+            options: [0, 2, 1, 3].map((ele) => {
+              return { value: ele, key: ele, label: renderOwnTypeLabel(ele) };
+            }),
+          },
+          required: true,
+        },
+        {
+          field: 'cameraType',
+          component: 'Select',
+          label: t('routes.devices.cameraType'),
+          required: true,
+          colProps: {
+            span: 24,
+          },
+          componentProps: {
+            disabled: true,
+            options: [4, 1, 9, 10, 6].map((ele) => {
+              return { value: ele, key: ele, label: rendercameraTypeLabel(ele) };
+            }),
+            // onChange: function (val) {
+            //   console.log('appendSchemaByField', val);
+            //   if (val !== 6) {
+            //     appendSchemaByField(
+            //       {
+            //         field: 'snCode',
+            //         component: 'Input',
+            //         label: t('routes.devices.snCode'),
+            //         required: true,
+            //         colProps: {
+            //           span: 24,
+            //         },
+            //       },
+            //       'address',
+            //     );
+            //   } else {
+            //     removeSchemaByFiled('snCode');
+            //   }
+            // },
+          },
+        },
+
+        {
+          field: 'childName',
+          component: 'Input',
+          label: t('routes.devices.childName'),
+          required: true,
+          colProps: {
+            span: 24,
+          },
+          componentProps: {
+            disabled: true,
+          },
+        },
+        {
+          field: 'wifiName',
+          component: 'Input',
+          label: t('routes.devices.wifiName'),
+          required: true,
+          componentProps: {
+            disabled: true,
+          },
+          colProps: {
+            span: 24,
+          },
+        },
+        // {
+        //   field: 'address',
+        //   component: 'Input',
+        //   required: true,
+        //   label: t('routes.devices.address'),
+        //   componentProps: {
+        //     disabled: true,
+        //   },
+        //   colProps: {
+        //     span: 24,
+        //   },
+        // },
+        {
+          field: 'snCode',
+          component: 'Input',
+          label: t('routes.devices.snCode'),
+          required: true,
+          componentProps: {
+            disabled: true,
+          },
+          ifShow: ({ model }) => {
+            console.log('record', model.cameraType);
+
+            return model.cameraType && model.cameraType !== 6;
+          },
+          colProps: {
+            span: 24,
+          },
+        },
+        // {
+        //   field: 'balance',
+        //   component: 'Input',
+        //   label: t('routes.devices.balance'),
+        //   colProps: {
+        //     span: 24,
+        //   },
+        // },
+
+        // {
+        //   field: 'companyId',
+        //   component: 'ApiSelect',
+        //   label: t('routes.devices.companyId'),
+        //   componentProps: {
+        //     api: allCompanyApi,
+        //     numberToString: true,
+        //     labelField: 'companyName',
+        //     valueField: 'id',
+        //     immediate: true,
+        //     params: {
+        //       page: 1,
+        //       limit: 1000,
+        //     },
+        //   },
+        //   colProps: {
+        //     span: 24,
+        //   },
+        // },
+      ];
+      const [
+        registerForm,
+        {
+          // getFieldsValue,
+          // validateFields,
+          // appendSchemaByField,
+          // removeSchemaByFiled,
+          setFieldsValue,
+          validate,
+          // setProps
+        },
+      ] = useForm({
+        labelWidth: 120,
+        schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function renderOwnTypeLabel(type: number): string {
+        switch (type) {
+          case 0:
+            return t('routes.devices.ownName.0');
+          case 2:
+            return t('routes.devices.ownName.2');
+          case 1:
+            return t('routes.devices.ownName.1');
+          case 3:
+            return t('routes.devices.ownName.3');
+          default:
+            return '';
+        }
+      }
+      function rendercameraTypeLabel(cameraType: number): string {
+        switch (cameraType) {
+          case 4:
+            return t('routes.devices.cameraName.4');
+          case 1:
+            return t('routes.devices.cameraName.1');
+          case 9:
+            return t('routes.devices.cameraName.9');
+          case 10:
+            return t('routes.devices.cameraName.10');
+          case 6:
+            return t('routes.devices.cameraName.6');
+          default:
+            return '';
+        }
+      }
+      function onDataReceive(data) {
+        console.log('Data Received', data);
+        setFieldsValue({
+          ...data,
+          cameraId: Number(data.id),
+          cameraType: Number(data.cameraType),
+        });
+      }
+      const handleSubmit = async () => {
+        // console.log('getFieldsValue()', getFieldsValue());
+        try {
+          const values = await validate();
+          console.log('values', values);
+          if (values) {
+            const res = await editCameraApi(values);
+            emit('update');
+            console.log('res', res);
+            createMessage.success(t('common.optSuccess'));
+            closeModal();
+          }
+        } catch (error) {
+          console.log('not passing', error);
+        }
+      };
+      function handleVisibleChange(v) {
+        v && props.userData && nextTick(() => onDataReceive(props.userData));
+      }
+
+      return {
+        register,
+        rendercameraTypeLabel,
+        renderOwnTypeLabel,
+        schemas,
+        registerForm,
+        model: modelRef,
+        handleVisibleChange,
+        handleSubmit,
+        addListFunc,
+        t,
+      };
+    },
+  });
+</script>

+ 179 - 0
src/views/product/app/index.vue

@@ -0,0 +1,179 @@
+<template>
+    <BasicTable @register="registerTable">
+      <template #toolbar>
+        <a-button type="primary" @click="exportExcel"> 导出</a-button>
+      </template>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'action'">
+          <TableAction
+            stopButtonPropagation
+            :actions="[
+              {
+                label: '删除',
+                icon: 'ic:outline-delete-outline',
+                onClick: handleDelete.bind(null, record),
+              },
+            ]"
+            :dropDownActions="[
+              {
+                label: '启用',
+                popConfirm: {
+                  title: '是否启用?',
+                  confirm: handleOpen.bind(null, record),
+                },
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+</template>
+<script lang="ts">
+  import { defineComponent, h } from 'vue';
+  import { BasicTable, useTable, TableAction, BasicColumn, TableImg, FormProps } from '/@/components/Table';
+  import { PageWrapper } from '/@/components/Page';
+  import { Time } from '/@/components/Time';
+  import { Descriptions } from 'ant-design-vue';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { Switch } from 'ant-design-vue';
+  import { InvoiceList,DownExport } from '/@/api/order'
+
+  export default defineComponent({
+    components: { 
+      BasicTable, 
+      TableAction, 
+      PageWrapper,
+      TableImg,
+      [Descriptions.name]: Descriptions,
+      [Descriptions.Item.name]: Descriptions.Item,
+    },
+    setup() {
+      const { t } = useI18n();
+      const { createMessage,createConfirm } = useMessage();
+      const columns: BasicColumn[] = [
+        {
+          title: '时间',
+          dataIndex: 'createTime',
+          width: 150,
+          customRender: ({ record }) => {
+            return (
+              record.createTime &&
+              h(Time, {
+                value: record.createTime,
+                mode: 'datetime',
+              })
+            );
+          },
+        },
+        {
+          title: '订单号',
+          dataIndex: 'orderSn',
+          ellipsis: false,
+          width: 180,
+        },
+        {
+          title: '用户名',
+          dataIndex: 'userName',
+          width: 80,
+        },
+        {
+          title: '订单金额',
+          dataIndex: 'amount',
+          width: 80,
+        },
+        {
+          title: '支付方式',
+          dataIndex: 'payType',
+          // slots: { customRender: 'orderType' },
+          width: 80,
+        },
+        {
+          title: '订单状态',
+          dataIndex: 'payStatus',
+          // slots: { customRender: 'orderStatus' },
+          width: 80,
+        },
+      ];
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        schemas: [
+          {
+            field: 'sceneName',
+            label: '开票申请时间',
+            component: 'RangePicker',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },
+          {
+            field: 'sceneName',
+            label: '支付时间',
+            component: 'RangePicker',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },{
+            field: 'sceneName',
+            label: '订单号',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 6,
+              xxl: 6,
+            },
+          }
+        ],
+      };
+      const [registerTable] = useTable({
+        api: InvoiceList,
+        title: '发票列表',
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        columns: columns,
+        useSearchForm: true,
+        formConfig: searchForm,
+        showTableSetting: true,
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'size',
+          listField: 'records',
+          totalField: 'total',
+        },
+        canResize: false,
+      });
+      function handleDelete(record: Recordable) {
+        console.log('点击了删除', record);
+      }
+      function handleOpen(record: Recordable) {
+        console.log('点击了启用', record);
+      }
+      function exportExcel() {
+        createConfirm({
+          iconType: 'warning',
+          title: () => h('span', '温馨提示'),
+          content: () => h('span', '确定当前标签下的订单记录?'),
+          onOk: async () => {
+            await DownExport();
+          },
+        });
+      }
+      return {
+        registerTable,
+        handleDelete,
+        handleOpen,
+        exportExcel,
+      };
+    },
+  });
+</script>

+ 100 - 0
src/views/product/data.tsx

@@ -0,0 +1,100 @@
+import { BasicColumn } from '/@/components/Table/src/types/table';
+import { h } from 'vue';
+import { Time } from '/@/components/Time';
+import { useMessage } from '/@/hooks/web/useMessage';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { Switch } from 'ant-design-vue';
+const { createMessage } = useMessage();
+const { t } = useI18n();
+
+export const refundTimeTableSchema: BasicColumn[] = [
+  {
+    title: '版本号',
+    width: 150,
+    dataIndex: 't1',
+  },
+  {
+    title: '版本更新说明',
+    width: 150,
+    dataIndex: 't2',
+    fixed: 'left',
+  },
+  {
+    title: '最低版本号',
+    width: 150,
+    dataIndex: 't2',
+  },{
+    title: '创建人	',
+    width: 150,
+    dataIndex: 'shipName',
+  },{
+    title: '创建时间',
+    width: 150,
+    dataIndex: 't3',
+    customRender: ({ record }) => {
+      return (
+        record.orderTime &&
+        h(Time, {
+          value: record.orderTime,
+          mode: 'datetime',
+        })
+      );
+    },
+  },{
+    title: '状态',
+    dataIndex: 'isOnSale',
+    width: 80,
+    customRender: ({ record }) => {
+      if (!Reflect.has(record, 'pendingStatus')) {
+        record.pendingStatus = false;
+      }
+      return h(Switch, {
+        checked: record.isOnSale === 1,
+        checkedChildren: '启用',
+        unCheckedChildren: '禁用',
+        loading: false,
+        onChange: async (checked: boolean) => {
+          record.pendingStatus = true;
+          const newStatus = checked ? 1 : 0;
+          if (checked) {
+            Reflect.set(record, 'isOnSale', newStatus);
+          } else {
+            Reflect.set(record, 'isOnSale', newStatus);
+          }
+          createMessage.success(t('common.optSuccess'));
+        },
+      });
+    },
+  },
+];
+
+export const refundTimeTableData: any[] = [
+  {
+    t1: '2017-10-01 14:10',
+    t2: '联系客户',
+    t3: '进行中',
+    t4: '取货员 ID1234',
+    t5: '5mins',
+  },
+  {
+    t1: '2017-10-01 14:10',
+    t2: '取货员出发',
+    t3: '成功',
+    t4: '取货员 ID1234',
+    t5: '5mins',
+  },
+  {
+    t1: '2017-10-01 14:10',
+    t2: '取货员接单',
+    t3: '成功',
+    t4: '系统',
+    t5: '5mins',
+  },
+  {
+    t1: '2017-10-01 14:10',
+    t2: '申请审批通过',
+    t3: '成功',
+    t4: '用户',
+    t5: '1h',
+  },
+];

+ 116 - 0
src/views/product/firmware/index.vue

@@ -0,0 +1,116 @@
+<template>
+  <PageWrapper contentBackground>
+    <template #footer>
+      <a-tabs v-model:activeKey="activeKey" @change="tabChange">
+        <a-tab-pane key="1" :tab="t('routes.product.type.1')" />
+        <a-tab-pane key="2" :tab="t('routes.product.type.2')" />
+        <a-tab-pane key="3" :tab="t('routes.product.type.3')" />
+      </a-tabs>
+    </template>
+    <div class="desc-wrap-BasicTable">
+      <BasicTable @register="registerTimeTable" >
+        <template #toolbar>
+          <a-button type="primary" @click="()=>{openAddModal(true,activeKey)}">{{
+            t('routes.product.addVstive')
+          }}</a-button>
+      </template>
+      </BasicTable>
+    </div>
+    <AddModal @update="reload" @register="registerAddModal" />
+    <!-- <EditModal @register="registerEditModal" @update="reload" /> -->
+  </PageWrapper>
+</template>
+<script lang="ts">
+  import { defineComponent,ref } from 'vue';
+  import { BasicTable, useTable, FormProps } from '/@/components/Table';
+  import { PageWrapper } from '/@/components/Page';
+  import { Divider, Card, Empty, Descriptions, Steps, Tabs } from 'ant-design-vue';
+  import { CameraList } from '/@/api/product'
+  import { useModal } from '/@/components/Modal';
+  import { refundTimeTableSchema } from '../data';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import AddModal from '../AddModal.vue';
+  // import EditModal from '../EditModal.vue';
+
+  export default defineComponent({
+    components: {
+      BasicTable,
+      AddModal,
+      // EditModal,
+      PageWrapper,
+      [Divider.name]: Divider,
+      [Card.name]: Card,
+      Empty,
+      [Descriptions.name]: Descriptions,
+      [Descriptions.Item.name]: Descriptions.Item,
+      [Steps.name]: Steps,
+      [Steps.Step.name]: Steps.Step,
+      [Tabs.name]: Tabs,
+      [Tabs.TabPane.name]: Tabs.TabPane,
+    },
+    setup() {
+      const { t } = useI18n();
+      const [registerAddModal, { openModal: openAddModal }] = useModal();
+      const [registerEditModal, { openModal: openEditModal }] = useModal();
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        schemas: [
+          {
+            field: 'sceneName',
+            label: '版本号',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 6,
+              xxl: 6,
+            },
+          }
+        ],
+      };
+      const [registerTimeTable, { reload }] = useTable({
+        api: CameraList,
+        title: '相机列表',
+        columns: refundTimeTableSchema,
+        useSearchForm: true,
+        formConfig: searchForm,
+        showTableSetting: true,
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'pageSize',
+          listField: 'list',
+          totalField: 'total',
+        },
+        canResize: false,
+      });
+      function tabChange(val:string){
+        console.log('tabChange',val)
+      }
+      function handleEdit(record: Recordable) {
+        console.log('record', record);
+        openEditModal(true, record);
+      }
+      return {
+        registerTimeTable,
+        tabChange,
+        reload,
+        registerAddModal,
+        registerEditModal,
+        openAddModal,
+        handleEdit,
+        t,
+        activeKey: ref('1'),
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+.desc-wrap-BasicTable{
+  background-color: #f0f2f5;
+  .vben-basic-table-form-container{
+    padding: 0;
+  }
+}
+</style>

+ 179 - 0
src/views/product/sdk/index.vue

@@ -0,0 +1,179 @@
+<template>
+    <BasicTable @register="registerTable">
+      <template #toolbar>
+        <a-button type="primary" @click="exportExcel"> 导出</a-button>
+      </template>
+      <template #bodyCell="{ column, record }">
+        <template v-if="column.key === 'action'">
+          <TableAction
+            stopButtonPropagation
+            :actions="[
+              {
+                label: '删除',
+                icon: 'ic:outline-delete-outline',
+                onClick: handleDelete.bind(null, record),
+              },
+            ]"
+            :dropDownActions="[
+              {
+                label: '启用',
+                popConfirm: {
+                  title: '是否启用?',
+                  confirm: handleOpen.bind(null, record),
+                },
+              },
+            ]"
+          />
+        </template>
+      </template>
+    </BasicTable>
+</template>
+<script lang="ts">
+  import { defineComponent, h } from 'vue';
+  import { BasicTable, useTable, TableAction, BasicColumn, TableImg, FormProps } from '/@/components/Table';
+  import { PageWrapper } from '/@/components/Page';
+  import { Time } from '/@/components/Time';
+  import { Descriptions } from 'ant-design-vue';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { Switch } from 'ant-design-vue';
+  import { InvoiceList,DownExport } from '/@/api/order'
+
+  export default defineComponent({
+    components: { 
+      BasicTable, 
+      TableAction, 
+      PageWrapper,
+      TableImg,
+      [Descriptions.name]: Descriptions,
+      [Descriptions.Item.name]: Descriptions.Item,
+    },
+    setup() {
+      const { t } = useI18n();
+      const { createMessage,createConfirm } = useMessage();
+      const columns: BasicColumn[] = [
+        {
+          title: '时间',
+          dataIndex: 'createTime',
+          width: 150,
+          customRender: ({ record }) => {
+            return (
+              record.createTime &&
+              h(Time, {
+                value: record.createTime,
+                mode: 'datetime',
+              })
+            );
+          },
+        },
+        {
+          title: '订单号',
+          dataIndex: 'orderSn',
+          ellipsis: false,
+          width: 180,
+        },
+        {
+          title: '用户名',
+          dataIndex: 'userName',
+          width: 80,
+        },
+        {
+          title: '订单金额',
+          dataIndex: 'amount',
+          width: 80,
+        },
+        {
+          title: '支付方式',
+          dataIndex: 'payType',
+          // slots: { customRender: 'orderType' },
+          width: 80,
+        },
+        {
+          title: '订单状态',
+          dataIndex: 'payStatus',
+          // slots: { customRender: 'orderStatus' },
+          width: 80,
+        },
+      ];
+      const searchForm: Partial<FormProps> = {
+        labelWidth: 100,
+        schemas: [
+          {
+            field: 'sceneName',
+            label: '开票申请时间',
+            component: 'RangePicker',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },
+          {
+            field: 'sceneName',
+            label: '支付时间',
+            component: 'RangePicker',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 7,
+              xxl: 7,
+            },
+          },{
+            field: 'sceneName',
+            label: '订单号',
+            component: 'Input',
+            componentProps: {
+              maxLength: 100,
+            },
+            colProps: {
+              xl: 6,
+              xxl: 6,
+            },
+          }
+        ],
+      };
+      const [registerTable] = useTable({
+        api: InvoiceList,
+        title: '发票列表',
+        // titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
+        columns: columns,
+        useSearchForm: true,
+        formConfig: searchForm,
+        showTableSetting: true,
+        rowKey: 'id',
+        fetchSetting: {
+          pageField: 'pageNum',
+          sizeField: 'size',
+          listField: 'records',
+          totalField: 'total',
+        },
+        canResize: false,
+      });
+      function handleDelete(record: Recordable) {
+        console.log('点击了删除', record);
+      }
+      function handleOpen(record: Recordable) {
+        console.log('点击了启用', record);
+      }
+      function exportExcel() {
+        createConfirm({
+          iconType: 'warning',
+          title: () => h('span', '温馨提示'),
+          content: () => h('span', '确定当前标签下的订单记录?'),
+          onOk: async () => {
+            await DownExport();
+          },
+        });
+      }
+      return {
+        registerTable,
+        handleDelete,
+        handleOpen,
+        exportExcel,
+      };
+    },
+  });
+</script>