Explorar el Código

销售报价单-页面开发/功能开发

jingbb hace 5 meses
padre
commit
52d618fa1e

+ 14 - 0
src/views/saleCode/quotation/components/BaseProjectArchive.api.ts

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

+ 84 - 0
src/views/saleCode/quotation/components/BaseProjectArchive.data.ts

@@ -0,0 +1,84 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+import { getWeekMonthQuarterYear } from '/@/utils';
+//列表数据
+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},
+   },
+	
+];

+ 17 - 0
src/views/saleCode/quotation/components/BaseShipArchive.api.ts

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

+ 94 - 0
src/views/saleCode/quotation/components/BaseShipArchive.data.ts

@@ -0,0 +1,94 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+import { getWeekMonthQuarterYear } from '/@/utils';
+//列表数据
+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},
+},
+];

+ 48 - 0
src/views/saleCode/quotation/components/BaseShipArchiveAccessories.data.ts

@@ -0,0 +1,48 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+import { getWeekMonthQuarterYear } from '/@/utils';
+//列表数据
+export const columns: BasicColumn[] = [
+   
+   {
+    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: '备注',
+    align:"center",
+    dataIndex: 'notes',
+    key: 'notes'
+   },
+   {
+    title: '附件',
+    align:"center",
+    dataIndex: 'attachs',
+    key: 'attachs'
+   }, */
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+];

+ 104 - 0
src/views/saleCode/quotation/components/BaseShipArchiveAccessoriesModal.vue

@@ -0,0 +1,104 @@
+<template>
+ <a-modal
+      title="配件明细(accessories details)"
+      width="70%"
+      :visible="visible"
+      :maskClosable="false"
+      switchFullscreen
+      @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>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref,reactive} from 'vue';
+    import { useGlobSetting } from '/@/hooks/setting';
+    import {defHttp} from '/@/utils/http/axios';
+    const { domainUrl } = useGlobSetting();
+    var visible = ref(false);
+    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>

+ 83 - 0
src/views/saleCode/quotation/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, useTable, TableAction} 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/quotation/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, reactive } from 'vue';
+    import { defHttp } from '/@/utils/http/axios';
+    import { message } from 'ant-design-vue';
+    import { filterObj, getFileAccessHttpUrl } 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/quotation/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, useTable, TableAction} 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>

+ 121 - 0
src/views/saleCode/quotation/components/ViewHistoryQuotationModal.vue

@@ -0,0 +1,121 @@
+<template>
+  <a-modal
+    title="历史报价查看(view historical quotations)"
+    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 }"
+            >
+            </a-table>
+        </a-card>
+      </div>
+  </a-modal>
+</template>
+<script lang="ts" setup>
+  import {ref, reactive } from 'vue';
+  import { defHttp } from '/@/utils/http/axios';
+  import { message } from 'ant-design-vue';
+  import { filterObj, getFileAccessHttpUrl } from '/@/utils/common/compUtils';
+  import { JDictSelectTag} from '/@/components/Form';
+  const emit = defineEmits([ 'selectProduct']); //定义emit
+  let classOption = ref([])
+  var visible = ref(false)
+  const columns = [
+      {
+          title: '项目号(project code)',
+          dataIndex: 'projectCode',
+          key: 'projectCode',
+          align:"center"
+      },
+      {
+          title: '报价时间(quotation date)',
+          dataIndex: 'quotationDate',
+          key: 'quotationDate',
+          align:"center"
+      },
+      {
+          title: '价格(price)',
+          dataIndex: 'price',
+          key: 'price',
+          align:"center",
+          width:200
+      },
+  ];
+  const dataSource =ref([]);
+  let selectedRowKeys = ref([]);
+  let selectedRows = 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(){
+     
+  }
+
+  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(){
+      visible.value = true
+      loadData()
+  }
+  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>

+ 165 - 0
src/views/saleCode/quotation/components/ViewHistoryVersionModal.vue

@@ -0,0 +1,165 @@
+<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>
+      <quotationFormModal  ref="quotationFormModalRef"></quotationFormModal>
+  </a-modal>
+</template>
+<script lang="ts" setup>
+  import {ref, reactive } from 'vue';
+  import { defHttp } from '/@/utils/http/axios';
+  import { message } from 'ant-design-vue';
+  import { filterObj, getFileAccessHttpUrl } from '/@/utils/common/compUtils';
+  import { JDictSelectTag} from '/@/components/Form';
+  import quotationFormModal from './quotationFormModal.vue';
+  const emit = defineEmits([ 'selectProduct']); //定义emit
+  let classOption = ref([])
+  var visible = ref(false)
+  var quotationFormModalRef = ref()
+  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/saleQuotationHis/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){
+    quotationFormModalRef.value.getVersionDetail(record)
+  }
+  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>

+ 598 - 0
src/views/saleCode/quotation/components/quotationFormForm.vue

