jingbb 5 месяцев назад
Родитель
Сommit
9252424971

+ 70 - 1
src/views/saleCode/saleContract/SaleContract.api.ts

@@ -7,12 +7,19 @@ enum Api {
   list = '/saleCode/saleContract/list',
   save='/saleCode/saleContract/add',
   edit='/saleCode/saleContract/edit',
+  editHis ='/saleCode/saleContract/editHis',
   deleteOne = '/saleCode/saleContract/delete',
   deleteBatch = '/saleCode/saleContract/deleteBatch',
   importExcel = '/saleCode/saleContract/importExcel',
   exportXls = '/saleCode/saleContract/exportXls',
   saleContractShipList = '/saleCode/saleContract/querySaleContractShipByMainId',
+  saleVersonShipList = '/saleCode/saleContractHis/querySaleContractShipHisByMainId',
   saleContractProductList = '/saleCode/saleContract/querySaleContractProductByMainId',
+  saleVersonProductList = '/saleCode/saleContractHis/querySaleContractProductHisByMainId',
+  submitBatch='/saleCode/saleContract/submitBatch',
+  cancelSubmitBatch='/saleCode/saleContract/returnSubmitBatch',
+  closeBill='/saleCode/saleContract/closeBatch',
+  queryVersonHistoryById='/saleCode/saleContractHis/queryById',
 }
 /**
  * 导出api
@@ -29,6 +36,22 @@ export const getImportUrl = Api.importExcel;
  * @param params
  */
 export const saleContractShipList = Api.saleContractShipList;
+
+/**
+ * 查询历史版本船子表数据
+ * @param params
+ */
+export const querysaleVersonFormShipListByMainId = (id) => defHttp.get({url: Api.saleVersonShipList, params:{ id }});
+
+/**
+ * 查询历史版本产品子表数据
+ * @param params
+ */
+export const querySaleVersonProductListByMainId = (id) => defHttp.get({url: Api.saleVersonProductList, params:{ id }});
+
+//历史版本详情主表
+export const queryVersonHistoryById = (id) => defHttp.get({url: Api.queryVersonHistoryById, params:{ id }});
+
 /**
  * 查询子表数据
  * @param params
@@ -71,7 +94,53 @@ export const batchDelete = (params, handleSuccess) => {
  * 保存或者更新
  * @param params
  */
