Browse Source

feat: 订单详情页展示发票和证件图片

laiqi 1 year ago
parent
commit
6b84e3c210

+ 2 - 0
apps/web-ele/auto-imports.d.ts

@@ -6,5 +6,7 @@
 // biome-ignore lint: disable
 export {}
 declare global {
+  const ElImage: (typeof import('element-plus/es'))['ElImage'];
+  const ElInput: (typeof import('element-plus/es'))['ElInput'];
   const ElTag: (typeof import('element-plus/es'))['ElTag'];
 }

+ 1 - 0
apps/web-ele/components.d.ts

@@ -12,6 +12,7 @@ declare module 'vue' {
     ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
     ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
     ElDivider: typeof import('element-plus/es')['ElDivider']
+    ElImage: typeof import('element-plus/es')['ElImage']
     ElInput: typeof import('element-plus/es')['ElInput']
     ElTag: typeof import('element-plus/es')['ElTag']
     RouterLink: typeof import('vue-router')['RouterLink']

+ 5 - 1
apps/web-ele/src/api/dict/index.ts

@@ -15,7 +15,11 @@ interface DictQueryParams extends DictPartialEntity, PageConfig {}
  */
 export async function getDictListApi(params: DictQueryParams) {
   return requestClient.post<any>('/api/query/list?pagevalue=73', {
-    ...params,
+    pageindex: params.pageindex,
+    rows: params.rows,
+    ...parseQueryValues({
+      groupname: params.groupname,
+    }),
   });
 }
 

+ 66 - 0
apps/web-ele/src/api/file/index.ts

@@ -0,0 +1,66 @@
+import type { AttachmentEntity, PageConfig } from '@vben/types';
+
+import { parseQueryValues } from '@vben/utils';
+
+import { requestClient } from '#/api/request';
+
+interface AttachmentPartialEntity
+  extends Partial<Omit<AttachmentEntity, 'attid'>> {
+  attid?: string;
+}
+
+interface AttachmentQueryParams extends AttachmentPartialEntity, PageConfig {}
+
+/**
+ * 附件信息_列表
+ */
+export async function getAttachmentListApi(params: AttachmentQueryParams) {
+  return requestClient.post<any>('/api/query/list?pagevalue=97', {
+    pageindex: params.pageindex,
+    rows: params.rows,
+    ...parseQueryValues({
+      attlsh: params.attlsh,
+      attmodel: params.attmodel,
+    }),
+  });
+}
+
+/**
+ * 新增图片并返回id
+ */
+export async function addImageApi(params: AttachmentEntity) {
+  return requestClient.post<any>('/api/attachment/addimg?pagevalue=93', {
+    ...params,
+  });
+}
+
+/**
+ * 添加附件记录并返回路径
+ */
+export async function addAttachmentApi(data: { id: number }) {
+  return requestClient.post<any>(
+    '/api/attachment/addtopath?pagevalue=94',
+    {
+      ...parseQueryValues(data),
+    },
+    { formatData: true },
+  );
+}
+
+/**
+ * 删除附件记录
+ */
+export async function deleteAttachmentApi(data: { attid: string }) {
+  return requestClient.post<any>('/api/attachment/del?pagevalue=95', {
+    ...data,
+  });
+}
+
+/**
+ * 更新附件记录
+ */
+export async function updateAttachmentApi(data: { attid: string }) {
+  return requestClient.post<any>('/api/attachment/up?pagevalue=96', {
+    ...data,
+  });
+}

+ 209 - 7
apps/web-ele/src/views/order-manage/form.vue

@@ -1,13 +1,16 @@
 <script lang="ts" setup>
+import type { ExtendedFormApi } from '@vben/common-ui';
 import type { OrdersEntity } from '@vben/types';
 
-import { computed, ref } from 'vue';
+import { computed, h, ref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
-import { ElMessage } from 'element-plus';
+import { ElImage, ElMessage } from 'element-plus';
 
 import { useVbenForm, z } from '#/adapter/form';
+import { getDictListApi } from '#/api/dict';
+import { getAttachmentListApi } from '#/api/file';
 import { addOrdersApi, editOrdersApi, getOrdersDetailApi } from '#/api/orders';
 
 const emit = defineEmits(['finish']);
@@ -22,6 +25,9 @@ const titleMap = {
 
 const getTitle = computed(() => titleMap[formType.value]);
 
+const invoiceDataList = ref<any[]>([{}]);
+const certificateDataList = ref<any[]>([]);
+
 const [BaseForm, baseFormApi] = useVbenForm({
   showDefaultActions: false,
   // 所有表单项共用,可单独在表单内覆盖
@@ -202,19 +208,215 @@ const [Modal, modalApi] = useVbenModal({
 
       try {
         modalApi.setState({ loading: true });
-        const detailData = await getOrdersDetailApi({
-          ordersid: data.value.row.ordersid,
+
+        invoiceDataList.value = [];
+        certificateDataList.value = [];
+
+        // 去掉schema中invoiceAttachments和certificateAttachments字段,避免页面不更新
+        baseFormApi.setState({
+          schema: baseFormApi
+            .getState()
+            ?.schema?.filter(
+              (item) =>
+                item.fieldName !== 'invoiceAttachments' &&
+                item.fieldName !== 'certificateAttachments',
+            ),
         });
 
-        baseFormApi.setValues(detailData);
-      } catch {
-        // console.log(error);
+        const filePrefix = await getFilePrefix();
+        const results = await Promise.allSettled([
+          getOrderDetail(data.value.row.ordersid, baseFormApi),
+          getOrderInvoice(data.value.row.ordersid, filePrefix),
+          getOrderCertificate(data.value.row.ordersid, filePrefix),
+        ]);
+
+        // 更新schema
+        const schema = baseFormApi.getState()?.schema ?? [];
+
+        // 检查schema中是否已存在invoiceAttachments字段
+        const hasInvoiceAttachments = schema.some(
+          (item) => item.fieldName === 'invoiceAttachments',
+        );
+
+        // 如果不存在,则添加发票附件字段
+        if (!hasInvoiceAttachments && invoiceDataList.value.length > 0) {
+          baseFormApi.setState({
+            schema: [
+              ...schema,
+              {
+                component: h(
+                  'div',
+                  { class: 'grid-cols-1 lg:grid-cols-2 flex flex-wrap gap-3' },
+                  invoiceDataList.value.map((item) => {
+                    return h(ElImage, {
+                      src: item.url,
+                      previewSrcList: invoiceDataList.value.map((i) => i.url),
+                      fit: 'cover',
+                      style: 'width: 100px; height: 100px;',
+                      class: 'border rounded',
+                      previewTeleported: true,
+                    });
+                  }),
+                ),
+                fieldName: 'invoiceAttachments',
+                label: '发票附件',
+                // formItemClass: 'lg:col-span-2',
+              },
+            ],
+          });
+        } else {
+          // 设置空数据提示
+          baseFormApi.setState({
+            schema: [
+              ...schema,
+              {
+                component: h(
+                  'div',
+                  {
+                    class:
+                      'grid-cols-1 lg:grid-cols-2 flex flex-wrap gap-3 text-sm',
+                  },
+                  '暂无',
+                ),
+                fieldName: 'invoiceAttachments',
+                label: '发票附件',
+                // formItemClass: 'lg:col-span-2',
+              },
+            ],
+          });
+        }
+
+        // 检查schema中是否已存在certificateAttachments字段
+        const hasCertificateAttachments = schema.some(
+          (item) => item.fieldName === 'certificateAttachments',
+        );
+
+        // 如果不存在,则添加证书附件字段
+        if (
+          !hasCertificateAttachments &&
+          certificateDataList.value.length > 0
+        ) {
+          baseFormApi.setState({
+            schema: [
+              ...(baseFormApi.getState()?.schema ?? []),
+              {
+                component: h(
+                  'div',
+                  { class: 'grid-cols-1 lg:grid-cols-2 flex flex-wrap gap-3' },
+                  certificateDataList.value.map((item) => {
+                    return h(ElImage, {
+                      src: item.url,
+                      previewSrcList: certificateDataList.value.map(
+                        (i) => i.url,
+                      ),
+                      fit: 'cover',
+                      style: 'width: 100px; height: 100px;',
+                      class: 'border rounded',
+                      previewTeleported: true,
+                    });
+                  }),
+                ),
+                fieldName: 'certificateAttachments',
+                label: '证书附件',
+                // formItemClass: 'lg:col-span-2',
+              },
+            ],
+          });
+        } else {
+          baseFormApi.setState({
+            schema: [
+              ...(baseFormApi.getState()?.schema ?? []),
+              {
+                component: h(
+                  'div',
+                  {
+                    class:
+                      'grid-cols-1 lg:grid-cols-2 flex flex-wrap gap-3 text-sm',
+                  },
+                  '暂无',
+                ),
+                fieldName: 'certificateAttachments',
+                label: '证书附件',
+                // formItemClass: 'lg:col-span-2',
+              },
+            ],
+          });
+        }
+
+        // 可以选择处理失败的请求
+        results.forEach((result, index) => {
+          if (result.status === 'rejected') {
+            console.warn(`请求 ${index} 失败:`, result.reason);
+          }
+        });
+      } catch (error) {
+        console.error(error);
       }
 
       modalApi.setState({ loading: false });
     }
   },
 });
+
+// 获取订单详情
+const getOrderDetail = async (ordersid: string, formApi: ExtendedFormApi) => {
+  const detailData = await getOrdersDetailApi({
+    ordersid,
+  });
+
+  formApi.setValues(detailData);
+};
+
+// 获取订单发票附件
+const getOrderInvoice = async (ordersid: string, filePrefix: string) => {
+  const invoiceData = await getAttachmentListApi({
+    attlsh: ordersid,
+    attmodel: 'orders_invoice',
+    pageindex: 1,
+    rows: 10,
+  });
+
+  if (invoiceData.Data.length > 0) {
+    invoiceData.Data.forEach((item: any) => {
+      item.url = `${filePrefix}${item.attpath}${item.attname}.${item.atttype}`;
+    });
+  }
+
+  invoiceDataList.value = invoiceData.Data;
+};
+
+// 获取订单证件附件
+const getOrderCertificate = async (ordersid: string, filePrefix: string) => {
+  const certificateData = await getAttachmentListApi({
+    attlsh: ordersid,
+    attmodel: 'orders_identity',
+    pageindex: 1,
+    rows: 10,
+  });
+
+  if (certificateData.Data.length > 0) {
+    certificateData.Data.forEach((item: any) => {
+      item.url = `${filePrefix}${item.attpath}${item.attname}.${item.atttype}`;
+    });
+  }
+
+  certificateDataList.value = certificateData.Data;
+};
+
+// 获取文件前缀地址
+const getFilePrefix = async () => {
+  const filePrefixData = await getDictListApi({
+    groupname: 'fileheadurl',
+    pageindex: 1,
+    rows: 999,
+  });
+
+  if (filePrefixData.Data.length > 0) {
+    return filePrefixData.Data[0].substance;
+  }
+
+  return '';
+};
 </script>
 
 <template>

+ 13 - 10
apps/web-ele/src/views/system-manage/menu-manage/index.vue

@@ -7,6 +7,7 @@ import { h } from 'vue';
 
 import { Page, useVbenModal } from '@vben/common-ui';
 import { MdiDelete, MdiDetail, MdiEdit } from '@vben/icons';
+import { parseQueryValues } from '@vben/utils';
 
 import { ElMessage, ElMessageBox, ElTag } from 'element-plus';
 
@@ -33,15 +34,15 @@ const formOptions: VbenFormProps = {
         allowClear: true,
       },
     },
-    {
-      component: 'Input',
-      fieldName: 'menu_sort',
-      label: '菜单分类',
-      componentProps: {
-        placeholder: $t('ui.placeholder.input'),
-        allowClear: true,
-      },
-    },
+    // {
+    //   component: 'Input',
+    //   fieldName: 'menu_sort',
+    //   label: '菜单分类',
+    //   componentProps: {
+    //     placeholder: $t('ui.placeholder.input'),
+    //     allowClear: true,
+    //   },
+    // },
     {
       component: 'Select',
       fieldName: 'menu_type',
@@ -49,6 +50,7 @@ const formOptions: VbenFormProps = {
       componentProps: {
         placeholder: $t('ui.placeholder.select'),
         allowClear: true,
+        clearable: true,
         options: [
           { label: '目录', value: 1 },
           { label: '菜单', value: 2 },
@@ -86,7 +88,7 @@ const gridOptions: VxeGridProps<any> = {
         return await getMenuListApi({
           pageindex: page.currentPage,
           rows: page.pageSize,
-          ...formValues,
+          ...parseQueryValues(formValues),
         });
       },
     },
@@ -94,6 +96,7 @@ const gridOptions: VxeGridProps<any> = {
 
   columns: [
     { title: '菜单名称', field: 'menu_name', sortable: true },
+    { title: '备注', field: 'remark', sortable: true },
     // { title: '菜单分类', field: 'menu_sort' },
     {
       title: '菜单类型',

+ 59 - 0
packages/types/src/file.ts

@@ -0,0 +1,59 @@
+// CREATE TABLE `attachment` (
+//   `attid` varchar(32) NOT NULL COMMENT '附件ID(查询条件)',
+//   `attname` varchar(32) NOT NULL COMMENT '文件名',
+//   `attpath` varchar(200) NOT NULL COMMENT '路径',
+//   `atttype` varchar(10) NOT NULL COMMENT '扩展名',
+//   `attsize` varchar(20) NOT NULL COMMENT '文件大小',
+//   `attmodel` varchar(20) NOT NULL COMMENT '关联模块(查询条件)',
+//   `attlsh` varchar(32) DEFAULT NULL COMMENT '关联表单流水号(查询条件)',
+//   `attcreate` datetime NOT NULL COMMENT '创建时间#不可编辑(禁止前端编辑)(查询条件)',
+//   `attcreateuser` varchar(30) DEFAULT NULL COMMENT '上传者#不可编辑(禁止前端编辑)',
+//   `attdelcode` tinyint(4) DEFAULT NULL COMMENT '删除标记(禁止前端编辑)(禁止插入)',
+//   `attother1` varchar(50) DEFAULT NULL COMMENT '附加参数1',
+//   `attother2` varchar(50) DEFAULT NULL COMMENT '附加参数2',
+//   `attother3` varchar(50) DEFAULT NULL COMMENT '附加参数3',
+//   `attorginname` varchar(255) DEFAULT NULL COMMENT '文件原始名称',
+//   `attfileSHA1` varchar(100) DEFAULT NULL COMMENT '文件SHA1值',
+//   `attfileSHA256` varchar(100) DEFAULT NULL COMMENT '文件SHA256值',
+//   `attfileMD5` varchar(100) DEFAULT NULL COMMENT '文件MD5值',
+//   PRIMARY KEY (`attid`)
+// ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='附件';
+
+interface AttachmentEntity {
+  /** 附件ID(查询条件) */
+  attid: string;
+  /** 文件名 */
+  attname: string;
+  /** 路径 */
+  attpath: string;
+  /** 扩展名 */
+  atttype: string;
+  /** 文件大小 */
+  attsize: string;
+  /** 关联模块(查询条件) */
+  attmodel: string;
+  /** 关联表单流水号(查询条件) */
+  attlsh: string;
+  /** 创建时间#不可编辑(禁止前端编辑)(查询条件) */
+  attcreate: string;
+  /** 上传者#不可编辑(禁止前端编辑) */
+  attcreateuser: string;
+  /** 删除标记(禁止前端编辑)(禁止插入) */
+  attdelcode: number;
+  /** 附加参数1 */
+  attother1: string;
+  /** 附加参数2 */
+  attother2: string;
+  /** 附加参数3 */
+  attother3: string;
+  /** 文件原始名称 */
+  attorginname: string;
+  /** 文件SHA1值 */
+  attfileSHA1: string;
+  /** 文件SHA256值 */
+  attfileSHA256: string;
+  /** 文件MD5值 */
+  attfileMD5: string;
+}
+
+export type { AttachmentEntity };

+ 1 - 0
packages/types/src/index.ts

@@ -3,6 +3,7 @@ export type * from './base';
 export type * from './coupon1';
 export type * from './coupon2';
 export type * from './dict';
+export type * from './file';
 export type * from './log';
 export type * from './menu';
 export type * from './orders';