@@ -0,0 +1,598 @@
+<template>
+  <a-spin :spinning="loading">
+    <JFormContainer :disabled="disabled">
+      <template #detail>
+        <a-form v-bind="formItemLayout" name="quotationFormForm" ref="formRef">
+          <a-row>
+						<a-col :span="12">
+							<a-form-item label="单据日期(bill date)" v-bind="validateInfos.billDate" id="quotationFormForm-billDate" name="billDate">
+								<a-date-picker placeholder="请选择单据日期(bill date)"  v-model:value="formData.billDate"  value-format="YYYY-MM-DD" disabled  style="width: 100%"  allow-clear />
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="报价单号(bill code)" v-bind="validateInfos.billCode" id="quotationFormForm-billCode" name="billCode" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+								<a-input v-model:value="formData.billCode" placeholder="请输入报价单号(bill code)" ></a-input>
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="报价项目(quotation project)" v-bind="validateInfos.quotationProjectName" id="quotationFormForm-quotationProjectName" name="quotationProjectName">
+								<a-input-search v-model:value="formData.quotationProjectName" placeholder="请输入报价项目(inquiry project)"  allow-clear enter-button="Search" @search="onSearchProject"></a-input-search>
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="报价客户(quotation customer)" v-bind="validateInfos.quotationCustomer" id="quotationFormForm-quotationCustomer" name="quotationCustomer" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+                <JSelectInput   v-model:value="formData.quotationCustomer"  placeholder="请选择" :options="customerOption" disabled></JSelectInput>
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="报价有效期(quotation period)" v-bind="validateInfos.quotationPeriod" id="quotationFormForm-quotationPeriod" name="quotationPeriod">
+                <a-range-picker v-model:value="quotationPeriod" :format="['YYYY-MM-DD','YYYY-MM-DD']"  @change="onChangequotationPeriod" style="width: 100%" />
+							</a-form-item>
+						</a-col>
+            <a-col :span="12">
+							<a-form-item label="业务类型(busyness type)" v-bind="validateInfos.busynessType" id="quotationFormForm-busynessType" name="busynessType" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+                <JDictSelectTag v-model:value="formData.busynessType" placeholder="请选择" dictCode="busyness_type"/>
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="优先级(priority)" v-bind="validateInfos.priority" id="quotationFormForm-priority" name="priority">
+                <JDictSelectTag v-model:value="formData.priority" placeholder="请选择" dictCode="priority"/>
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="产品分类(production class)" v-bind="validateInfos.productionClass" id="quotationFormForm-productionClass" name="productionClass" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+                <JSelectInput   v-model:value="formData.productionClass"  placeholder="请选择" :options="classOption"></JSelectInput>
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="机型(model)" v-bind="validateInfos.model" id="quotationFormForm-model" name="model">
+                <JSelectMultiple v-model:value="formData.model" placeholder="请选择" dictCode="model_typer"/>
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="厂家(maker)" v-bind="validateInfos.maker" id="quotationFormForm-maker" name="maker" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+								<a-input v-model:value="formData.maker" placeholder="请输入厂家(maker)"  allow-clear ></a-input>
+							</a-form-item>
+						</a-col>
+            <a-col :span="12">
+							<a-form-item label="币种(currency)" v-bind="validateInfos.currency" id="quotationFormForm-currency" name="currency">
+								<JDictSelectTag v-model:value="formData.currency" placeholder="请选择" dictCode="currency" />
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="贸易方式(delivery terms)" v-bind="validateInfos.deliveryTerms" id="quotationFormForm-deliveryTerms" name="deliveryTerms" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+                <JDictSelectTag v-model:value="formData.deliveryTerms" placeholder="请选择" dictCode="delivery_terms"/>
+							</a-form-item>
+						</a-col>
+            <a-col :span="12">
+							<a-form-item label="交期(delivery time)" v-bind="validateInfos.deliveryTime" id="quotationFormForm-deliveryTime" name="deliveryTime">
+								<a-date-picker placeholder="请选择交期(delivery time)"  v-model:value="formData.deliveryTime" @change="changeDelivertTime" value-format="YYYY-MM-DD" format="YYYY-MM-DD" style="width: 100%"  allow-clear />
+							</a-form-item>
+						</a-col>
+            <a-col :span="12">
+							<a-form-item label="付款条件(payment terms)" v-bind="validateInfos.paymentTerms" id="quotationFormForm-paymentTerms" name="paymentTerms" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+                <JDictSelectTag v-model:value="formData.paymentTerms" placeholder="请选择" dictCode="payment_terms"/>
+							</a-form-item>
+						</a-col>
+            <a-col :span="12">
+							<a-form-item label="交货地点(place of delivery)" v-bind="validateInfos.placeDelivery" id="quotationFormForm-placeDelivery" name="placeDelivery">
+								<a-input v-model:value="formData.placeDelivery" placeholder="请输入交货地点(place of delivery)"  allow-clear ></a-input>
+							</a-form-item>
+						</a-col>
+            <a-col :span="12">
+							<a-form-item label="客户折扣(custumer discount)" v-bind="validateInfos.custumerDiscount" id="quotationFormForm-custumerDiscount" name="custumerDiscount" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+								<a-input v-model:value="formData.custumerDiscount" placeholder="请输入客户折扣(custumer discount)"  allow-clear ></a-input>
+							</a-form-item>
+						</a-col>
+            <a-col :span="12">
+							<a-form-item label="销售部门(sale department)" v-bind="validateInfos.saleDepartment" id="SaleInquiryFormForm-saleDepartment" name="saleDepartment">
+								<a-input v-model:value="formData.saleDepartment" placeholder=""  allow-clear disabled></a-input>
+							</a-form-item>
+						</a-col>
+            <a-col :span="12">
+							<a-form-item label="包装方式(packaging method)" v-bind="validateInfos.packagingMethod" id="quotationFormForm-packagingMethod" name="packagingMethod" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+								<a-input v-model:value="formData.packagingMethod" placeholder="请输入包装方式(packaging method)"  allow-clear ></a-input>
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="业务员(salesman)" v-bind="validateInfos.salesman" id="quotationFormForm-salesman" name="salesman">
+								<a-input v-model:value="formData.salesman" placeholder=""  allow-clear disabled></a-input>
+							</a-form-item>
+						</a-col>
+            <a-col :span="12">
+							<a-form-item label="报价备注(quotation notes)" v-bind="validateInfos.quotationNotes" id="quotationFormForm-quotationNotes" name="quotationNotes" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+								<a-input v-model:value="formData.quotationNotes" placeholder="请输入报价备注(quotation notes)"  allow-clear ></a-input>
+							</a-form-item>
+						</a-col>
+						<a-col :span="12">
+							<a-form-item label="附件(attachs)" v-bind="validateInfos.attachs" id="quotationFormForm-attachs" name="attachs">
+								<JUpload v-model:value="formData.attachs"></JUpload>
+							</a-form-item>
+						</a-col>
+            <a-col :span="12">
+							<a-form-item label="供应商技术资料(supplier quotation attachs)" v-bind="validateInfos.supplierAttachs" id="quotationFormForm-supplierAttachs" name="supplierAttachs" :labelCol="formItemLayout.labelCol1" :wrapperCol="formItemLayout.wrapperCol1">
+								<a :href="baseUrl+formData.supplierAttachs" v-if="formData.supplierAttachs">{{formData.supplierAttachs}}</a>
+                <a-input v-model:value="formData.supplierAttachs"   disabled v-if="!formData.supplierAttachs"></a-input>
+							</a-form-item>
+						</a-col>
+          </a-row>
+        </a-form>
+      </template>
+    </JFormContainer>
+
+		<!-- 子表单区域 -->
+    <a-tabs v-model:activeKey="activeKey" animated  style=" padding: 24px;padding-top: 0px;">
+      <a-tab-pane tab="报价单子表 - 船明细(ship details)" key="saleQuotationFormShip" :forceRender="true">
+        <a-button type="primary" @click="selectShip"> 选择船(select ship)</a-button>
+        <j-vxe-table
+          :keep-source="true"
+          resizable
+          ref="saleQuotationFormShipTableRef"
+          :loading="saleQuotationFormShipTable.loading"
+          :columns="saleQuotationFormShipTable.columns"
+          :dataSource="saleQuotationFormShipTable.dataSource"
+          :height="340"
+          :disabled="disabled"
+          :rowNumber="true"
+          :rowSelection="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>
+          </j-vxe-table>
+      </a-tab-pane>
+      <a-tab-pane tab="报价单 - 产品明细(product details)" key="saleQuotationFormProduct" :forceRender="true">
+        <a-button type="primary" @click="selectProducts" style="margin-right: 1%;margin-bottom: 1%;"> 选择产品(select product)</a-button>
+        <!-- <a-button type="primary" @click="chooseSupplier"> 选择供应商报价(selete supplier quotation)</a-button> -->
+        <j-vxe-table
+          :keep-source="true"
+          resizable
+          ref="saleQuotationFormProductTableRef"
+          :loading="saleQuotationFormProductTable.loading"
+          :columns="saleQuotationFormProductTable.columns"
+          :dataSource="saleQuotationFormProductTable.dataSource"
+          :height="340"
+          :disabled="disabled"
+          :rowNumber="true"
+          :rowSelection="true"
+          asyncRemove
+          >
+            <template #lastPrice="props">
+                  <a @click="viewHistory">{{ props.row.lastPrice }}</a>
+            </template>
+          <template #action="props">
+                <a-popconfirm title="确定删除吗?" @confirm="handleDelete1(props)">
+                  <a>删除(delete)</a>
+                </a-popconfirm>
+            </template>
+          </j-vxe-table>
+      </a-tab-pane>
+    </a-tabs>
+    <SelectShipSModal ref="SelectShipSModalRef" @select="addShip"></SelectShipSModal>
+    <BaseShipArchiveAccessoriesList ref="BaseShipArchiveAccessoriesListRef"></BaseShipArchiveAccessoriesList>
+    <SelectPrpductModal ref="SelectPrpductModalRef" @selectProduct="addProduct"></SelectPrpductModal>
+    <SelectProjectModal ref="SelectProjectModalRef" @selectProject="addProject"></SelectProjectModal>
+    <ViewHistoryQuotationModal ref="ViewHistoryQuotationModalRef" ></ViewHistoryQuotationModal>
+  </a-spin>
+</template>
+
+<script lang="ts">
+  import { defineComponent, ref, reactive, computed, toRaw, onMounted } from 'vue';
+  import { defHttp } from '/@/utils/http/axios';
+  import { useValidateAntFormAndTable } from '/@/hooks/system/useJvxeMethods';
+  import { querysaleQuotationFormShipListByMainId,querysaleVersonFormShipListByMainId,querySaleQuotationFormProductListByMainId, querySaleVersonProductListByMainId,queryDataById, saveOrUpdate,HistoryQuotation,queryVersonHistoryById } from '../quotationForm.api';
+  import { JVxeTable } from '/@/components/jeecg/JVxeTable';
+  import {saleQuotationFormShipColumns, saleQuotationFormProductColumns} from '../quotationForm.data';
+  import SelectShipSModal from './SelectShipSModal.vue';
+  import BaseShipArchiveAccessoriesList from './BaseShipArchiveAccessoriesModal.vue';
+  import SelectPrpductModal from './SelectPrpductModal.vue';
+  import SelectProjectModal from './SelectProjectModal.vue';
+  import ViewHistoryQuotationModal from './ViewHistoryQuotationModal.vue';
+  import JFormContainer from '/@/components/Form/src/container/JFormContainer.vue';
+  import JUpload from '/@/components/Form/src/jeecg/components/JUpload/JUpload.vue';
+  import { JDictSelectTag,JSelectMultiple} from '/@/components/Form';
+  import JSelectInput from '/@/components/Form/src/jeecg/components/JSelectInput.vue';
+  import { Form } from 'ant-design-vue';
+  import { useUserStore } from '/@/store/modules/user';
+  import moment from 'moment';
+  import { useGlobSetting } from '/@/hooks/setting';
+  const { domainUrl } = useGlobSetting();
+  const userStore = useUserStore();
+  const useForm = Form.useForm;
+  export default defineComponent({
+    name: "quotationFormForm",
+    components:{
+      JVxeTable,
+			JFormContainer,
+      SelectShipSModal,
+      BaseShipArchiveAccessoriesList,
+      SelectPrpductModal,
+      JUpload,
+      SelectProjectModal,
+      ViewHistoryQuotationModal,
+      JDictSelectTag,
+      JSelectInput,
+      JSelectMultiple
+    },
+    props:{
+      formDisabled:{
+        type: Boolean,
+        default: false
+      },
+      formData: { type: Object, default: ()=>{} },
+      formBpm: { type: Boolean, default: true }
+    },
+    emits:['success'],
+    setup(props, {emit}) {
+      const baseUrl = domainUrl + '/sys/common/static/';
+      const loading = ref(false);
+      const formRef = ref();
+      var SelectPrpductModalRef = ref()
+      var SelectProjectModalRef = ref()
+      var ViewHistoryQuotationModalRef = ref()
+      var quotationPeriod = ref([])
+      const saleQuotationFormShipTableRef = ref();
+      const saleQuotationFormShipTable = reactive<Record<string, any>>({
+        loading: false,
+        columns:saleQuotationFormShipColumns,
+        dataSource: []
+      });
+      const saleQuotationFormProductTableRef = ref();
+      const saleQuotationFormProductTable = reactive<Record<string, any>>({
+        loading: false,
+        columns: saleQuotationFormProductColumns,
+        dataSource: []
+      });
+      var SelectShipSModalRef = ref();
+      var BaseShipArchiveAccessoriesListRef = ref();
+      const activeKey = ref('saleQuotationFormShip');
+      var classOption = ref([]);
+      var customerOption =ref([]);
+      const formData = reactive<Record<string, any>>({
+        id: '',
+        status: undefined,
+        delFlag: undefined,
+        otherStatus: '',   
+        submit: '',   
+        billDate: moment(new Date()).format('YYYY-MM-DD'),   
+        billCode: '',   
+        quotationProject: '',   
+        quotationProjectName: '',   
+        quotationCustomer: '',   
+        quotationCustomerName: '',   
+        quotationPeriodBegin: '',   
+        quotationPeriodEnd: '',   
+        busynessType: '',   
+        priority: '',   
+        productionClass: '',   
+        model: '',   
+        maker: '',   
+        currency:"",
+        deliveryTerms: '',   
+        deliveryTime: '',
+        paymentTerms: '',
+        placeDelivery: '',
+        custumerDiscount: '',
+        saleDepartment:'',
+        packagingMethod:'',      
+        salesman: '', 
+        quotationNotes:"",
+        attachs: '',   
+        supplierAttachs: '',   
+      });
+
+      //表单验证
+      const validatorRules = reactive({
+      });
+      const {resetFields, validate, validateInfos} = useForm(formData, validatorRules, {immediate: false});
+      const dbData = {};
+      const formItemLayout = {
+        labelCol: {xs: {span: 24}, sm: {span: 8}},
+        wrapperCol: {xs: {span: 24}, sm: {span: 13}},
+        labelCol1: {xs: {span: 24}, sm: {span: 8}},
+        wrapperCol1: {xs: {span: 24}, sm: {span: 13}},
+      };
+
+      // 表单禁用
+      const disabled = computed(()=>{
+        if(props.formBpm === true){
+          if(props.formData.disabled === false){
+            return false;
+          }else{
+            return true;
+          }
+        }
+        return props.formDisabled;
+      });
+
+      
+
+      function add() {
+        resetFields();
+        saleQuotationFormShipTable.dataSource = [];
+        saleQuotationFormProductTable.dataSource = [];
+        activeKey.value = 'saleQuotationFormShip'
+        getOptiom()
+        getCustomerOptions()
+        quotationPeriod.value = []
+        formData.salesman=userStore.getUserInfo.username;
+        formData.saleDepartment = userStore.getUserInfo.orgCode
+      }
+
+      async function edit(row) {
+        //主表数据
+        await queryMainData(row.id);
+        //子表数据
+        const saleQuotationFormShipDataList = await querysaleQuotationFormShipListByMainId(row['id']);
+        saleQuotationFormShipTable.dataSource = [...saleQuotationFormShipDataList];
+        const saleQuotationFormProductDataList = await querySaleQuotationFormProductListByMainId(row['id']);
+        saleQuotationFormProductTable.dataSource = [...saleQuotationFormProductDataList];
+        getOptiom()
+        getCustomerOptions()
+        quotationPeriod.value[0]=formData.quotationPeriodBegin?moment(formData.quotationPeriodBegin):''
+        quotationPeriod.value[1]=formData.quotationPeriodEnd?moment(formData.quotationPeriodEnd):''
+        
+      }
+      async function queryMainData(id) {
+        const row = await queryDataById(id);
+        resetFields();
+        const tmpData = {};
+        Object.keys(formData).forEach((key) => {
+          if(row.hasOwnProperty(key)){
+            tmpData[key] = row[key]
+          }
+        })
+        //赋值
+        Object.assign(formData,tmpData);
+      }
+
+      const {getSubFormAndTableData, transformData} = useValidateAntFormAndTable(activeKey, {
+        'saleQuotationShip': saleQuotationFormShipTableRef,
+        'saleQuotationProduct': saleQuotationFormProductTableRef,
+      });
+
+      async function getFormData() {
+        try {
+          // 触发表单验证
+          await validate();
+        } catch ({ errorFields }) {
+          if (errorFields) {
+            const firstField = errorFields[0];
+            if (firstField) {
+              formRef.value.scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
+            }
+          }
+          return Promise.reject(errorFields);
+        }
+        return transformData(toRaw(formData))
+      }
+
+      async function submitForm() {
+        const mainData = await getFormData();
+        const subData = await getSubFormAndTableData();
+        const values = Object.assign({}, dbData, mainData, subData);
+        console.log('表单提交数据', values)
+        const isUpdate = values.id ? true : false
+        const isRevise = values.status=='1' ? true : false
+        await saveOrUpdate(values, isUpdate,isRevise);
+        //关闭弹窗
+        emit('success');
+      }
+      
+      function setFieldsValue(values) {
+        if(values){
+          Object.keys(values).map(k=>{
+            formData[k] = values[k];
+          });
+        }
+      }
+
+      /**
+       * 值改变事件触发-树控件回调
+       * @param key
+       * @param value
+       */
+      function handleFormChange(key, value) {
+        formData[key] = value;
+      }
+      async function handleDelete(prop) {
+        var newArray = [...saleQuotationFormShipTable.dataSource]
+        newArray.splice(prop.rowIndex, 1)
+        saleQuotationFormShipTable.dataSource = newArray 
+      }
+      async function handleDelete1(prop) {
+        var newArray = [...saleQuotationFormProductTable.dataSource]
+        newArray.splice(prop.rowIndex, 1)
+        saleQuotationFormProductTable.dataSource = newArray  
+      }
+      function selectShip(){
+        SelectShipSModalRef.value.getTable()
+      }
+      function addShip(data){
+        var arr = data.concat(saleQuotationFormShipTable.dataSource)
+        arr.map(item=>item.shipowner = item.relateCustomer)
+        saleQuotationFormShipTable.dataSource=arr             
+      }
+      function addProduct(data){
+        var arrProduct = data.concat(saleQuotationFormProductTable.dataSource)
+        arrProduct.map(item=>{
+          item.productClass = item.classId_dictText
+          item.productCode = item.code
+          item.unit = item.measurementUnit
+          item.deliveryTime = formData.deliveryTime
+        })
+        saleQuotationFormProductTable.dataSource=arrProduct      
+      }
+      function addProject(data) {
+        formData.quotationProject = data[0].id
+        formData.quotationProjectName = data[0].name
+        formData.quotationCustomer =data[0].customerId
+        formData.quotationCustomerName =data[0].customerId_dictText
+        customerOption.value.map(item=>{
+          if(item.value==data[0].customerId){
+            formData.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 viewAccessory(prop){
+        BaseShipArchiveAccessoriesListRef.value.getTable(prop.row)
+      }
+      function selectProducts(){
+        SelectPrpductModalRef.value.getTable()
+      }
+      function onSearchProject(){
+        SelectProjectModalRef.value.getTable()
+      }
+      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 onChangequotationPeriod(data){
+        quotationPeriod.value = data
+        formData.quotationPeriodBegin = data[0].format('YYYY-MM-DD')
+        formData.quotationPeriodEnd = data[1].format('YYYY-MM-DD')
+      }
+      function chooseSupplier(){
+
+      }
+      function changeDelivertTime(prop){
+         if(saleQuotationFormProductTable.dataSource.length>0){
+            var newArr = [...saleQuotationFormProductTable.dataSource]
+            newArr.map(item=>{
+              item.deliveryTime = prop
+            })
+            saleQuotationFormProductTable.dataSource = newArr
+         }
+      }
+      function viewHistory(){
+        ViewHistoryQuotationModalRef.value.getTable()
+      }
+      async function VersionDetail(record){
+         //主表数据
+         await queryVersonHistoryData(record.id);
+         //子表数据
+        const saleQuotationFormShipDataList = await querysaleVersonFormShipListByMainId(record.id);
+        saleQuotationFormShipTable.dataSource = [...saleQuotationFormShipDataList];
+        const saleQuotationFormProductDataList = await querySaleVersonProductListByMainId(record.id);
+        saleQuotationFormProductTable.dataSource = [...saleQuotationFormProductDataList];
+        getOptiom()
+        getCustomerOptions()
+        quotationPeriod.value[0]=formData.quotationPeriodBegin?moment(formData.quotationPeriodBegin):''
+        quotationPeriod.value[1]=formData.quotationPeriodEnd?moment(formData.quotationPeriodEnd):''
+      }
+      async function queryVersonHistoryData(id){
+        const row = await queryVersonHistoryById(id);
+        resetFields();
+        const tmpData = {};
+        Object.keys(formData).forEach((key) => {
+          if(row.hasOwnProperty(key)){
+            tmpData[key] = row[key]
+          }
+        })
+        //赋值
+        Object.assign(formData,tmpData);
+      }
+      return {
+        saleQuotationFormShipTableRef,
+        saleQuotationFormShipTable,
+        saleQuotationFormProductTableRef,
+        saleQuotationFormProductTable,
+        validatorRules,
+        validateInfos,
+        activeKey,
+        loading,
+        formData,
+        setFieldsValue,
+        handleFormChange,
+        formItemLayout,
+        disabled,
+        getFormData,
+        submitForm,
+        SelectShipSModalRef,
+        add,
+        edit,
+        formRef,
+        selectShip,
+        addShip,
+        addProduct,
+        BaseShipArchiveAccessoriesListRef,
+        viewAccessory,
+        handleDelete,
+        handleDelete1,
+        selectProducts,
+        SelectPrpductModalRef,
+        SelectProjectModalRef,
+        ViewHistoryQuotationModalRef,
+        onSearchProject,
+        addProject,
+        getOptiom,
+        classOption,
+        getCustomerOptions,
+        customerOption,
+        quotationPeriod,
+        onChangequotationPeriod,
+        chooseSupplier,
+        changeDelivertTime,
+        viewHistory,
+        baseUrl,
+        VersionDetail,
+        queryVersonHistoryData
+      }
+    }
+  });
+</script>
+<style lang="less" scoped>
+  /** 时间和数字输入框样式 */
+  :deep(.ant-input-number) {
+    width: 100%;
+  }
+
+  :deep(.ant-calendar-picker) {
+    width: 100%;
+  }
+  /deep/.vxe-table--body-wrapper{
+    height: 100% !important;
+  }
+  /deep/.ant-modal-body{
+    padding: 24px !important;
+  }
+  
+  /deep/.ant-form-item{
+    margin-bottom: 8px !important;
+  }
+      
+</style>

+ 78 - 0
src/views/saleCode/quotation/components/quotationFormModal.vue

@@ -0,0 +1,78 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" width="95%" @ok="handleSubmit">
+    <quotationFormForm ref="formComponent" :formDisabled="formDisabled" :formBpm="false" @success="submitSuccess"></quotationFormForm>
+  </BasicModal>
+</template>
+
+<script lang="ts">
+  import { ref, unref } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import quotationFormForm from './quotationFormForm.vue';
+
+  export default {
+    name: "TestCgMainVxeModal",
+    components:{
+      BasicModal,
+      quotationFormForm
+    },
+    emits:['register','success'],
+    setup(_p, {emit}){
+      const formComponent = ref()
+      const isUpdate = ref(true);
+      const formDisabled = ref(false);
+      const isRevise = ref(false);
+      const title = ref('')
+
+      //表单赋值
+      const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        formDisabled.value = !data?.showFooter;
+        title.value = data?.isUpdate ? (unref(formDisabled) ? '详情' : '编辑') : '新增';
+        title.value = data.isRevise ? '修改(Revise)' : title.value;
+        if (unref(isUpdate)) {
+          formComponent.value.edit(data.record)
+        }else{
+          formComponent.value.add()
+        }
+      });
+
+      function handleSubmit() {
+        formComponent.value.submitForm();
+      }
+
+      function submitSuccess(){
+        emit('success');
+        closeModal();
+      }
+      function getVersionDetail(record){
+        setModalProps({open: true,showOkBtn:false});
+        title.value ='详情'
+        formDisabled.value = true
+        setTimeout(()=>{
+          formComponent.value.VersionDetail(record)
+        },100)
+      }
+
+      return {
+        registerModal,
+        title,
+        formComponent,
+        formDisabled,
+        handleSubmit,
+        submitSuccess,
+        getVersionDetail
+      }
+    }
+  }
+</script>
+<style lang="less" scoped>
+	/** 时间和数字输入框样式 */
+  :deep(.ant-input-number) {
+    width: 100%;
+  }
+
+  :deep(.ant-calendar-picker) {
+    width: 100%;
+  }
+</style>

+ 67 - 40
src/views/saleCode/quotation/quotation.vue

@@ -35,12 +35,6 @@
                 <JDictSelectTag v-model:value="queryParam.busynessType" placeholder="请选择" dictCode="busyness_type"/>
               </a-form-item>
             </a-col>
-            <a-col :lg="8">
-              <a-form-item name="ship">
-                <template #label><span title="船(ship)">船(ship)</span></template>
-                <a-input placeholder="请输入船(ship)" v-model:value="queryParam.shipID" allow-clear ></a-input>
-              </a-form-item>
-            </a-col>
             <a-col :lg="8">
               <a-form-item name="priority">
                 <template #label><span title="优先级(priority)">优先级(priority)</span></template>
@@ -86,7 +80,7 @@
             <a-col :lg="8">
               <a-form-item name="submit">
                 <template #label><span title="状态(status)">状态(status)</span></template>
-                <JDictSelectTag v-model:value="queryParam.status" placeholder="请选择" dictCode="inquiry_status"/>
+                <JDictSelectTag v-model:value="queryParam.status" placeholder="请选择" dictCode="quotation_status"/>
               </a-form-item>
             </a-col>
           </template>
@@ -109,12 +103,14 @@
    <BasicTable @register="registerTable" :rowSelection="rowSelection" size="small" >
      <!--插槽:table标题-->
       <template #tableTitle>
-          <a-button type="primary" v-auth="'saleCode:sale_inquiry_form:add'"  @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增(add)</a-button>
-          <a-button  type="primary" v-auth="'saleCode:sale_inquiry_form:exportXls'"  preIcon="ant-design:export-outlined" @click="onExportXls"> 导出(export)</a-button>
+          <a-button type="primary" v-auth="'saleCode:sale_quotation:add'"  @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增(add)</a-button>
+          <a-button  type="primary" v-auth="'saleCode:sale_quotation:exportXls'"  preIcon="ant-design:export-outlined" @click="onExportXls"> 导出(export)</a-button>
+          <a-button  type="primary"  @click="submit"> 提交(submit)</a-button>
+          <a-button  type="primary"  @click="cancelSubmit"> 取消提交(cancelSubmit)</a-button>
           <a-dropdown v-if="selectedRowKeys.length > 0">
               <template #overlay>
                 <a-menu>
-                  <a-menu-item key="1" @click="batchHandleDelete">
+                  <a-menu-item key="1" @click="batchHandleDelete" v-auth="'saleCode:sale_quotation:deleteBatch'" >
                     <Icon icon="ant-design:delete-outlined"></Icon>
                     删除(delete)
                   </a-menu-item>
@@ -133,8 +129,9 @@
       <template v-slot:bodyCell="{ column, record, index, text }">
       </template>
     </BasicTable>
+    <quotationFormModal  @register="registerModal" @success="handleSuccess"></quotationFormModal>
+    <ViewHistoryVersionModal ref="ViewHistoryVersionModalRef" @success="handleSuccess"></ViewHistoryVersionModal>
     <!-- 表单区域 -->
-    <SaleInquiryFormModal @register="registerModal" @success="handleSuccess"></SaleInquiryFormModal>
   </div>
 </template>
 
@@ -143,7 +140,6 @@
   import {BasicTable, useTable, TableAction} from '/@/components/Table';
   import { useListPage } from '/@/hooks/system/useListPage'
   import {useModal} from '/@/components/Modal';
-  import SaleInquiryFormModal from './components/SaleInquiryFormModal.vue'
   import {columns, superQuerySchema} from './quotationForm.data';
   import {list, deleteOne, batchDelete, getImportUrl,getExportUrl,batchSubmit,cancelBatchSubmit} from './quotationForm.api';
   import { cloneDeep } from "lodash-es";
@@ -151,6 +147,8 @@
   import { defHttp } from '/@/utils/http/axios';
   import { JDictSelectTag} from '/@/components/Form';
   import JSelectInput from '/@/components/Form/src/jeecg/components/JSelectInput.vue';
+  import quotationFormModal from './components/quotationFormModal.vue';
+  import ViewHistoryVersionModal from './components/ViewHistoryVersionModal.vue';
   import { message } from 'ant-design-vue';
   const formRef = ref();
   const queryParam = reactive<any>({});
@@ -159,6 +157,7 @@
   const [registerModal, {openModal}] = useModal();
   const userStore = useUserStore();
   var classOption = ref([]);
+  var ViewHistoryVersionModalRef = ref();
    //注册table数据
   const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
       tableProps:{
@@ -168,11 +167,11 @@
            canResize:false,
            useSearchForm: false,
            actionColumn: {
-               width: 200,
+               width: 340,
                fixed:'right'
            },
            scroll:{
-            x:'4000px'
+            x:'2700px'
            },
            beforeFetch: async (params) => {
              let rangerQuery = await setRangeQuery();
@@ -180,7 +179,7 @@
            },
         },
         exportConfig: {
-            name:"销售价单",
+            name:"销售价单",
             url: getExportUrl,
             params: queryParam,
         },
@@ -213,20 +212,34 @@
     * 新增事件
     */
   function handleAdd() {
-    //  openModal(true, {
-    //    isUpdate: false,
-    //    showFooter: true,
-    //  });
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+       isRevise: false
+     });
   }
    /**
     * 编辑事件
     */
   function handleEdit(record: Recordable) {
-    //  openModal(true, {
-    //    record,
-    //    isUpdate: true,
-    //    showFooter: true,
-    //  });
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+       isRevise: false
+     });
+   }
+   //修订
+   function handleRevise(record: Recordable){
+    openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+       isRevise: true
+     });
+   }
+   function handleViewHistory(record: Recordable){
+    ViewHistoryVersionModalRef.value.getTable(record)
    }
   //  产品分类
   function getOptiom(){
@@ -252,11 +265,11 @@
     * 详情
    */
   function handleDetail(record: Recordable) {
-    //  openModal(true, {
-    //    record,
-    //    isUpdate: true,
-    //    showFooter: false,
-    //  });
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
    }
    /**
     * 删除事件
@@ -284,7 +297,29 @@
          {
            label: '编辑(edit)',
            onClick: handleEdit.bind(null, record),
-           auth: 'saleCode:sale_inquiry_form:edit'
+           auth: 'saleCode:sale_quotation:edit',
+           ifShow: record.status=='0'
+         },
+         {
+           label: '修订(revise)',
+           ifShow: record.status=='1',
+           auth:'saleCode:sale_quotation:editHis',
+           onClick: handleRevise.bind(null, record),
+         }, 
+         {
+           label: '查看历史版本(history)',
+           onClick: handleViewHistory.bind(null, record),
+           ifShow: record.status=='1'
+         }, 
+         {
+           label: '删除(delete)',
+           popConfirm: {
+             title: '是否确认删除',
+             confirm: handleDelete.bind(null, record),
+             placement: 'topLeft'
+           },
+           ifShow: record.status=='0',
+           auth: 'saleCode:sale_quotation:delete'
          }
        ]
    }
@@ -293,18 +328,10 @@
         */
   function getDropDownAction(record){
        return [
-         {
+       {
            label: '详情(detail)',
            onClick: handleDetail.bind(null, record),
-         }, {
-           label: '删除(delete)',
-           popConfirm: {
-             title: '是否确认删除',
-             confirm: handleDelete.bind(null, record),
-             placement: 'topLeft'
-           },
-           auth: 'saleCode:sale_inquiry_form:delete'
-         }
+         }, 
        ]
    }
   function submit(){

+ 34 - 15
src/views/saleCode/quotation/quotationForm.api.ts

@@ -5,17 +5,22 @@ const { createConfirm } = useMessage();
 
 enum Api {
   list = '/saleCode/saleQuotation/list',
-  save='/saleCode/saleInquiryForm/add',
-  edit='/saleCode/saleInquiryForm/edit',
-  deleteOne = '/saleCode/saleInquiryForm/delete',
-  deleteBatch = '/saleCode/saleInquiryForm/deleteBatch',
-  importExcel = '/saleCode/saleInquiryForm/importExcel',
-  exportXls = '/saleCode/saleInquiryForm/exportXls',
-  queryDataById = '/saleCode/saleInquiryForm/queryById',
-  saleInquiryFormShipList = '/saleCode/saleInquiryForm/querySaleInquiryFormShipByMainId',
-  saleInquiryFormProductList = '/saleCode/saleInquiryForm/querySaleInquiryFormProductByMainId',
-  submitBatch='/saleCode/saleInquiryForm/submitBatch',
-  cancelSubmitBatch='/saleCode/saleInquiryForm/returnSubmitBatch'
+  save='/saleCode/saleQuotation/add',
+  edit='/saleCode/saleQuotation/edit',
+  editHis ='/saleCode/saleQuotation/editHis',
+  QuotationHis ='/saleCode/saleQuotationHis/queryById',
+  deleteOne = '/saleCode/saleQuotation/delete',
+  deleteBatch = '/saleCode/saleQuotation/deleteBatch',
+  importExcel = '/saleCode/saleQuotation/importExcel',
+  exportXls = '/saleCode/saleQuotation/exportXls',
+  queryDataById = '/saleCode/saleQuotation/queryById',
+  queryVersonHistoryById='/saleCode/saleQuotationHis/queryById',
+  saleQuotationFormShipList = '/saleCode/saleQuotation/querySaleQuotationShipByMainId',
+  saleVersonFormShipList = '/saleCode/saleQuotationHis/querySaleQuotationShipHisByMainId',
+  saleQuotationFormProductList = '/saleCode/saleQuotation/querySaleQuotationProductByMainId',
+  salVersonFormProductList = '/saleCode/saleQuotationHis/querySaleQuotationProductHisByMainId',
+  submitBatch='/saleCode/saleQuotation/submitBatch',
+  cancelSubmitBatch='/saleCode/saleQuotation/returnSubmitBatch'
 }
 /**
  * 导出api
@@ -32,12 +37,23 @@ export const getImportUrl = Api.importExcel;
  * 查询子表数据
  * @param params
  */
-export const querySaleInquiryFormShipListByMainId = (id) => defHttp.get({url: Api.saleInquiryFormShipList, params:{ id }});
+export const querysaleQuotationFormShipListByMainId = (id) => defHttp.get({url: Api.saleQuotationFormShipList, params:{ id }});
+/**
+ * 查询历史版本船子表数据
+ * @param params
+ */
+export const querysaleVersonFormShipListByMainId = (id) => defHttp.get({url: Api.saleVersonFormShipList, params:{ id }});
 /**
  * 查询子表数据
  * @param params
  */
-export const querySaleInquiryFormProductListByMainId = (id) => defHttp.get({url: Api.saleInquiryFormProductList, params:{ id }});
+export const querySaleQuotationFormProductListByMainId = (id) => defHttp.get({url: Api.saleQuotationFormProductList, params:{ id }});
+/**
+ * 查询历史版本产品子表数据
+ * @param params
+ */
+export const querySaleVersonProductListByMainId = (id) => defHttp.get({url: Api.salVersonFormProductList, params:{ id }});
+
 
 /**
  * 列表接口
@@ -76,17 +92,20 @@ 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});
 }
+//
 
 /**
 * 根据id查询数据
 * @param params
 */
 export const queryDataById = (id) => defHttp.get({url: Api.queryDataById, params:{ id }});
-
+export const queryVersonHistoryById = (id) => defHttp.get({url: Api.queryVersonHistoryById, params:{ id }});
+export const HistoryQuotation = (id) => defHttp.get({url: Api.QuotationHis, params:{ id }});
 // 提交
 export const batchSubmit = (params, handleSuccess) => {
   createConfirm({

+ 86 - 38
src/views/saleCode/quotation/quotationForm.data.ts

@@ -23,12 +23,14 @@ export const columns: BasicColumn[] = [
    {
     title: '报价项目(quotation project)',
     align:"center",
-    dataIndex: 'quotationProject_dictText'
+    width:250,
+    dataIndex: 'quotationProjectName'
    },
    {
     title: '报价客户(quotation customer)',
     align:"center",
-    dataIndex: 'quotationCustomer_dictText'
+    width:250,
+    dataIndex: 'quotationCustomerName'
    },
    {
     title: '报价有效期(quotation period)',
@@ -48,21 +50,6 @@ export const columns: BasicColumn[] = [
       return text;
     },
    },
-  //  {
-  //   title: '询价有效期(inquiry period)止',
-  //   align:"center",
-  //   width:250,
-  //   dataIndex: 'inquiryPeriodEnd',
-  //   customRender:({text}) =>{
-  //     text = !text ? "" : (text.length > 10 ? text.substr(0,10) : text);
-  //     return text;
-  //   },
-  //  },
-   {
-    title: '船(ship)',
-    align:"center",
-    dataIndex: 'shipName'
-   },
    {
     title: '优先级(priority)',
     align:"center",
@@ -71,7 +58,8 @@ export const columns: BasicColumn[] = [
    {
     title: '产品分类(production class)',
     align:"center",
-    dataIndex: 'productionClass'
+    dataIndex: 'productionClass',
+    width:250,
    },
    {
     title: '机型(model)',
@@ -86,7 +74,7 @@ export const columns: BasicColumn[] = [
    {
     title: '业务类型(busyness type)',
     align:"center",
-    dataIndex: 'busyness type'
+    dataIndex: 'busynessType;'
    },
 
    {
@@ -95,9 +83,9 @@ export const columns: BasicColumn[] = [
     dataIndex: 'status',
     customRender:function (t, r, index) {
       if(t.text==1){
-        return '已报价'
+        return '已确认'
       }else if(t.text==0){
-        return '未报价'
+        return '未确认'
       }
     }
    },
@@ -109,7 +97,7 @@ export const columns: BasicColumn[] = [
 ];
 
 //子表表格配置
-export const saleInquiryFormShipColumns: JVxeColumn[] = [
+export const saleQuotationFormShipColumns: JVxeColumn[] = [
     {
       title: '船名(ship name)',
       key: 'shipName',
@@ -159,7 +147,7 @@ export const saleInquiryFormShipColumns: JVxeColumn[] = [
       slotName: 'action',
     },
   ]
-export const saleInquiryFormProductColumns: JVxeColumn[] = [
+export const saleQuotationFormProductColumns: JVxeColumn[] = [
     {
       title: '交期(delivery time)',
       key: 'deliveryTime',
@@ -246,16 +234,13 @@ export const saleInquiryFormProductColumns: JVxeColumn[] = [
       placeholder: '请输入${title}',
       width:"200px",
       defaultValue:'',
-      type: JVxeTypes.select,
-      options: [],
+      type: JVxeTypes.normal,
       dictCode: 'factory',
     },
     {
       title: '质量等级(quality grade)',
       key: 'qualityGrade',
-      type: JVxeTypes.select,
-      options: [],
-      dictCode: 'quality_grade',
+      type: JVxeTypes.normal,
       placeholder: '请输入${title}',
       width:"200px",
       defaultValue:'',
@@ -269,29 +254,92 @@ export const saleInquiryFormProductColumns: JVxeColumn[] = [
       defaultValue:'',
     },
     {
-      title: '单位(unit)',
-      key: 'unit',
+      title: '供应商币种(supplier currency)',
+      key: 'supplierCurrency',
       type: JVxeTypes.normal,
       placeholder: '请输入${title}',
       defaultValue:'',  
       width:"200px",
     },
     {
-      title: '需要船检证书(need Ship inspection certificate)',
-      key: 'needShip',
+      title: '采购单价(purchase price)',
+      key: 'purchasePrice',
+      type: JVxeTypes.inputNumber,
+      placeholder: '请输入${title}',
+      width:"200px",
+      defaultValue:'',
+    },
+    {
+      title: '税率(tax rate)',
+      key: 'taxRate',
+      type: JVxeTypes.inputNumber,
+      placeholder: '请输入${title}',
       width:"200px",
+      defaultValue:'',
+    },
+    {
+      title: '毛利率(gross margin)',
+      key: 'grossMargin',
+      type: JVxeTypes.inputNumber,
       placeholder: '请输入${title}',
+      width:"200px",
       defaultValue:'',
-      type: JVxeTypes.select,
-      options: [],
-      dictCode: 'yes_or_no',
     },
     {
-      title: '船检证书(ship Inspection certificate)',
-      key: 'shipInspection',
-      type: JVxeTypes.input,
+      title: '折扣(discount)',
+      key: 'discount',
+      type: JVxeTypes.inputNumber,
+      placeholder: '请输入${title}',
       width:"200px",
+      defaultValue:'',
+    },
+    {
+      title: '关税(tariff)',
+      key: 'tariff',
+      type: JVxeTypes.inputNumber,
       placeholder: '请输入${title}',
+      width:"200px",
+      defaultValue:'',
+    },
+    {
+      title: '客户佣金(customer commission)',
+      key: 'customerCommision',
+      type: JVxeTypes.inputNumber,
+      placeholder: '请输入${title}',
+      width:"200px",
+      defaultValue:'',
+    },
+    {
+      title: '中间人佣金(intermediator commission)',
+      key: 'intermediatorCommission',
+      type: JVxeTypes.inputNumber,
+      placeholder: '请输入${title}',
+      width:"200px",
+      defaultValue:'',
+    },
+    {
+      title: '销售单价(sale price)',
+      key: 'salePrice',
+      type: JVxeTypes.normal,
+      placeholder: '请输入${title}',
+      width:"200px",
+      defaultValue:'',
+    },
+    {
+      title: '上一次报价(last price)',
+      key: 'lastPrice',
+      type: JVxeTypes.slot,
+      placeholder: '请输入${title}',
+      width:"200px",
+      defaultValue:'',
+      slotName: 'lastPrice',
+    },
+    {
+      title: '含税报价(tax amount)',
+      key: 'taxAmount',
+      type: JVxeTypes.normal,
+      placeholder: '请输入${title}',
+      width:"200px",
       defaultValue:'',
     },
     {