-export const saveOrUpdate = (params, isUpdate) => {
+export const saveOrUpdate = (params, isUpdate,isRevise) => {
   let url = isUpdate ? Api.edit : Api.save;
+  url = isRevise?Api.editHis:url;
   return defHttp.post({url: url, params});
 }
+// 提交
+export const batchSubmit = (params, handleSuccess) => {
+  createConfirm({
+    iconType: 'warning',
+    title: '确认提交',
+    content: '是否提交选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.get({url: Api.submitBatch, params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+// 取消提交
+export const cancelBatchSubmit = (params, handleSuccess) => {
+  createConfirm({
+    iconType: 'warning',
+    title: '确认取消提交',
+    content: '是否取消提交选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.get({url: Api.cancelSubmitBatch, params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+// 关闭
+export const closeBill = (params, handleSuccess) => {
+  createConfirm({
+    iconType: 'warning',
+    title: '确认关闭',
+    content: '是否关闭选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.get({url: Api.closeBill, params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}

+ 244 - 267
src/views/saleCode/saleContract/SaleContract.data.ts

@@ -1,23 +1,16 @@
 import {BasicColumn} from '/@/components/Table';
 import {FormSchema} from '/@/components/Table';
-import { rules} from '/@/utils/helper/validator';
-import { render } from '/@/utils/common/renderUtils';
 import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types'
-import { getWeekMonthQuarterYear } from '/@/utils';
+import { defHttp } from '/@/utils/http/axios';
 //列表数据
 export const columns: BasicColumn[] = [
-   {
-    title: '历史主键',
-    align:"center",
-    dataIndex: 'hisId'
-   },
-   {
-    title: '状态(1-已提交,0-未提交)',
+  {
+    title: '单据编码(bill code)',
     align:"center",
-    dataIndex: 'status'
+    dataIndex: 'billCode'
    },
    {
-    title: '单据日期',
+    title: '单据日期(bill date)',
     align:"center",
     sorter: true,
     dataIndex: 'billDate',
@@ -27,35 +20,15 @@ export const columns: BasicColumn[] = [
     },
    },
    {
-    title: '单据编码',
-    align:"center",
-    dataIndex: 'billCode'
-   },
-   {
-    title: '报价项目',
-    align:"center",
-    dataIndex: 'quotationProject'
-   },
-   {
-    title: '报价项目名称',
+    title: '项目(Project)',
     align:"center",
     dataIndex: 'quotationProjectName'
    },
    {
-    title: '报价客户',
-    align:"center",
-    dataIndex: 'quotationCustomer'
-   },
-   {
-    title: '报价客户名称',
+    title: '客户(Customer)',
     align:"center",
     dataIndex: 'quotationCustomerName'
    },
-   {
-    title: '业务类型(busyness type)',
-    align:"center",
-    dataIndex: 'busynessType'
-   },
    {
     title: '优先级(priority)',
     align:"center",
@@ -77,188 +50,194 @@ export const columns: BasicColumn[] = [
     dataIndex: 'maker'
    },
    {
-    title: '币种(currency)',
-    align:"center",
-    dataIndex: 'currency'
-   },
-   {
-    title: '交货条款(delivery terms)',
-    align:"center",
-    dataIndex: 'deliveryTerms'
-   },
-   {
-    title: '付款条件(payment terms)',
-    align:"center",
-    dataIndex: 'paymentTerms'
-   },
-   {
-    title: '付款条件2',
+    title: '业务类型(busyness type)',
     align:"center",
-    dataIndex: 'paymentInfo'
+    dataIndex: 'busynessType',
+    // width:250,
    },
    {
     title: '销售部门(sale department)',
     align:"center",
-    dataIndex: 'saleDepartment_dictText'
+    dataIndex: 'saleDepartment'
    },
    {
     title: '业务员(salesman)',
     align:"center",
-    dataIndex: 'salesman_dictText'
-   },
-   {
-    title: '汇率(exchange rate)',
-    align:"center",
-    dataIndex: 'exchangeRate'
+    dataIndex: 'salesman'
    },
    {
-    title: '备注(notes)',
+    title: '关闭(close)',
     align:"center",
-    dataIndex: 'notes'
+    dataIndex: 'isClose_dictText'
    },
    {
-    title: '附件(attachs)',
+    title: '提交(submit)',
     align:"center",
-    dataIndex: 'attachs'
+    dataIndex: 'status_dictText'
    },
    {
     title: '版本号',
     align:"center",
     dataIndex: 'version'
    },
-   {
-    title: '关闭(1-是,0-否)',
-    align:"center",
-    dataIndex: 'isClose'
-   },
 ];
 //查询数据
 export const searchFormSchema: FormSchema[] = [
-	{
-      label: "状态(1-已提交,0-未提交)",
-      field: "status",
-      component: 'InputNumber',
-      //colProps: {span: 6},
- 	},
-     {
-      label: "单据日期",
+    {
+      label: "单据编码(bill code)",
+      field: "billCode",
+      component: 'Input',
+      labelWidth: 150,
+        //colProps: {span: 6},
+    },
+    {
+      label: "单据日期(bill date)",
       field: "billDate",
       component: 'RangePicker',
+      labelWidth: 150,
       componentProps: {
         valueType: 'Date',
       },
       //colProps: {span: 6},
 	},
+  {
+    label: "业务类型(busyness type)",
+    field: "busynessType",
+    labelWidth: 180,
+    component: 'JDictSelectTag',
+    componentProps:{
+      dictCode:"busyness_type"
+    },
+    //colProps: {span: 6},
+  },
+	
 	{
-      label: "单据编码",
-      field: "billCode",
-      component: 'Input',
-      //colProps: {span: 6},
- 	},
-	{
-      label: "报价项目名称",
-      field: "quotationProjectName",
-      component: 'Input',
-      //colProps: {span: 6},
- 	},
-	{
-      label: "报价客户名称",
+      label: "客户(Customer)",
       field: "quotationCustomerName",
+      labelWidth: 150,
       component: 'Input',
       //colProps: {span: 6},
  	},
-	{
-      label: "业务类型(busyness type)",
-      field: "busynessType",
-      component: 'Input',
-      //colProps: {span: 6},
- 	},
+  {
+    label: "项目(Project)",
+    field: "quotationProjectName",
+    labelWidth: 150,
+    component: 'Input',
+    //colProps: {span: 6},
+  },
+
 	{
       label: "优先级(priority)",
       field: "priority",
-      component: 'Input',
+      labelWidth: 150,
+      component: 'JDictSelectTag',
+      componentProps:{
+        dictCode:"priority"
+      },
       //colProps: {span: 6},
  	},
 	{
       label: "产品分类(production class)",
       field: "productionClass",
-      component: 'Input',
+      labelWidth: 180,
+      component: 'ApiSelect',
+      componentProps: {
+              // mode: 'multiple',//multiple: 多选;不填写为单选
+              //请求api,返回结果{ result: { records: [{'id':'1',name:'scott'},{'id':'2',name:'小张'}] }}
+              api: ()=> defHttp.get({ url: 'baseCode/baseProductClass/list?pageSize=-1' }),
+              //数值转成String
+              numberToString: false,
+              //标题字段
+              labelField: 'name',
+              //值字段
+              valueField: 'id',
+              //请求参数
+              params:{},
+              //返回结果字段
+              resultField:'records'
+            },
       //colProps: {span: 6},
  	},
 	{
       label: "机型(model)",
       field: "model",
-      component: 'Input',
+      labelWidth: 150,
+      component: 'JDictSelectTag',
+      componentProps:{
+        dictCode:"model_typer"
+      },
       //colProps: {span: 6},
  	},
 	{
       label: "厂家(maker)",
       field: "maker",
+      labelWidth: 150,
       component: 'Input',
-      //colProps: {span: 6},
- 	},
-	{
-      label: "销售部门(sale department)",
-      field: "saleDepartment",
-      component: 'JSelectDept',
-      componentProps:{
-      },
       //colProps: {span: 6},
  	},
 	{
       label: "业务员(salesman)",
       field: "salesman",
+      labelWidth: 150,
       component: 'JSelectUser',
-     componentProps:{
-     },
+      componentProps:{
+      },
       //colProps: {span: 6},
  	},
+   {
+    label: "销售部门(sale department)",
+    field: "saleDepartment",
+    labelWidth: 180,
+    component: 'JSelectDept',
+    componentProps:{
+    },
+    //colProps: {span: 6},
+ },
+   {
+    label: "提交(submit)",
+    field: "status",
+    labelWidth: 150,
+    component: 'JDictSelectTag',
+    componentProps:{
+      dictCode:"yes_or_no"
+    },
+    //colProps: {span: 6},
+  },
 	{
-      label: "关闭(1-是,0-否)",
-      field: "isClose",
-      component: 'InputNumber',
+    label: "关闭(close)",
+    field: "isClose",
+    labelWidth: 150,
+    component: 'JDictSelectTag',
+    componentProps:{
+      dictCode:"yes_or_no"
+    },
       //colProps: {span: 6},
  	},
 ];
 //表单数据
 export const formSchema: FormSchema[] = [
   {
-    label: '历史主键',
-    field: 'hisId',
-    component: 'Input',
-  },
-  {
-    label: '状态(1-已提交,0-未提交)',
-    field: 'status',
-    component: 'InputNumber',
-  },
-  {
-    label: '单据日期',
+    label: '单据日期(bill date)',
     field: 'billDate',
     component: 'DatePicker',
-    componentProps:{
-      valueFormat: 'YYYY-MM-DD'
-    },    
-    dynamicRules: ({model,schema}) => {
-          return [
-                 { required: true, message: '请输入单据日期!'},
-          ];
-     },
+    componentProps: {
+      valueFormat: 'YYYY-MM-DD',
+    },
+    dynamicDisabled:true,  
+    labelWidth: 200,
   },
   {
-    label: '单据编码',
+    label: '合同编号(bill code)',
     field: 'billCode',
+    labelWidth: 200,
     component: 'Input',
   },
   {
-    label: '报价项目',
-    field: 'quotationProject',
-    component: 'Input',
-  },
-  {
-    label: '报价项目名称',
+    label: '报价项目(quotation project)',
+    labelWidth: 200,
     field: 'quotationProjectName',
-    component: 'Input',
+    component: 'InputSearch',
+    slot: 'quotationProjectName',
     dynamicRules: ({model,schema}) => {
           return [
                  { required: true, message: '请输入报价项目名称!'},
@@ -266,312 +245,297 @@ export const formSchema: FormSchema[] = [
      },
   },
   {
-    label: '报价客户',
-    field: 'quotationCustomer',
-    component: 'Input',
-  },
-  {
-    label: '报价客户名称',
+    label: '客户(customer)',
+    labelWidth: 200,
     field: 'quotationCustomerName',
     component: 'Input',
+    dynamicDisabled:true,  
   },
   {
     label: '业务类型(busyness type)',
+    labelWidth: 200,
     field: 'busynessType',
-    component: 'Input',
+    component: 'JDictSelectTag',
+    componentProps:{
+      dictCode:"busyness_type"
+    },
   },
   {
     label: '优先级(priority)',
+    labelWidth: 200,
     field: 'priority',
-    component: 'Input',
+    component: 'JDictSelectTag',
+    componentProps:{
+      dictCode:"priority"
+    },
   },
   {
     label: '产品分类(production class)',
+    labelWidth: 200,
     field: 'productionClass',
+    slot: 'productionClass',
     component: 'Input',
   },
   {
     label: '机型(model)',
     field: 'model',
-    component: 'Input',
+    labelWidth: 200,
+    component: 'JDictSelectTag',
+    componentProps:{
+      dictCode:"model_typer"
+    },
   },
   {
     label: '厂家(maker)',
+    labelWidth: 200,
     field: 'maker',
     component: 'Input',
   },
   {
     label: '币种(currency)',
+    labelWidth: 200,
     field: 'currency',
-    component: 'Input',
+    component: 'JDictSelectTag',
+    componentProps:{
+      dictCode:"currency"
+    },
   },
   {
     label: '交货条款(delivery terms)',
+    labelWidth: 200,
     field: 'deliveryTerms',
-    component: 'Input',
+    component: 'JDictSelectTag',
+    componentProps:{
+      dictCode:"delivery_terms"
+    },
   },
+
   {
     label: '付款条件(payment terms)',
     field: 'paymentTerms',
-    component: 'Input',
+    labelWidth: 200,
+    component: 'JDictSelectTag',
+    componentProps:{
+      dictCode:"payment_terms"
+    },
   },
   {
     label: '付款条件2',
     field: 'paymentInfo',
+    labelWidth: 200,
     component: 'Input',
   },
   {
     label: '销售部门(sale department)',
     field: 'saleDepartment',
-     component: 'JSelectDept',
-     componentProps:{
-     },
+    labelWidth: 200,
+    component: 'Input',
+    dynamicDisabled:true,  
+    componentProps:{
+    },
   },
   {
     label: '业务员(salesman)',
     field: 'salesman',
-    component: 'JSelectUser',
-     componentProps:{
-     },
+    labelWidth: 200,
+    component: 'Input',
+    dynamicDisabled:true,  
+    componentProps:{
+    },
   },
   {
     label: '汇率(exchange rate)',
     field: 'exchangeRate',
+    labelWidth: 200,
     component: 'Input',
   },
   {
     label: '备注(notes)',
     field: 'notes',
+    labelWidth: 200,
     component: 'Input',
   },
   {
     label: '附件(attachs)',
     field: 'attachs',
-    component: 'Input',
+    labelWidth: 200,
+    component: 'JUpload',
   },
   {
-    label: '版本号',
-    field: 'version',
-    component: 'Input',
-  },
-  {
-    label: '关闭(1-是,0-否)',
-    field: 'isClose',
-    component: 'InputNumber',
-  },
-	// TODO 主键隐藏字段,目前写死为ID
-	{
 	  label: '',
 	  field: 'id',
 	  component: 'Input',
 	  show: false
 	},
+  {
+	  label: '',
+	  field: 'quotationCustomer',
+	  component: 'Input',
+	  show: false
+	},
+  {
+	  label: '',
+	  field: 'quotationProject',
+	  component: 'Input',
+	  show: false
+	},
+  {
+	  label: '',
+	  field: 'status',
+	  component: 'Input',
+	  show: false
+	},
 ];
 //子表单数据
 //子表表格配置
 export const saleContractShipColumns: JVxeColumn[] = [
     {
-      title: '状态(1-启用,0-停用)',
-      key: 'status',
-      type: JVxeTypes.inputNumber,
-      width:"200px",
-      placeholder: '请输入${title}',
-      defaultValue:'',
-    },
-    {
-      title: '表头主键(销售合同)',
-      key: 'headId',
-      type: JVxeTypes.input,
-      width:"200px",
-      placeholder: '请输入${title}',
-      defaultValue:'',
-    },
-    {
-      title: '船id',
-      key: 'shipId',
-      type: JVxeTypes.input,
-      width:"200px",
-      placeholder: '请输入${title}',
-      defaultValue:'',
-    },
-    {
-      title: '船名',
+      title: '船名(ship name)',
       key: 'shipName',
-      type: JVxeTypes.input,
-      width:"200px",
+      type: JVxeTypes.normal,
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '主机号',
+      title: '主机号(hostN number)',
       key: 'hostNumber',
       type: JVxeTypes.input,
-      width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '工程编号',
+      title: '工程编号(project No)',
       key: 'projectNo',
       type: JVxeTypes.input,
-      width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '船厂',
+      title: '船厂(ship factory)',
       key: 'shipFactory',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '船东',
+      title: '船东(shipowner)',
       key: 'shipowner',
-      type: JVxeTypes.input,
-      width:"200px",
-      placeholder: '请输入${title}',
-      defaultValue:'',
-    },
-  ]
-export const saleContractProductColumns: JVxeColumn[] = [
-    {
-      title: '状态(1-启用,0-停用)',
-      key: 'status',
-      type: JVxeTypes.inputNumber,
-      width:"200px",
+      type: JVxeTypes.normal,
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '表头主键(销售报价单)',
-      key: 'headId',
-      type: JVxeTypes.input,
-      width:"200px",
-      placeholder: '请输入${title}',
-      defaultValue:'',
+      title: '操作(operation)',
+      key: 'action',
+      width:"400px",
+      // 固定在右侧
+      fixed: 'right',
+      // 对齐方式为居中
+      align: 'center',
+      // 组件类型定义为【插槽】
+      type: JVxeTypes.slot,
+      // slot 的名称,对应 v-slot 冒号后面和等号前面的内容
+      slotName: 'action',
     },
+  ]
+export const saleContractProductColumns: JVxeColumn[] = [
     {
-      title: '交期',
+      title: '交期(delivery time)',
       key: 'deliveryTime',
-      type: JVxeTypes.datetime,
-      width:"200px",
-      placeholder: '请输入${title}',
-      defaultValue:'',
-    },
-    {
-      title: '产品id',
-      key: 'productId',
-      type: JVxeTypes.input,
+      type: JVxeTypes.date,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '产品分类',
+      title: '产品分类(product class)',
       key: 'productClass',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '产品编码',
+      title: '产品编码(product code)',
       key: 'productCode',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '产品中文名',
+      title: '产品中文名chinese name)',
       key: 'chineseName',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '产品英文名',
+      title: '产品英文名(english name)',
       key: 'englishName',
-      type: JVxeTypes.input,
-      width:"200px",
-      placeholder: '请输入${title}',
-      defaultValue:'',
-    },
-    {
-      title: '规格',
-      key: 'specifications',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '型号',
+      title: '型号(model)',
       key: 'model',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '备件号',
+      title: '备件号(partno)',
       key: 'partno',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '图号',
+      title: '图号(drawingno)',
       key: 'drawingno',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '订货号',
+      title: '订货号(orderno)',
       key: 'orderno',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '厂家',
+      title: '厂家(factory)',
       key: 'factory',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '质量等级',
+      title: '质量等级(quality grade)',
       key: 'qualityGrade',
-      type: JVxeTypes.input,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
     {
-      title: '数量',
+      title: '数量(quantity)',
       key: 'quantity',
       type: JVxeTypes.inputNumber,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
     },
-    {
-      title: '单位',
-      key: 'unit',
-      type: JVxeTypes.input,
-      width:"200px",
-      placeholder: '请输入${title}',
-      defaultValue:'',
-    },
     {
       title: '税率(tax rate)',
       key: 'taxRate',
@@ -599,7 +563,7 @@ export const saleContractProductColumns: JVxeColumn[] = [
     {
       title: '含税金额(tax amount)',
       key: 'taxAmount',
-      type: JVxeTypes.inputNumber,
+      type: JVxeTypes.normal,
       width:"200px",
       placeholder: '请输入${title}',
       defaultValue:'',
@@ -612,6 +576,19 @@ export const saleContractProductColumns: JVxeColumn[] = [
       placeholder: '请输入${title}',
       defaultValue:'',
     },
+    {
+      title: '操作(operation)',
+      key: 'action',
+      width:"200px",
+      // 固定在右侧
+      fixed: 'right',
+      // 对齐方式为居中
+      align: 'center',
+      // 组件类型定义为【插槽】
+      type: JVxeTypes.slot,
+      // slot 的名称,对应 v-slot 冒号后面和等号前面的内容
+      slotName: 'action',
+    },
   ]
 
 

+ 81 - 38
src/views/saleCode/saleContract/SaleContractList.vue

@@ -4,15 +4,17 @@
    <BasicTable @register="registerTable" :rowSelection="rowSelection">
      <!--插槽:table标题-->
       <template #tableTitle>
-          <a-button type="primary" v-auth="'saleCode:sale_contract:add'"  @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
-          <a-button  type="primary" v-auth="'saleCode:sale_contract:exportXls'"  preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
-          <j-upload-button  type="primary" v-auth="'saleCode:sale_contract:importExcel'"  preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+          <a-button type="primary" v-auth="'saleCode:sale_contract:add'"  @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增(add)</a-button>
+          <a-button  type="primary" v-auth="'saleCode:sale_contract:exportXls'"  preIcon="ant-design:export-outlined" @click="onExportXls"> 导出(export)</a-button>
+          <a-button  type="primary" v-auth="'saleCode:sale_contract:exportXls'"  @click="submit"> 提交(submit)</a-button>
+          <a-button  type="primary" v-auth="'saleCode:sale_contract:exportXls'"   @click="cancelSubmit"> 取消提交(cancel submit)</a-button>
+          <a-button  type="primary" v-auth="'saleCode:sale_contract:exportXls'"   @click="closeBillData"> 关闭(close)</a-button>
           <a-dropdown v-if="selectedRowKeys.length > 0">
               <template #overlay>
                 <a-menu>
                   <a-menu-item key="1" @click="batchHandleDelete">
                     <Icon icon="ant-design:delete-outlined"></Icon>
-                    删除
+                    删除(delete)
                   </a-menu-item>
                 </a-menu>
               </template>
@@ -20,8 +22,6 @@
                 <Icon icon="mdi:chevron-down"></Icon>
               </a-button>
         </a-dropdown>
-        <!-- 高级查询 -->
-        <super-query :config="superQueryConfig" @search="handleSuperQuery" />
       </template>
        <!--操作栏-->
       <template #action="{ record }">
@@ -33,26 +33,26 @@
     </BasicTable>
     <!-- 表单区域 -->
     <SaleContractModal @register="registerModal" @success="handleSuccess"></SaleContractModal>
+    <ViewHistoryVersionModal ref="ViewHistoryVersionModalRef" @success="handleSuccess"></ViewHistoryVersionModal>
   </div>
 </template>
 
 <script lang="ts" name="saleCode-saleContract" setup>
-  import {ref, reactive, computed, unref} from 'vue';
-  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import {ref, reactive} from 'vue';
+  import {BasicTable, TableAction} from '/@/components/Table';
   import { useListPage } from '/@/hooks/system/useListPage'
   import {useModal} from '/@/components/Modal';
   import SaleContractModal from './components/SaleContractModal.vue'
-  import {columns, searchFormSchema, superQuerySchema} from './SaleContract.data';
-  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './SaleContract.api';
-  import {downloadFile} from '/@/utils/common/renderUtils';
-  import { useUserStore } from '/@/store/modules/user';
+  import ViewHistoryVersionModal from './components/ViewHistoryVersionModal.vue'
+  import {columns, searchFormSchema} from './SaleContract.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl,batchSubmit,cancelBatchSubmit,closeBill} from './SaleContract.api';
+  import { message } from 'ant-design-vue';
   const queryParam = reactive<any>({});
-  const checkedKeys = ref<Array<string | number>>([]);
-  const userStore = useUserStore();
+  var ViewHistoryVersionModalRef = ref();
   //注册model
   const [registerModal, {openModal}] = useModal();
    //注册table数据
-  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+  const { tableContext,onExportXls } = useListPage({
       tableProps:{
            title: '销售合同主表',
            api: list,
@@ -70,9 +70,12 @@
                 ],
             },
            actionColumn: {
-               width: 120,
+               width: 340,
                fixed:'right'
            },
+           scroll:{
+              x:'3000px'
+           },
            beforeFetch: (params) => {
              return Object.assign(params, queryParam);
            },
@@ -89,20 +92,6 @@
     })
 
   const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
-
-  // 高级查询配置
-  const superQueryConfig = reactive(superQuerySchema);
-
-  /**
-   * 高级查询事件
-   */
-  function handleSuperQuery(params) {
-    Object.keys(params).map((k) => {
-      queryParam[k] = params[k];
-    });
-    reload();
-  }
-
    /**
     * 新增事件
     */
@@ -110,6 +99,7 @@
      openModal(true, {
        isUpdate: false,
        showFooter: true,
+       isRevise: false
      });
   }
    /**
@@ -120,6 +110,7 @@
        record,
        isUpdate: true,
        showFooter: true,
+       isRevise: false
      });
    }
    /**
@@ -130,6 +121,7 @@
        record,
        isUpdate: true,
        showFooter: false,
+       isRevise: false
      });
    }
    /**
@@ -156,10 +148,21 @@
   function getTableAction(record){
        return [
          {
-           label: '编辑',
+           label: '编辑(edit)',
            onClick: handleEdit.bind(null, record),
-           auth: 'saleCode:sale_contract:edit'
-         }
+           auth: 'saleCode:sale_contract:edit',
+           ifShow: record.status=='0'
+         },
+         {
+           label: '修订(revise)',
+           ifShow: record.status=='1',
+           onClick: handleRevise.bind(null, record),
+         }, 
+         {
+           label: '查看历史版本(history)',
+           onClick: handleViewHistory.bind(null, record),
+           ifShow: record.status=='1'
+         }, 
        ]
    }
 
@@ -170,20 +173,60 @@
   function getDropDownAction(record){
     return [
       {
-        label: '详情',
+        label: '详情(detail)',
         onClick: handleDetail.bind(null, record),
-      }, {
-        label: '删除',
+      }, 
+      {
+        label: '删除(delete)',
         popConfirm: {
           title: '是否确认删除',
           confirm: handleDelete.bind(null, record),
           placement: 'topLeft'
         },
-        auth: 'saleCode:sale_contract:delete'
+        auth: 'saleCode:sale_contract:delete',
+        fShow: record.status=='0',
       }
     ]
   }
-
+  //提交
+  function submit(){
+    if(selectedRowKeys.value.length==0){
+      message.warning('请选择数据')
+    }else{
+      var ids=selectedRowKeys.value.join(',')
+      batchSubmit({ids: ids},handleSuccess);
+    }
+  }
+  //取消提交
+  function cancelSubmit(){
+    if(selectedRowKeys.value.length==0){
+      message.warning('请选择数据')
+    }else{
+      var ids=selectedRowKeys.value.join(',')
+      cancelBatchSubmit({ids: ids},handleSuccess);
+    }
+  }
+   //关闭
+   function closeBillData(){
+    if(selectedRowKeys.value.length==0){
+      message.warning('请选择数据')
+    }else{
+      var ids=selectedRowKeys.value.join(',')
+      closeBill({ids: ids},handleSuccess);
+    }
+  }
+  //修订
+  function handleRevise(record: Recordable){
+    openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+       isRevise: true
+     });
+   }
+  function handleViewHistory(record: Recordable){
+    ViewHistoryVersionModalRef.value.getTable(record)
+  }
 </script>
 
 <style lang="less" scoped>

+ 11 - 0
src/views/saleCode/saleContract/components/BaseProjectArchive.api.ts

@@ -0,0 +1,11 @@
+import {defHttp} from '/@/utils/http/axios';
+
+enum Api {
+  list = '/baseCode/baseProjectArchive/list'
+}
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});

+ 81 - 0
src/views/saleCode/saleContract/components/BaseProjectArchive.data.ts

@@ -0,0 +1,81 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+//列表数据
+export const columns: BasicColumn[] = [
+  {
+    title: '编码(code)',
+    align:"center",
+    dataIndex: 'code'
+   },
+   {
+    title: '名称(name)',
+    align:"center",
+    dataIndex: 'name'
+   },
+  
+   {
+    title: '客户(customer)',
+    align:"center",
+    dataIndex: 'customerId_dictText'
+   },
+   {
+    title: '备注(notes)',
+    align:"center",
+    dataIndex: 'notes'
+   },
+   {
+    title: '创建时间(create time)',
+    align:"center",
+    dataIndex: 'createTime'
+   },
+   {
+    title: '创建人(create by)',
+    align:"center",
+    dataIndex: 'createBy'
+   },
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+	  {
+      label: "编码(code)",
+      field: 'code',
+      component: 'Input',
+      componentProps:{
+      },
+      //colProps: {span: 6},
+ 	  },
+   {
+      label: "名称(name)",
+      field: 'name',
+      component: 'Input',
+        //colProps: {span: 6},
+    },
+    {
+      label: "客户(customer)",
+      field: 'customerId',
+      component: 'JDictSelectTag',
+      componentProps:{
+          dictCode: 'customer',
+      },
+      //colProps: {span: 6},
+ 	  },
+     {
+      label: "创建时间(create time)",
+      field: "createTime",
+      component: 'RangePicker',
+      labelWidth: 150,
+      componentProps: {
+          valueType: 'Date',
+          showTime:true
+      },
+      //colProps: {span: 6},
+	},
+	{
+    label: "创建人(create by)",
+    field: 'createBy',
+    component: 'Input',
+    labelWidth: 120,
+    //colProps: {span: 6},
+   },
+	
+];

+ 14 - 0
src/views/saleCode/saleContract/components/BaseShipArchive.api.ts

@@ -0,0 +1,14 @@
+import {defHttp} from '/@/utils/http/axios';
+
+enum Api {
+  list = '/baseCode/baseShipArchive/list',
+  
+}
+
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+

+ 91 - 0
src/views/saleCode/saleContract/components/BaseShipArchive.data.ts

@@ -0,0 +1,91 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+//列表数据
+export const columns: BasicColumn[] = [
+   {
+    title: 'IMO',
+    align:"center",
+    dataIndex: 'imo'
+   },
+   {
+    title: '船名称(ship name)',
+    align:"center",
+    dataIndex: 'shipName'
+   },
+   {
+    title: '客户名称(customer name)',
+    align:"center",
+    dataIndex: 'relateCustomer'
+   },
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+	{
+      label: "IMO",
+      field: 'imo',
+      component: 'Input',
+      // labelWidth: 150,
+      //colProps: {span: 6},
+ 	},
+	{
+      label: "船名称(ship name)",
+      field: 'shipName',
+      labelWidth: 150,
+      component: 'Input',
+      //colProps: {span: 6},
+ 	},
+   {
+    label: '客户名称(customer name)',
+    field: 'relateCustomer',
+    component: 'Input',
+    labelWidth: 180,
+
+   },
+	{
+      label: "hull number",
+      field: 'hullNumber',
+      component: 'Input',
+      //colProps: {span: 6},
+ 	},
+   {
+    label: "船厂(ship factory)",
+    field: 'shipFactory',
+    component: 'JSelectMultiple',
+    labelWidth: 150,
+    componentProps:{
+      dictCode:"ship_factory"
+   },
+    //colProps: {span: 6},
+ },
+ {
+  label: "造船日期(ship date)",
+  field: "shipDate",
+  component: 'RangePicker',
+  labelWidth: 150,
+  componentProps: {
+      valueType: 'Date',
+      showTime:true
+  },
+  //colProps: {span: 6},
+},
+{
+  label: "船类型(ship type)",
+  field: 'shipType',
+  component: 'JSelectMultiple',
+  labelWidth: 180,
+  componentProps:{
+    dictCode:"ship_type"
+ },
+      //colProps: {span: 6},
+},
+
+{
+  label: "状态(status)",
+  field: 'status',
+  component: 'JSelectMultiple',
+  componentProps:{
+    dictCode:"valid_status"
+  },
+  //colProps: {span: 6},
+},
+];

+ 108 - 0
src/views/saleCode/saleContract/components/BaseShipArchiveAccessoriesModal.vue

@@ -0,0 +1,108 @@
+<template>
+  <div ref="accessoriesDetailsRef">
+    <a-modal
+      title="配件明细(accessories details)"
+      width="70%"
+      :visible="visible"
+      :maskClosable="false"
+      switchFullscreen
+      :getContainer ='()=>$refs.accessoriesDetailsRef'
+      @cancel="handleCancel">
+        <div>
+          <a-table
+                :columns="columns"
+                :row-key="record => record.id"
+                :data-source="dataSource"
+                bordered
+                size="small"
+                height="500"
+                :pagination="false"
+                :scroll="{ x: 1000, y: 500 }"
+            > 
+                <template #attachs="{ text, record,index }">
+                    <a :href="baseUrl+record.attachs">{{record.attachs}}</a>
+                </template>
+            </a-table>
+        </div>
+    </a-modal>
+  </div>
+</template>
+
+<script lang="ts" setup>
+    import {ref} from 'vue';
+    import { useGlobSetting } from '/@/hooks/setting';
+    import {defHttp} from '/@/utils/http/axios';
+    const { domainUrl } = useGlobSetting();
+    var visible = ref(false);
+    var accessoriesDetailsRef = ref();
+    var columns = ref([
+          {
+          title: '配件类型(accessory type)',
+          align:"center",
+          dataIndex: 'accessoryType',
+          key: 'accessoryType'
+        },
+        {
+          title: '规格(specifications)',
+          align:"center",
+          dataIndex: 'specifications',
+          key: 'specifications'
+        },
+        {
+          title: '型号(model)',
+          align:"center",
+          dataIndex: 'model',
+          key: 'model'
+        },
+        {
+          title: '序列号(serial number)',
+          align:"center",
+          dataIndex: 'serialNumber',
+          key: 'serialNumber'
+        },
+        {
+          title: '备注(notes)',
+          align:"center",
+          dataIndex: 'notes',
+          key: 'notes'
+        },
+        {
+          title: '附件(attachs)',
+          align:"center",
+          dataIndex: 'attachs',
+          key: 'attachs',
+          slots: { customRender: 'attachs' },
+        },
+    ])
+    var dataSource=ref([])
+    const baseUrl = domainUrl + '/sys/common/static/';
+    function getTable(record){
+        visible.value = true
+        let params={headId:record.id}
+        defHttp.get({url:"/baseCode/baseShipArchiveAccessories/list",params}).then(res=>{
+        if(res){
+          dataSource.value = res.records
+        }
+    })
+    }
+    function handleCancel(){
+      visible.value = false;
+    }
+    defineExpose({
+      getTable
+    });
+  </script>
+
+<style lang="less" scoped>
+	/** 时间和数字输入框样式 */
+  :deep(.ant-input-number) {
+    width: 100%;
+  }
+
+  :deep(.ant-calendar-picker) {
+    width: 100%;
+  }
+  /deep/.ant-modal-body{
+    padding: 14px !important;
+  }
+</style>

+ 0 - 1
src/views/saleCode/saleContract/components/SaleContractForm.vue

@@ -50,7 +50,6 @@
   import {defHttp} from '/@/utils/http/axios';
   import { propTypes } from '/@/utils/propTypes';
   import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods';
-  import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils';
   import {getBpmFormSchema,saleContractShipColumns,saleContractProductColumns} from '../SaleContract.data';
   import {saveOrUpdate,saleContractShipList,saleContractProductList} from '../SaleContract.api';
 

+ 166 - 15
src/views/saleCode/saleContract/components/SaleContractModal.vue

@@ -1,9 +1,17 @@
 <template>
-  <BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="896" @ok="handleSubmit">
-    <BasicForm @register="registerForm" ref="formRef" name="SaleContractForm"/>
+  <BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" width="95%" @ok="handleSubmit">
+    <BasicForm @register="registerForm" ref="formRef" name="SaleContractForm">
+        <template #quotationProjectName="props">
+								<a-input-search v-model:value="props.values.quotationProjectName"   allow-clear enter-button="Search" @search="onSearchProject( props)"></a-input-search>
+        </template>
+        <template #productionClass="{model,field}">
+          <JSelectInput   v-model:value="model[field]"  placeholder="请选择" :options="classOption" ></JSelectInput>
+        </template>
+    </BasicForm>
     <!-- 子表单区域 -->
-    <a-tabs v-model:activeKey="activeKey" animated @change="handleChangeTabs">
+    <a-tabs v-model:activeKey="activeKey" animated @change="handleChangeTabs" style="padding: 24px;padding-top: 0px;">
       <a-tab-pane tab="销售合同-船明细" key="saleContractShip" :forceRender="true">
+        <a-button type="primary" @click="selectShip" style="margin-top: 10px;margin-bottom: 5px;"> 选择船(select ship)</a-button>
         <JVxeTable
           keep-source
           resizable
@@ -15,10 +23,19 @@
           :rowNumber="true"
           :rowSelection="true"
           :disabled="formDisabled"
-          :toolbar="true"
-          />
+          >
+            <template #action="props" >
+              <a @click="viewAccessory(props)" >查看配件信息(view accessory information)</a>
+              <a-divider type="vertical"/>
+                <a-popconfirm title="确定删除吗?" @confirm="handleDelete(props)">
+                  <a>删除(delete)</a>
+                </a-popconfirm>
+            </template>
+        </JVxeTable>
       </a-tab-pane>
       <a-tab-pane tab="销售合同-产品明细" key="saleContractProduct" :forceRender="true">
+        <a-button type="primary" @click="selectProducts" style="margin-top: 10px;margin-bottom: 5px"> 选择产品(select product)</a-button>
+        <!-- <a-button type="primary" @click="chooseSupplier"> 选择供应商报价(selete supplier quotation)</a-button> -->
         <JVxeTable
           keep-source
           resizable
@@ -30,30 +47,56 @@
           :rowNumber="true"
           :rowSelection="true"
           :disabled="formDisabled"
-          :toolbar="true"
-          />
+          >
+            <template #action="props">
+              <!-- <a>关闭(close)</a>
+              <a-divider type="vertical"/> -->
+              <a-popconfirm title="确定删除吗?" @confirm="handleDelete1(props)">
+                <a>删除(delete)</a>
+              </a-popconfirm>
+            </template>
+        </JVxeTable>
       </a-tab-pane>
     </a-tabs>
+    <SelectProjectModal ref="SelectProjectModalRef"  @selectProject="addProject"></SelectProjectModal>
+    <SelectShipSModal ref="SelectShipSModalRef" @select="addShip"></SelectShipSModal>
+    <BaseShipArchiveAccessoriesList ref="BaseShipArchiveAccessoriesListRef"></BaseShipArchiveAccessoriesList>
+    <SelectPrpductModal ref="SelectPrpductModalRef" @selectProduct="addProduct"></SelectPrpductModal>
   </BasicModal>
 </template>
 
 <script lang="ts" setup>
-    import {ref, computed, unref,reactive} from 'vue';
+    import {ref, unref,reactive} from 'vue';
     import {BasicModal, useModalInner} from '/@/components/Modal';
     import {BasicForm, useForm} from '/@/components/Form/index';
     import { JVxeTable } from '/@/components/jeecg/JVxeTable'
+    import JSelectInput from '/@/components/Form/src/jeecg/components/JSelectInput.vue';
     import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts'
     import {formSchema,saleContractShipColumns,saleContractProductColumns} from '../SaleContract.data';
-    import {saveOrUpdate,saleContractShipList,saleContractProductList} from '../SaleContract.api';
-    import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
+    import {saveOrUpdate,saleContractShipList,saleContractProductList,querysaleVersonFormShipListByMainId,querySaleVersonProductListByMainId,queryVersonHistoryById} from '../SaleContract.api';
+    import { defHttp } from '/@/utils/http/axios';
+    import SelectProjectModal from './SelectProjectModal.vue';
+    import SelectShipSModal from './SelectShipSModal.vue';
+    import BaseShipArchiveAccessoriesList from './BaseShipArchiveAccessoriesModal.vue';
+    import SelectPrpductModal from './SelectPrpductModal.vue';
+    import { useUserStore } from '/@/store/modules/user';
+    import moment from 'moment';
     // Emits声明
     const emit = defineEmits(['register','success']);
+    const userStore = useUserStore();
+    var customerOption =ref([]);
+    var classOption = ref([]);
     const isUpdate = ref(true);
+    var title = ref('');
     const formDisabled = ref(false);
     const refKeys = ref(['saleContractShip', 'saleContractProduct', ]);
     const activeKey = ref('saleContractShip');
     const saleContractShip = ref();
     const saleContractProduct = ref();
+    var SelectProjectModalRef = ref();
+    var SelectShipSModalRef = ref();
+    var SelectPrpductModalRef = ref()
+    var BaseShipArchiveAccessoriesListRef = ref();
     const tableRefs = {saleContractShip, saleContractProduct, };
     const saleContractShipTable = reactive({
           loading: false,
@@ -66,7 +109,7 @@
           columns:saleContractProductColumns
     })
     //表单配置
-    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate,getFieldsValue}] = useForm({
         schemas: formSchema,
         showActionButtonGroup: false,
         baseColProps: {span: 12}
@@ -75,16 +118,31 @@
     const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
         //重置表单
         await reset();
+        getCustomerOptions()
+        getOptiom()
         setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
         isUpdate.value = !!data?.isUpdate;
         formDisabled.value = !data?.showFooter;
-        if (unref(isUpdate)) {
+        title.value = data?.isUpdate ? (unref(formDisabled) ? '详情' : '编辑') : '新增';
+        title.value = data.isRevise ? '修订(Revise)' : title.value;
+        if(data.history=='yes'){
+          const row = await queryVersonHistoryById(data.record.id);
+          await setFieldsValue({ ...row});
+          const saleContractShipList = await querysaleVersonFormShipListByMainId(data.record.id);
+          saleContractShipTable.dataSource = [...saleContractShipList];
+          const saleContractProductList = await querySaleVersonProductListByMainId(data.record.id);
+          saleContractProductTable.dataSource = [...saleContractProductList];
+        }else if (unref(isUpdate)) {
             //表单赋值
             await setFieldsValue({
                 ...data.record,
             });
              requestSubTableData(saleContractShipList, {id:data?.record?.id}, saleContractShipTable)
              requestSubTableData(saleContractProductList, {id:data?.record?.id}, saleContractProductTable)
+        }else{
+          await setFieldsValue({ billDate: moment(new Date()).format('YYYY-MM-DD')});
+          await setFieldsValue({ salesman: userStore.getUserInfo.username });
+          await setFieldsValue({ saleDepartment: userStore.getUserInfo.orgCode });
         }
         // 隐藏底部时禁用整个表单
        setProps({ disabled: !data?.showFooter })
@@ -92,8 +150,8 @@
     //方法配置
     const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys);
 
-    //设置标题
-    const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(formDisabled) ? '编辑' : '详情'));
+    // //设置标题
+    // const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(formDisabled) ? '编辑' : '详情'));
 
     async function reset(){
       await resetFields();
@@ -113,8 +171,10 @@
     async function requestAddOrEdit(values) {
         try {
             setModalProps({confirmLoading: true});
+            const isRevise = values.status=='1' ? true : false
+            debugger
             //提交表单
-            await saveOrUpdate(values, isUpdate.value);
+            await saveOrUpdate(values, isUpdate.value,isRevise);
             //关闭弹窗
             closeModal();
             //刷新列表
@@ -123,6 +183,87 @@
             setModalProps({confirmLoading: false});
         }
     }
+    function onSearchProject(prop) {
+      SelectProjectModalRef.value.getTable()
+    }
+    async function addProject(data) {
+       await setFieldsValue({ quotationProjectName: data[0].name });
+       await setFieldsValue({ quotationProject: data[0].id });
+       await setFieldsValue({ quotationCustomerName: data[0].customerId_dictText });
+       await setFieldsValue({ quotationCustomer: data[0].customerId });
+       customerOption.value.map(item=>{
+          if(item.value==data[0].customerId){
+            setFieldsValue({ priority:item.priority});
+          }
+        })
+    }
+    function getCustomerOptions(){
+          let params = {pageSize:'-1',status:1}
+          defHttp.get({url:'/cuspCode/cuspCustomerProfile/list',params}, { isTransformResponse: false }).then(res=>{
+            if(res){
+              customerOption.value = []
+              res.result.records.forEach(item=>{
+                customerOption.value.push({
+                  label: item.name,
+                  value: item.id,
+                  priority:item.priority
+                })
+              })
+            }
+          })
+      }
+    function getOptiom(){
+        defHttp
+            .get({ url: 'baseCode/baseProductClass/list'}, { isTransformResponse: false })
+            .then((res) => {
+                if (res.success) {
+                  classOption.value = []
+                  res.result.records.forEach(element => {
+                      var obj = {
+                        label: element.name?element.name:'无名称请维护',
+                        value: element.id?element.id:''
+                      };
+                      classOption.value.push( obj)
+                  });    
+                }
+            })
+            .finally(() => {
+                // loading.value = false;
+            });
+      }
+    function selectShip(){
+        SelectShipSModalRef.value.getTable()
+    }
+    function addShip(data){
+      var arr = data.concat(saleContractShipTable.dataSource)
+        arr.map(item=>item.shipowner = item.relateCustomer)
+        saleContractShipTable.dataSource=arr 
+    }
+    async function handleDelete(prop) {
+        var newArray = [...saleContractShipTable.dataSource]
+        newArray.splice(prop.rowIndex, 1)
+        saleContractShipTable.dataSource = newArray 
+    }
+    function viewAccessory(prop){
+        BaseShipArchiveAccessoriesListRef.value.getTable(prop.row)
+    }
+    function selectProducts(){
+      SelectPrpductModalRef.value.getTable()
+    }
+    function addProduct(data){
+        var arrProduct = data.concat(saleContractProductTable.dataSource)
+        arrProduct.map(item=>{
+          item.productClass = item.classId_dictText
+          item.productCode = item.code
+          item.unit = item.measurementUnit
+        })
+        saleContractProductTable.dataSource=arrProduct      
+      }
+    async function handleDelete1(prop) {
+        var newArray = [...saleContractProductTable.dataSource]
+        newArray.splice(prop.rowIndex, 1)
+        saleContractProductTable.dataSource = newArray  
+    }
 </script>
 
 <style lang="less" scoped>
@@ -134,4 +275,14 @@
   :deep(.ant-calendar-picker) {
     width: 100%;
   }
+  /deep/.ant-form-item {
+    margin-bottom: 8px;
+  }
+  /deep/.ant-tabs-nav{
+    margin: 0px !important;
+  }
+  
+  /deep/.ant-modal-body{
+    padding: 24px !important;
+  }
 </style>

+ 83 - 0
src/views/saleCode/saleContract/components/SelectProjectModal.vue

@@ -0,0 +1,83 @@
+<template>
+    <a-modal
+      title="选择项目(select project)"
+      width="95%"
+      :visible="visible"
+      :maskClosable="false"
+      switchFullscreen
+      @ok = "handleOk"
+      @cancel="handleCancel">
+      <div>
+            <!--引用表格-->
+        <BasicTable @register="registerTable" :rowSelection="rowSelection"></BasicTable>
+        </div>
+      </a-modal>
+</template>
+<script lang="ts" name="baseCode-baseShipArchive" setup>
+  import {ref, reactive } from 'vue';
+  import {BasicTable} from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {columns, searchFormSchema} from './BaseProjectArchive.data';
+  import {list} from './BaseProjectArchive.api';
+  import { message } from 'ant-design-vue';
+
+  const queryParam = reactive<any>({});
+  var visible = ref(false);
+  const emit = defineEmits([ 'selectProject']); //定义emit
+  //注册table数据
+  const { tableContext} = useListPage({
+      tableProps:{
+           api:list,
+           columns,
+           canResize:false,
+           formConfig: {
+              schemas: searchFormSchema,
+              autoSubmitOnEnter:true,
+              showAdvancedButton:true,
+              fieldMapToNumber: [
+              ],
+              fieldMapToTime: [
+                 ['shipDate', ['shipDate_begin', 'shipDate_end'], 'YYYY-MM-DD HH:mm:ss'],
+              ],
+            },
+           showTableSetting:false,
+           showActionColumn:false,
+           actionColumn: {
+               width: 200,
+               fixed:'right'
+            },
+            beforeFetch: (params) => {
+              return Object.assign(params, queryParam);
+            },
+      }
+  })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+  
+  function handleCancel() {
+    visible.value = false;
+    selectedRowKeys.value = []
+  }
+    function handleOk() {
+        if(selectedRowKeys.value.length!==1){
+          message.warning('请选择一条数据数据')
+        }else{
+            emit('selectProject',rowSelection.selectedRows)
+            handleCancel()
+        }  
+    }
+   function getTable(){
+    visible.value = true
+   }
+   defineExpose({
+    getTable
+  });
+
+
+</script>
+
+<style lang="less" scoped>
+  :deep(.ant-picker),:deep(.ant-input-number){
+    width: 100%;
+  }
+</style>

+ 340 - 0
src/views/saleCode/saleContract/components/SelectPrpductModal.vue

@@ -0,0 +1,340 @@
+<template>
+    <a-modal
+      title="选择产品(select product)"
+      width="95%"
+      :visible="visible"
+      :maskClosable="false"
+      switchFullscreen
+      @ok = "handleOk"
+      @cancel="handleCancel">
+        <div>
+          <a-card  :body-style="{ padding: '10px' }" :bordered="false" style="margin: 10px;">
+            <div class="table-page-search-wrapper">
+                <a-form :model="queryParams" :label-col="labelCol" :wrapper-col="wrapperCol" @keyup.enter.native="searchQuery">
+                <a-row :gutter="24">
+                    <a-col :md="6" :sm="8">
+                        <a-form-item label="分类(class)">
+                            <!-- <a-input placeholder="请输入" v-model:value="queryParams.classId"></a-input> -->
+                            <JSelectInput   v-model:value="queryParams.classId"  placeholder="请选择" :options="classOption" ></JSelectInput>
+                        </a-form-item>
+                    </a-col>
+                    <a-col :md="6" :sm="8">
+                        <a-form-item label="编码(code)">
+                            <a-input placeholder="请输入" v-model:value="queryParams.code"></a-input>
+                        </a-form-item>
+                    </a-col>
+                    <a-col :md="6" :sm="8">
+                        <a-form-item label="中文名(Chinese name)">
+                            <a-input placeholder="请输入" v-model:value="queryParams.chineseName"></a-input>
+                        </a-form-item>
+                    </a-col>
+                    <template v-if="toggleSearchStatus">
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="英文名(English name)">
+                                <a-input placeholder="请输入" v-model:value="queryParams.englishName"></a-input>
+                            </a-form-item>
+                        </a-col>
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="规格(specifications)">
+                                <a-input placeholder="请输入" v-model:value="queryParams.specifications"></a-input>
+                            </a-form-item>
+                        </a-col>
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="型号(model)">
+                                <a-input placeholder="请输入" v-model:value="queryParams.model"></a-input>
+                            </a-form-item>
+                        </a-col>
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="虚拟产品(virtual product)" :label-col="labelCol1" :wrapper-col="wrapperCol1">
+                                <JDictSelectTag v-model:value="queryParams.virtualProduct" placeholder="请选择" dictCode="yes_or_no"/>
+                            </a-form-item>
+                        </a-col>
+                        <a-col :md="6" :sm="8">
+                            <a-form-item label="有害物质(harmful substances)" :label-col="labelCol1" :wrapper-col="wrapperCol1">
+                                <JDictSelectTag v-model:value="queryParams.harmfulSubstances" placeholder="请选择" dictCode="yes_or_no"/>
+                            </a-form-item>
+                        </a-col>
+                    </template>
+                    <a-col :md="6" :sm="8">
+                        <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
+                            <a-button type="primary" @click="searchQuery" >查询(search)</a-button>
+                            <a-button type="primary" @click="searchReset"  style="margin-left: 8px">重置(reset)</a-button>
+                            <a @click="handleToggleSearch" style="margin-left: 8px">
+                            {{ toggleSearchStatus ? '收起' : '展开' }}
+                            <a-icon :type="toggleSearchStatus ? 'up' : 'down'" />
+                            </a>
+                        </span>
+                    </a-col>
+                </a-row>
+            </a-form>
+           </div>
+        </a-card>
+
+        <a-card  :body-style="{ padding: '10px' }" :bordered="false" style="margin: 10px;">
+            <a-alert type="info" show-icon class="alert" style="margin-bottom: 8px">
+            <template #message>
+                <template v-if="selectedRowKeys.length > 0">
+                <span>已选中 {{ selectedRowKeys.length }} 条记录</span>
+                <a-divider type="vertical" />
+                <a @click="selectedRowKeys = []">清空</a>
+                </template>
+                <template v-else>
+                <span>未选中任何数据</span>
+                </template>
+            </template>
+            </a-alert>
+            <a-table
+                :columns="columns"
+                :row-key="record => record.id"
+                :data-source="dataSource"
+                bordered
+                size="small"
+                @change="handleTableChange"
+                :pagination="pagination"
+                :scroll="{ x: 2500, y: 300 }"
+                :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
+            >
+            </a-table>
+        </a-card>
+      </div>
+    </a-modal>
+</template>
+<script lang="ts" setup>
+    import {ref} from 'vue';
+    import { defHttp } from '/@/utils/http/axios';
+    import { message } from 'ant-design-vue';
+    import { filterObj} from '/@/utils/common/compUtils';
+    import { JDictSelectTag} from '/@/components/Form';
+    import JSelectInput from '/@/components/Form/src/jeecg/components/JSelectInput.vue';
+    const emit = defineEmits([ 'selectProduct']); //定义emit
+    let classOption = ref([])
+    var visible = ref(false)
+    const columns = [
+        {
+            title: '分类(class)',
+            dataIndex: 'classId_dictText',
+            key: 'classId_dictText',
+            align:"center"
+        },
+        {
+            title: '编码(code)',
+            dataIndex: 'code',
+            key: 'code',
+            align:"center"
+        },
+        {
+            title: '中文名(Chinese name)',
+            dataIndex: 'chineseName',
+            key: 'chineseName',
+            align:"center",
+            width:200
+        },
+        {
+            title: '英文名(English name)',
+            key: 'englishName',
+            dataIndex: 'englishName',
+            align:"center"
+        },
+        {
+            title: '规格(specifications)',
+            key: 'specifications',
+            dataIndex: 'specifications',
+            align:"center"
+        },
+        {
+            title: '型号(model)',
+            key: 'model',
+            dataIndex: 'model',
+            align:"center"
+        },
+        {
+            title: '计量单位(measurement unit)',
+            key: 'measurementUnit',
+            dataIndex: 'measurementUnit',
+            align:"center",
+            width:250
+        },
+        {
+            title: '虚拟产品(virtual product)',
+            key: 'virtualProduct',
+            dataIndex: 'virtualProduct',
+            align:"center",
+            customRender:function (t, r, index) {
+              if(t.text==1){
+                return '是(yes)'
+              }else if(t.text==0){
+                return '否(no)'
+              }else{
+                return ''
+              } 
+            }
+        },
+        {
+            title: '有害物质(harmful substances)',
+            key: 'harmfulSubstances',
+            dataIndex: 'harmfulSubstances',
+            align:"center",
+            width:250,
+            customRender:function (t, r, index) {
+              if(t.text==1){
+                return '是(yes)'
+              }else if(t.text==0){
+                return '否(no)'
+              }else{
+                return ''
+              } 
+            }
+        },
+    ];
+    const labelCol = ref({
+    xs: { span: 24 },
+    sm: { span: 9 },
+    });
+    const wrapperCol = ref({
+        xs: { span: 24 },
+        sm: { span: 15 },
+    });
+    const labelCol1 = ref({
+    xs: { span: 24 },
+    sm: { span: 12 },
+    });
+    const wrapperCol1 = ref({
+        xs: { span: 24 },
+        sm: { span: 12 },
+    });
+    const dataSource =ref([]);
+    let selectedRowKeys = ref([]);
+    let selectedRows = ref([]);
+    const toggleSearchStatus = ref(false);
+    const queryParams = ref({
+        classId:'',
+        code:'',
+        chineseName:'',
+        englishName:'',
+        specifications:'',
+        model:'',
+        chineseAlias:'',
+        englishAlias:'',
+        status:'',
+        virtualProduct:'',
+        harmfulSubstances:'',
+    });
+    let pagination = ref({
+      current: 1,
+      pageSize: 10,
+      total: '', // 假设总共有100条数据
+      showSizeChanger: true,
+      showQuickJumper: true,
+      showTotal: (total, range) => {
+          return range[0] + "-" + range[1] + " 共" + total + "条"
+      },
+      size:'small'
+    });
+    function loadData(){
+        let params = getQueryParams();
+        defHttp
+        .get({ url: '/baseCode/baseProductArchive/list',params}, { isTransformResponse: false })
+        .then((res) => {
+            if (res.success) {
+                dataSource.value = res.result.records;
+                pagination.value.total = res.result.total;
+                pagination.value.current = res.result.current;
+                pagination.value.pageSize = res.result.size;                
+            } else {
+                message.error(res.message);
+            }
+        })
+        .finally(() => {
+            // loading.value = false;
+        });
+    }
+    function getQueryParams(){
+        let params = Object.assign(queryParams.value);
+        params.pageNo = pagination.value.current;
+        params.pageSize = pagination.value.pageSize;
+        return filterObj(params);
+    }
+    function handleTableChange(paginations, filters, sorter){
+        pagination.value.total = paginations.total;
+        pagination.value.current = paginations.current;
+        pagination.value.pageSize = paginations.pageSize;
+        loadData()
+    };
+    function getOptiom(){
+    defHttp
+        .get({ url: 'baseCode/baseProductClass/list'}, { isTransformResponse: false })
+        .then((res) => {
+            if (res.success) {
+              classOption.value = []
+              res.result.records.forEach(element => {
+                  var obj = {
+                    label: element.name?element.name:'无名称请维护',
+                    value: element.id?element.id:''
+                  };
+                  classOption.value.push( obj)
+              });    
+            }
+        })
+        .finally(() => {
+            // loading.value = false;
+        });
+  }
+    function searchQuery(){
+        loadData();
+    }
+    function searchReset(){
+        queryParams.value = {
+            classId:'',
+            code:'',
+            chineseName:'',
+            englishName:'',
+            specifications:'',
+            model:'',
+            chineseAlias:'',
+            englishAlias:'',
+            status:'',
+            virtualProduct:'',
+            harmfulSubstances:'',
+        }
+        pagination.value.current =1;
+        pagination.value.pageSize = 10; 
+        loadData();
+    }
+    function handleToggleSearch(){
+        toggleSearchStatus.value = !toggleSearchStatus.value;
+    }
+    function onSelectChange(keys,rows){
+        selectedRowKeys.value = keys
+        selectedRows.value = rows
+    }
+    function handleOk(){
+      if(selectedRowKeys.value.length==0){
+        message.error('请勾选数据');
+      }else{
+        emit('selectProduct', selectedRows.value)
+        handleCancel()
+      }
+    }
+    function handleCancel(){
+      visible.value = false
+      selectedRowKeys.value = []
+      selectedRows.value=[]
+    }
+    function getTable(){
+        visible.value = true
+        loadData()
+        getOptiom()
+    }
+    defineExpose({
+      getTable
+    });
+</script>
+<style scoped lang="less">
+/deep/.ant-form-item{
+    margin-bottom: 8px !important;
+}
+// /deep/.ant-table-wrapper .ant-table-thead > tr > th, .ant-table-wrapper .ant-table-thead > tr > td{
+//     padding: 8px !important;
+// }
+
+</style>

+ 84 - 0
src/views/saleCode/saleContract/components/SelectShipSModal.vue

@@ -0,0 +1,84 @@
+<template>
+    <a-modal
+      title="选择船(select ship)"
+      width="95%"
+      :visible="visible"
+      :maskClosable="false"
+      switchFullscreen
+      @ok = "handleOk"
+      @cancel="handleCancel">
+      <div>
+            <!--引用表格-->
+        <BasicTable @register="registerTable" :rowSelection="rowSelection"></BasicTable>
+        </div>
+      </a-modal>
+</template>
+<script lang="ts" name="baseCode-baseShipArchive" setup>
+  import {ref, reactive } from 'vue';
+  import {BasicTable} from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {columns, searchFormSchema} from './BaseShipArchive.data';
+  import {list} from './BaseShipArchive.api';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  const queryParam = reactive<any>({});
+  var visible = ref(false);
+  const emit = defineEmits([ 'select']); //定义emit
+  //注册model
+  const { createMessage} = useMessage();
+  //注册table数据
+  const { tableContext} = useListPage({
+      tableProps:{
+           api:list,
+           columns,
+           canResize:false,
+           formConfig: {
+              schemas: searchFormSchema,
+              autoSubmitOnEnter:true,
+              showAdvancedButton:true,
+              fieldMapToNumber: [
+              ],
+              fieldMapToTime: [
+                 ['shipDate', ['shipDate_begin', 'shipDate_end'], 'YYYY-MM-DD HH:mm:ss'],
+              ],
+            },
+           showTableSetting:false,
+           showActionColumn:false,
+           actionColumn: {
+               width: 200,
+               fixed:'right'
+            },
+            beforeFetch: (params) => {
+              return Object.assign(params, queryParam);
+            },
+      }
+  })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+  
+  function handleCancel() {
+    visible.value = false;
+    selectedRowKeys.value = []
+  }
+    function handleOk() {
+        if(selectedRowKeys.value.length==0){
+            createMessage('请选择数据')
+        }else{
+            emit('select',rowSelection.selectedRows)
+            handleCancel()
+        }  
+    }
+   function getTable(){
+    visible.value = true
+   }
+   defineExpose({
+    getTable
+  });
+
+
+</script>
+
+<style lang="less" scoped>
+  :deep(.ant-picker),:deep(.ant-input-number){
+    width: 100%;
+  }
+</style>

+ 170 - 0
src/views/saleCode/saleContract/components/ViewHistoryVersionModal.vue

@@ -0,0 +1,170 @@
+<template>
+  <a-modal
+    title="历史版本查看(view historical version)"
+    width="55%"
+    :visible="visible"
+    :maskClosable="false"
+    switchFullscreen
+    @cancel="handleCancel">
+      <template #footer>
+        <a-button  @click="handleCancel" >关闭(close)</a-button>
+      </template>
+      <div>
+        <a-card  :body-style="{ padding: '10px' }" :bordered="false" style="margin: 10px;">
+            <a-alert type="info" show-icon class="alert" style="margin-bottom: 8px">
+            <template #message>
+                <template v-if="selectedRowKeys.length > 0">
+                <span>已选中 {{ selectedRowKeys.length }} 条记录</span>
+                <a-divider type="vertical" />
+                <a @click="selectedRowKeys = []">清空</a>
+                </template>
+                <template v-else>
+                <span>未选中任何数据</span>
+                </template>
+            </template>
+            </a-alert>
+            <a-table
+                :columns="columns"
+                :row-key="record => record.id"
+                :data-source="dataSource"
+                bordered
+                size="small"
+                @change="handleTableChange"
+                :pagination="pagination"
+                :scroll="{ x: 1000, y: 300 }"
+                :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
+            >
+                <template #bodyCell="{ column, record }">
+                    <template v-if="column.key === 'operation'">
+                        <span>
+                            <a @click="viewDetail(record)">查看(view)</a>
+                        </span>
+                    </template>
+                </template>
+            </a-table>
+        </a-card>
+      </div>
+      <SaleContractModal @register="registerModal" ></SaleContractModal>
+  </a-modal>
+</template>
+<script lang="ts" setup>
+  import {ref } from 'vue';
+  import { defHttp } from '/@/utils/http/axios';
+  import { message } from 'ant-design-vue';
+  import {useModal} from '/@/components/Modal';
+  import { filterObj } from '/@/utils/common/compUtils';
+  import SaleContractModal from './SaleContractModal.vue';
+  const emit = defineEmits([ 'selectProduct']); //定义emit
+  const [registerModal, {openModal}] = useModal();
+  var visible = ref(false)
+  const columns = [
+      {
+          title: '版本号(version)',
+          dataIndex: 'version',
+          key: 'version',
+          align:"center"
+      },
+      {
+          title: '创建时间(create time)',
+          dataIndex: 'createTime',
+          key: 'createTime',
+          align:"center"
+      },
+      {
+          title: '创建人(create by)',
+          dataIndex: 'createBy',
+          key: 'price',
+          align:"createBy",
+          width:200
+      },
+      {
+          title: '操作(operation)',
+          key: 'operation',
+          dataIndex: 'operation',
+          align:"center",
+          fixed: 'right',
+      },
+  ];
+  const dataSource =ref([]);
+  let selectedRowKeys = ref([]);
+  let selectedRows = ref([]);
+  var Father = ref({})
+  let pagination = ref({
+    current: 1,
+    pageSize: 10,
+    total: '', // 假设总共有100条数据
+    showSizeChanger: true,
+    showQuickJumper: true,
+    showTotal: (total, range) => {
+        return range[0] + "-" + range[1] + " 共" + total + "条"
+    },
+    size:'small'
+  });
+  function loadData(){
+        let params = getQueryParams();
+        defHttp
+        .get({ url: '/saleCode/saleContractHis/list',params}, { isTransformResponse: false })
+        .then((res) => {
+            if (res.success) {
+                dataSource.value = res.result.records;
+                pagination.value.total = res.result.total;
+                pagination.value.current = res.result.current;
+                pagination.value.pageSize = res.result.size;                
+            } else {
+                message.error(res.message);
+            }
+        })
+        .finally(() => {
+            // loading.value = false;
+        });
+  }
+  function getQueryParams(){
+        let params = {}
+        params.pageNo = pagination.value.current;
+        params.hisId = Father.value.id;
+        params.pageSize = pagination.value.pageSize;
+        return filterObj(params);
+  }
+
+  function handleTableChange(paginations, filters, sorter){
+      pagination.value.total = paginations.total;
+      pagination.value.current = paginations.current;
+      pagination.value.pageSize = paginations.pageSize;
+      loadData()
+  };
+  function onSelectChange(keys,rows){
+      selectedRowKeys.value = keys
+      selectedRows.value = rows
+  }
+  function handleCancel(){
+    visible.value = false
+    selectedRowKeys.value = []
+    selectedRows.value=[]
+  }
+  function getTable(record){
+      visible.value = true
+      Father.value = record
+      loadData()
+  }
+  function viewDetail(record){
+    openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+       isRevise: false,
+       history:'yes'
+     });
+  }
+  defineExpose({
+    getTable
+  });
+</script>
+<style scoped lang="less">
+/deep/.ant-form-item{
+  margin-bottom: 8px !important;
+}
+// /deep/.ant-table-wrapper .ant-table-thead > tr > th, .ant-table-wrapper .ant-table-thead > tr > td{
+//     padding: 8px !important;
+// }
+
+</style>