瀏覽代碼

Merge branch 'master' of http://47.101.159.18:3000/Muchinfo/MTP2.0_WEB

marymelisa 4 年之前
父節點
當前提交
815936b2a5
共有 40 個文件被更改,包括 1753 次插入531 次删除
  1. 92 0
      public/proto/mtp.proto
  2. 13 5
      src/App.vue
  3. 205 0
      src/assets/styles/index.css
  4. 1 1
      src/assets/styles/index.less
  5. 69 0
      src/components/contextMenu/contextMenu.vue
  6. 50 37
      src/components/contextMenu/index.vue
  7. 128 122
      src/components/orderTable/index.vue
  8. 17 41
      src/components/quoteTable/index.vue
  9. 5 0
      src/funcode/index.ts
  10. 4 4
      src/goServiceAPI/ermcp/customInfo/index.ts
  11. 1 1
      src/goServiceAPI/ermcp/customInfo/type.ts
  12. 16 1
      src/goServiceAPI/ermcp/inventory-review/index.ts
  13. 59 0
      src/goServiceAPI/ermcp/inventory-review/interface.ts
  14. 6 6
      src/goServiceAPI/ermcp/spot-contract/index.ts
  15. 62 62
      src/goServiceAPI/ermcp/spot-contract/interface.ts
  16. 1 2
      src/layout/top.vue
  17. 0 0
      src/protoService/accountinfo/index.ts
  18. 0 0
      src/protoService/accountinfo/interface.ts
  19. 39 0
      src/protoService/contract/index.ts
  20. 28 0
      src/protoService/contract/interface.ts
  21. 0 2
      src/protoService/delivery/index.ts
  22. 39 0
      src/protoService/spotcontract/index.ts
  23. 59 0
      src/protoService/spotcontract/interface.ts
  24. 8 0
      src/setup/controlModal/interface.ts
  25. 2 1
      src/setup/router/index.ts
  26. 47 0
      src/views/information/custom/compoments/customDetail/index.vue
  27. 47 0
      src/views/information/custom/compoments/deleteCustom/index.vue
  28. 47 0
      src/views/information/custom/compoments/disableCustom/index.vue
  29. 16 25
      src/views/information/custom/compoments/filterTable/index.vue
  30. 47 0
      src/views/information/custom/compoments/modifyCustom/index.vue
  31. 47 0
      src/views/information/custom/compoments/recover/index.vue
  32. 1 1
      src/views/information/custom/index.vue
  33. 72 97
      src/views/information/custom/list/normal-use/index.vue
  34. 95 0
      src/views/information/custom/list/setup.ts
  35. 84 61
      src/views/information/custom/list/stop-use/index.vue
  36. 49 0
      src/views/information/spot-contract/components/add/index.vue
  37. 154 0
      src/views/information/spot-contract/components/filterTable/index.vue
  38. 37 60
      src/views/information/spot-contract/list/not-commit/index.vue
  39. 105 0
      src/views/information/spot-contract/list/setup.ts
  40. 1 2
      src/views/search/outaccount_status/index.vue

+ 92 - 0
public/proto/mtp.proto

@@ -781,3 +781,95 @@ message WarehouseStateChangeRsp {
 	optional string RetDesc = 3; // string 描述信息
 	optional uint64 warehouseid = 4; // uint64 仓库ID
 }
+
+// 现货合同操作请求 0 29 167
+message GldErmcpSpotContractOperateReq {
+	optional MessageHead Header = 1; // MessageHead
+	optional uint64 SpotContractID = 2; // uint64 现货合同ID(602+Unix秒时间戳(10位)+xxxxxx)
+	optional uint32 OperateType = 3; // uint32 操作类型-1:保存草稿2:提交申请3:审核通过4:审核拒绝5:撤回6:正常完结7:异常终止
+	optional uint32 OperateSrc = 4; // uint32 操作来源-1:管理端2:终端
+	optional uint64 UserID = 5; // uint64 操作用户ID
+	optional string Remark = 6; // string 操作备注
+	optional string ClientTicket = 7; // string 客户端流水号
+	optional GldSpotContractInfo Info = 8; // GldSpotContractInfo 现货合同信息
+}
+// 现货合同操作响应 0 29 168
+message GldErmcpSpotContractOperateRsp {
+	optional MessageHead Header = 1; // MessageHead 消息头
+	optional int32 RetCode = 2; // int32 返回码
+	optional string RetDesc = 3; // string 描述信息
+	optional uint64 SpotContractID = 4; // uint64 现货合同ID(602+Unix秒时间戳(10位)+xxxxxx)
+	optional uint32 OperateType = 5; // uint32 操作类型-1:保存草稿2:提交申请3:审核通过4:审核拒绝5:撤回6:正常完结7:异常终止
+	optional uint32 OperateSrc = 6; // uint32 操作来源-1:管理端2:终端
+	optional string ClientTicket = 7; // string 客户端流水号
+}
+
+// 现货合同信息 0 29 166
+message GldSpotContractInfo {
+	optional string TradeDate = 1; // string 交易日(yyyyMMdd)
+	optional string ContractNo = 2; // string 现货合同编号
+	optional int32 ContractType = 3; // int32 现货合同类型-1:采购-1:销售
+	optional uint64 UserID = 4; // uint64 机构ID
+	optional uint64 BuyUserID = 5; // uint64 采购方ID
+	optional uint64 SellUserID = 6; // uint64 客户ID
+	optional string SignDate = 7; // string 签订日期
+	optional bytes ContractAttachment = 8; // bytes 合同附件
+	optional double ContractMargin = 9; // double 合同保证金
+	optional uint64 DeliveryGoodsID = 10; // uint64 现货品种ID
+	optional uint64 WrStandardID = 11; // uint64 现货商品ID
+	optional uint32 ProductType = 12; // uint32 产品类型-1:标准仓单2:等标3:非标
+	optional double ConvertFactor = 13; // double 标仓系数
+	optional string SpotGoodsDesc = 14; // string 商品型号
+	optional uint32 PriceType = 15; // uint32 定价类型-1:一口价2:点价3:暂定价
+	optional double Qty = 16; // double 数量
+	optional double Price = 17; // double 价格暂定价[1:一口价、3:暂定价]
+	optional double Amount = 18; // double 金额[1:一口价、3:暂定价]
+	optional string DeliveryStartDate = 19; // string 交收期(开始)
+	optional string DeliveryEndDate = 20; // string 交收期(结束)
+	optional uint64 GoodsID = 21; // uint64 点价合约ID-0:为现货,其它为期货商品合约ID[2:点价3:暂定价]
+	optional double PriceMove = 22; // double 升贴水[2:点价3:暂定价]
+	optional string StartDate = 23; // string 点价开始日期[2:点价3:暂定价]
+	optional string EndDate = 24; // string 点价结束日期[2:点价3:暂定价]
+	optional string PointDesc = 25; // string 点价备注[2:点价3:暂定价]
+	optional string DeliveryDesc = 26; // string 交收方式
+	optional uint64 MerUserID = 27; // uint64 跟单员ID
+	optional uint64 TradeUserID = 28; // uint64 交易员ID
+	optional double PricedQty = 29; // double 已定价量
+	optional double PricedAmount = 30; // double 已定价金额
+	optional uint64 SpotGoodsBrandID = 31; // uint64 现货品牌ID
+	optional string Remark = 32; // string 合同备注
+	optional uint64 SaleUserID = 33; // uint64 业务员ID
+	optional uint64 AccountID = 34; // uint64 期货账户ID
+	optional uint32 BizType = 35; // uint32 业务类型 - 1:套保 2:套利
+}
+// 合同操作请求 0 29 170
+message ErmcpContractOperateApplyReq {
+	optional MessageHead Header = 1; // MessageHead
+	optional uint64 OperateApplyID = 2; // uint64 操作申请ID(603+Unix秒时间戳(10位)+xxxxxx)
+	optional uint32 OperateType = 3; // uint32 操作类型-1:登记2:确认3:拒绝4:撤销
+	optional uint32 OperateSrc = 4; // uint32 操作来源-1:管理端2:终端
+	optional uint64 UserID = 5; // uint64 操作用户ID
+	optional string Remark = 6; // string 备注
+	optional string ClientTicket = 7; // string 客户端流水号
+	optional ErmcpContractOperateApplyInfo Info = 8; // ErmcpContractOperateApplyInfo 合同操作信息
+}
+// 合同操作响应 0 29 171
+message ErmcpContractOperateApplyRsp {
+	optional MessageHead Header = 1; // MessageHead 消息头
+	optional int32 RetCode = 2; // int32 返回码
+	optional string RetDesc = 3; // string 描述信息
+	optional uint64 OperateApplyID = 4; // uint64 操作申请ID(603+Unix秒时间戳(10位)+xxxxxx)
+	optional uint32 OperateType = 5; // uint32 操作类型-1:登记2:确认3:拒绝4:撤销
+	optional uint32 OperateSrc = 6; // uint32 操作来源-1:管理端2:终端
+	optional string ClientTicket = 7; // string 客户端流水号
+}
+// 合同操作信息 0 29 169
+message ErmcpContractOperateApplyInfo {
+	optional uint32 OperateApplyType = 1; // uint32 操作申请类型-1:点价2:结算3:款项4:发票
+	optional uint64 RelatedID = 2; // uint64 现货合同ID(602+Unix秒时间戳(10位)+xxxxxx)
+	optional bytes DetailJson = 3; // bytes 明细JSON
+	optional bytes AttachUrl = 4; // bytes 附件
+}
+
+
+

+ 13 - 5
src/App.vue

@@ -1,9 +1,12 @@
 <template>
-  <a-spin :tip="tip"
-          :spinning="spinning"
-          size="large">
-    <router-view />
-  </a-spin>
+  <div class="app-container"
+       @contextmenu.prevent>
+    <a-spin :tip="tip"
+            :spinning="spinning"
+            size="large">
+      <router-view />
+    </a-spin>
+  </div>
 </template>
 
 <script lang="ts">
@@ -127,6 +130,11 @@ export default defineComponent({
 </script>
 
 <style lang="less">
+.app-container {
+    width: 100%;
+    height: auto;
+    min-height: 100%;
+}
 #app {
     width: 100%;
     height: auto;

+ 205 - 0
src/assets/styles/index.css

@@ -33,6 +33,210 @@
   text-overflow: ellipsis;
   overflow: hidden;
 }
+.commonInput {
+  background: #15202B;
+  border: 1px solid #2B3F52;
+  border-radius: 3px;
+  color: #E5E5E5;
+}
+.commonInput .ant-input {
+  color: #E5E5E5;
+  background: transparent;
+}
+.commonInput .ant-input::placeholder {
+  color: #394753;
+}
+.commonInput .ant-input-suffix {
+  color: #E5E5E5;
+}
+.tableConditionInput {
+  width: 140px;
+  height: 30px;
+  line-height: 30px;
+  background: #252D34;
+  /*圆角兼容性*/
+  -moz-border-radius: 3px 3px 3px 3px;
+  -webkit-border-radius: 3px 3px 3px 3px;
+  border-radius: 3px 3px 3px 3px;
+  border: 0;
+  color: #E5E5E5;
+  font-size: 14px;
+}
+.tableConditionInput::placeholder {
+  color: #394753;
+}
+.tableConditionInput + .tableConditionInput {
+  margin-left: 10px;
+}
+.ant-select-dropdown {
+  background: #424E59;
+  border: 1px solid #48545F;
+  box-shadow: 0px 10px 10px 0px rgba(18, 22, 24, 0.36);
+  border-radius: 5px;
+}
+.ant-select-dropdown .ant-select-item {
+  color: #7a8a94;
+}
+.ant-select-dropdown .ant-select-item-option-active,
+.ant-select-dropdown .ant-select-item-option-selected,
+.ant-select-dropdown .ant-select-item-option-hover {
+  background: #3a87f7;
+  color: #E5E5E5;
+}
+.topTable .ant-table {
+  width: 100%;
+}
+.topTable .ant-table table {
+  border: 0;
+}
+.topTable .ant-table .ant-table-thead tr {
+  box-shadow: 0px 1px 0px 0px #2E3539;
+}
+.topTable .ant-table .ant-table-thead tr th {
+  line-height: 34px;
+  background: #212629;
+  padding-top: 0;
+  padding-bottom: 0;
+  color: #556772;
+  font-size: 14px;
+  border-color: #161A1C;
+}
+.topTable .ant-table .ant-table-placeholder {
+  border: 0;
+  background: #0E0E0F;
+}
+.ant-empty-normal {
+  color: #556772;
+}
+.ant-empty-img-simple-path,
+.ant-empty-img-simple-ellipse {
+  fill: #556772;
+}
+.ant-empty-img-simple-g {
+  stroke: #556772;
+}
+.add-custom .ant-modal-content {
+  background: #0F1A25;
+  border-radius: 5px;
+}
+.add-custom .ant-modal-content .ant-modal-close .ant-modal-close-x {
+  width: 40px;
+  height: 40px;
+  line-height: 40px;
+}
+.add-custom .ant-modal-content .ant-modal-close .ant-modal-close-x .ant-modal-close-icon {
+  color: #1271BA;
+}
+.add-custom .ant-modal-content .ant-modal-header {
+  height: 40px;
+  background: linear-gradient(0deg, #112C43, #084258);
+  border-radius: 5px;
+  padding: 0;
+  text-align: center;
+  border-bottom: 0;
+}
+.add-custom .ant-modal-content .ant-modal-header .ant-modal-title {
+  line-height: 40px;
+  font-size: 16px;
+  color: #ffffff;
+}
+.add-custom .ant-modal-content .ant-modal-footer {
+  border-top: 0;
+  text-align: center;
+  padding-bottom: 31px;
+}
+.add-custom .ant-modal-content .ant-modal-footer .ant-btn-primary {
+  width: 200px;
+  height: 34px;
+  line-height: 34px;
+  border: 0;
+  background: linear-gradient(0deg, #3163BA 0%, #4179DB 100%);
+  border-radius: 3px;
+  font-size: 16px;
+  color: #ffffff;
+}
+.add-custom .ant-modal-content .ant-modal-footer .ant-btn-primary:hover {
+  background: linear-gradient(0deg, rgba(49, 99, 186, 0.8) 0%, rgba(65, 121, 219, 0.8) 100%);
+  color: rgba(255, 255, 255, 0.8);
+}
+.ant-form.inlineForm .ant-row.ant-form-item {
+  margin-bottom: 21px;
+}
+.ant-form.inlineForm .ant-row.ant-form-item .ant-form-item-label {
+  width: 80px;
+  line-height: 30px;
+  text-align: left;
+}
+.ant-form.inlineForm .ant-row.ant-form-item .ant-form-item-label label {
+  color: #7a8a94;
+}
+.ant-form.inlineForm .ant-row.ant-form-item .ant-form-item-label label::after {
+  content: '';
+}
+.ant-form.inlineForm .ant-row.ant-form-item .ant-form-item-control-wrapper .ant-form-item-control {
+  line-height: 30px;
+}
+.ant-form.inlineForm .relative.ant-form-item {
+  position: relative;
+}
+.ant-form.inlineForm .relative.ant-form-item .tip {
+  position: absolute;
+  font-size: 14px;
+  color: #7a8a94;
+}
+.ant-form.inlineForm .tc.ant-form-item .ant-form-item-control-wrapper {
+  margin: 0 auto;
+}
+.ant-select-single .ant-select-selector {
+  height: 30px;
+  padding: 0 8px;
+  background: #15202B;
+  border: 1px solid #0C95FF;
+  border-radius: 3px;
+  color: #E5E5E5;
+}
+.ant-select-single .ant-select-arrow {
+  right: 8px;
+  color: #3A87F7;
+}
+.inlineFormSelect.ant-select-single,
+.typeSelect.ant-select-single {
+  /*圆角兼容性*/
+  -moz-border-radius: 3px 3px 3px 3px;
+  -webkit-border-radius: 3px 3px 3px 3px;
+  border-radius: 3px 3px 3px 3px;
+}
+.inlineFormSelect.ant-select-single .ant-select-selector {
+  height: 30px;
+  padding: 0 8px;
+  background: #15202B;
+  border: 1px solid #0C95FF;
+  border-radius: 3px;
+  color: #E5E5E5;
+}
+.inlineFormSelect.ant-select-single .ant-select-selector .ant-select-selection-placeholder {
+  color: #394753;
+}
+.inlineFormSelect.ant-select-single .ant-select-arrow {
+  right: 8px;
+  color: #3A87F7;
+}
+.typeSelect.ant-select-single {
+  border: 1px solid #0C95FF;
+}
+.commonInput {
+  background: #15202B;
+  border: 1px solid #2B3F52;
+  border-radius: 3px;
+  color: #E5E5E5;
+}
+.commonInput .ant-input {
+  color: #E5E5E5;
+  background: transparent;
+}
+.commonInput .ant-input-suffix {
+  color: #E5E5E5;
+}
 /*滚动条样式*/
 ::-webkit-scrollbar {
   width: 10px;
@@ -176,6 +380,7 @@ body {
 }
 .ant-spin-nested-loading {
   width: 100%;
+  height: 100%;
 }
 .ant-spin-nested-loading .ant-spin-container {
   width: 100%;

+ 1 - 1
src/assets/styles/index.less

@@ -163,7 +163,7 @@ body {
 }
 .ant-spin-nested-loading {
     width: 100%;
-    // height: 100%;
+    height: 100%;
     .ant-spin-container {
         width: 100%;
         height: 100%;

+ 69 - 0
src/components/contextMenu/contextMenu.vue

@@ -0,0 +1,69 @@
+<template>
+  <ul class="context-menu"
+      v-show="contextMenu.show"
+      :style="{ top: y, left: x }">
+    <li v-for="(item, index) in contextMenu.menuList"
+        :key="index"
+        @click.passive="choose(item.callback)">
+      {{item.lable}}
+    </li>
+  </ul>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref, PropType, onUnmounted, computed } from 'vue';
+import { ContextMenu } from './interface';
+
+export default defineComponent({
+    name: 'context-menu',
+    props: {
+        contextMenu: {
+            default: {
+                position: { clientX: 0, clientY: 0 },
+                show: false,
+                menuList: [],
+                selectedData: null,
+            },
+            type: Object as PropType<ContextMenu>,
+        },
+    },
+    components: {},
+    setup(props, context) {
+        onUnmounted(() => {});
+        function choose(fn: Function) {
+            context.emit('update', false);
+            fn && fn(props.contextMenu.selectedData);
+        }
+        const x = computed(() => `${props.contextMenu.position.clientX - 10}px`);
+        const y = computed(() => `${props.contextMenu.position.clientY - 10}px`);
+        return { x, y, choose };
+    },
+});
+</script>
+
+<style lang="less">
+.context-menu {
+    min-width: 100px;
+    user-select: none;
+    position: fixed;
+    background-color: #282e34;
+    z-index: 999;
+    border-radius: 2px;
+    border: 1px solid #2e3539;
+    padding-left: 0;
+    list-style: none;
+    margin-bottom: 0;
+    cursor: pointer;
+    li {
+        padding: 6px;
+        color: #88a0ae;
+        font-size: 16px;
+        border-bottom: 1px solid #2e3539;
+        text-align: center;
+        &:hover {
+            color: #e5e5e5;
+            background-color: #343e48;
+        }
+    }
+}
+</style>;

+ 50 - 37
src/components/contextMenu/index.vue

@@ -1,48 +1,61 @@
 <template>
-    <ul class="context-menu"
-        v-show="contextMenu.show"
-        :style="{ top: y, left: x }"
-    >
-        <li v-for="(item, index) in contextMenu.menuList"
-            :key="index"
-            @click.passive="choose(item.callback)"
-        >
-            {{item.lable}}
-        </li>
-    </ul>
+  <!-- 右键 -->
+  <div class="context-menu-container"
+        @click="updateContextMenu(false)"
+       @contextmenu.prevent="onContextMenu">
+    <slot></slot>
+    <contextMenu :contextMenu="menuContext"
+                 @update="updateContextMenu" />
+  </div>
 </template>
 
 <script lang="ts">
-    import { defineComponent, ref, PropType, onUnmounted, computed} from 'vue';
-    import { ContextMenu } from './interface'
+import { defineComponent, PropType, reactive } from 'vue';
+import contextMenu from './contextMenu.vue';
+import { ContextMenu, MenuItem } from './interface';
 
-    export default defineComponent({
-        name: 'context-menu',
-        props: {
-            contextMenu: {
-                default: {
-                    position: { clientX: 0, clientY: 0 },
-                    show: false,
-                    menuList: [],
-                    selectedData: null,
-                },
-                type: Object as PropType<ContextMenu>,
-            },
+export default defineComponent({
+    name: 'context-menu-container',
+    props: {
+        contextMenuList: {
+            default: [],
+            type: Array as PropType<MenuItem[]>,
         },
-        components: {},
-        setup(props, context) {
-            onUnmounted(() => {
+        tableList: {
+            default: [],
+            type: Array as PropType<any[]>,
+        },
+    },
+    components: {
+        contextMenu,
+    },
+    setup(props) {
+        const menuContext = reactive<ContextMenu>({
+            position: { clientX: 0, clientY: 0 },
+            show: false,
+            menuList: props.contextMenuList,
+            selectedData: null,
+        });
 
-            })
-            function choose(fn: Function) {
-                context.emit('update', false)
-                fn && fn(props.contextMenu.selectedData)
+        function onContextMenu(value: MouseEvent) {
+            const target = value.target as any;
+            // 获取点击表格的 tr  所在的 索引位置
+            const index = target.parentElement.rowIndex;
+            // 过滤右键表头
+            if (index) {
+                const { clientX, clientY } = value;
+                Object.assign(menuContext.position, { clientX, clientY });
+                menuContext.show = true;
+                menuContext.selectedData = props.tableList[index - 1];
             }
-            const x = computed(() => `${props.contextMenu.position.clientX - 10}px`);
-            const y = computed(() => `${props.contextMenu.position.clientY - 10}px`);
-            return {x, y, choose };
-        },
-    });
+        }
+        // 关闭右键弹窗
+        function updateContextMenu(value: boolean) {
+            menuContext.show = value;
+        }
+        return { menuContext, onContextMenu, updateContextMenu };
+    },
+});
 </script>
 
 <style lang="less">

+ 128 - 122
src/components/orderTable/index.vue

@@ -1,137 +1,143 @@
 <template>
-    <div @contextmenu.prevent="onContextMenu">
-        <a-table :columns="columns" :data-source="dataSource" class="order-table" bordered :scroll="{ x: true, y: 400 }" :pagination="false">
-            <template>
-                <a>Delete</a>
-            </template>
-            <template #expandedRowRender="{ record }">
-                <p style="margin: 0">
-                    {{ record.description }}
-                </p>
-            </template>
-        </a-table>
-        <contextMenu :contextMenu="context" @update="updateContextMenu" />
-    </div>
+  <div @contextmenu.prevent="onContextMenu">
+    <a-table :columns="columns"
+             :data-source="dataSource"
+             class="order-table"
+             bordered
+             :scroll="{ x: true, y: 400 }"
+             :pagination="false">
+      <template>
+        <a>Delete</a>
+      </template>
+      <template #expandedRowRender="{ record }">
+        <p style="margin: 0">
+          {{ record.description }}
+        </p>
+      </template>
+    </a-table>
+    <contextMenu :contextMenu="context"
+                 @update="updateContextMenu" />
+  </div>
 </template>
 <script lang="ts">
-    ``;
-    import { defineComponent, reactive, PropType } from 'vue';
-    import contextMenu from '@/components/contextMenu/index.vue';
-    import { ContextMenu, MenuItem } from '@/components/contextMenu/interface';
+import { defineComponent, reactive, PropType } from 'vue';
+import contextMenu from '@/components/contextMenu/index.vue';
+import { ContextMenu, MenuItem } from '@/components/contextMenu/interface';
 
-    // 右键事件
-    function handleContextMenu(props: any) {
-        const context = reactive<ContextMenu>({
-            position: { clientX: 0, clientY: 0 },
-            show: false,
-            menuList: [],
-            selectedData: null,
-        });
-        function onContextMenu(value: MouseEvent) {
-            const target = value.target as any;
-            // 获取点击表格的 tr  所在的 索引位置
-            const index = target.parentElement.rowIndex;
-            const { clientX, clientY } = value;
-            Object.assign(context.position, { clientX, clientY });
-            context.show = true;
-            context.selectedData = props.dataSource[index];
-        }
-        // 关闭右键弹窗
-        function updateContextMenu(value: boolean) {
-            context.show = value;
-        }
-        return { context, onContextMenu, updateContextMenu };
+// 右键事件
+function handleContextMenu(props: any) {
+    const context = reactive<ContextMenu>({
+        position: { clientX: 0, clientY: 0 },
+        show: false,
+        menuList: [],
+        selectedData: null,
+    });
+    function onContextMenu(value: MouseEvent) {
+        const target = value.target as any;
+        // 获取点击表格的 tr  所在的 索引位置
+        const index = target.parentElement.rowIndex;
+        const { clientX, clientY } = value;
+        Object.assign(context.position, { clientX, clientY });
+        context.show = true;
+        context.selectedData = props.dataSource[index];
+    }
+    // 关闭右键弹窗
+    function updateContextMenu(value: boolean) {
+        context.show = value;
     }
+    return { context, onContextMenu, updateContextMenu };
+}
 
-    export default defineComponent({
-        components: {
-            contextMenu,
+export default defineComponent({
+    components: {
+        contextMenu,
+    },
+    props: {
+        columns: {
+            default: [],
+            type: Array,
         },
-        props: {
-            columns: {
-                default: [],
-                type: Array,
-            },
-            dataSource: {
-                default: [],
-                type: Array,
-            },
-            contextMenuList: {
-                default: [],
-                type: Object as PropType<MenuItem[]>,
-            },
+        dataSource: {
+            default: [],
+            type: Array,
         },
-        setup(props) {
-            const { context, onContextMenu, updateContextMenu } = handleContextMenu(props);
-            context.menuList = props.contextMenuList;
-            return {
-                onContextMenu,
-                context,
-                updateContextMenu,
-            };
+        contextMenuList: {
+            default: [],
+            type: Object as PropType<MenuItem[]>,
         },
-    });
+    },
+    setup(props) {
+        const { context, onContextMenu, updateContextMenu } = handleContextMenu(props);
+        context.menuList = props.contextMenuList;
+        return {
+            onContextMenu,
+            context,
+            updateContextMenu,
+        };
+    },
+});
 </script>
 <style lang="less">
-    .order-table {
-        .ant-table-fixed {
-            width: max-content !important;
-            color: #e5e5e5;
-            background: #0e0e0f;
-            border-top-color: #0e0e0f !important;
-            border-left-color: #161a1c !important;
-        }
-        .ant-table-thead {
-            tr th {
-                background: #212629;
-                color: #556772;
-                font-size: 14px;
-                font-family: Adobe Heiti Std;
-            }
-        }
-        .ant-table-tbody > tr {
-            height: 40px;
-        }
-        .ant-table-tbody .ant-table-row-hover td {
-            background: #172b56 !important;
-        }
-        .ant-table-tbody > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td {
-            background: #172b56;
-        }
-        .ant-table-bordered .ant-table-thead > tr > th,
-        .ant-table-bordered .ant-table-tbody > tr > td {
-            padding: 0;
-            height: 34px;
-            line-height: 34px;
-            border-color: #161a1c;
-            font-family: Adobe Heiti Std;
-            font-size: 16px;
-        }
-        ant-table-bordered .ant-table-thead > tr > th,
-        .ant-table-bordered .ant-table-tbody > tr > td {
-            padding: 0;
-            height: 34px;
-            line-height: 34px;
-            border-color: #161a1c;
+.order-table {
+    .ant-table-fixed {
+        width: max-content !important;
+        color: #e5e5e5;
+        background: #0e0e0f;
+        border-top-color: #0e0e0f !important;
+        border-left-color: #161a1c !important;
+    }
+    .ant-table-thead {
+        tr th {
+            background: #212629;
+            color: #556772;
+            font-size: 14px;
             font-family: Adobe Heiti Std;
-            font-size: 16px;
-        }
-        .ant-table-row-expand-icon {
-            width: 14px;
-            height: 14px;
-            line-height: 9px;
-            border: 1px solid @m-blue2;
-            border-radius: 3px;
-            background: inherit;
-        }
-        .ant-table-row-collapsed::after,
-        .ant-table-row-expanded::after {
-            color: @m-blue2;
         }
+    }
+    .ant-table-tbody > tr {
+        height: 40px;
+    }
+    .ant-table-tbody .ant-table-row-hover td {
+        background: #172b56 !important;
+    }
+    .ant-table-tbody > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected) > td {
+        background: #172b56;
+    }
+    .ant-table-bordered .ant-table-thead > tr > th,
+    .ant-table-bordered .ant-table-tbody > tr > td {
+        padding: 0;
+        height: 34px;
+        line-height: 34px;
+        border-color: #161a1c;
+        font-family: Adobe Heiti Std;
+        font-size: 16px;
+    }
+    ant-table-bordered .ant-table-thead > tr > th,
+    .ant-table-bordered .ant-table-tbody > tr > td {
+        padding: 0;
+        height: 34px;
+        line-height: 34px;
+        border-color: #161a1c;
+        font-family: Adobe Heiti Std;
+        font-size: 16px;
+    }
+    .ant-table-row-expand-icon {
+        width: 14px;
+        height: 14px;
+        line-height: 9px;
+        border: 1px solid @m-blue2;
+        border-radius: 3px;
+        background: inherit;
+    }
+    .ant-table-row-collapsed::after,
+    .ant-table-row-expanded::after {
+        color: @m-blue2;
+    }
 
-        .ant-table-expanded-row,
-        .ant-table-expanded-row:hover {
-            background: #121618;
-        }
-    }</style
+    .ant-table-expanded-row,
+    .ant-table-expanded-row:hover {
+        background: #121618;
+    }
+}
+</style
 >;

+ 17 - 41
src/components/quoteTable/index.vue

@@ -1,5 +1,7 @@
 <template>
-  <div @contextmenu.prevent="onContextMenu" class="quoteTable">
+
+  <contextMenu :contextMenuList="context"
+               :tableList="dataSource">
     <a-table class="quote-table"
              :columns="columns"
              :data-source="dataSource"
@@ -10,38 +12,12 @@
         <a>action</a>
       </template>
     </a-table>
-    <contextMenu :contextMenu="context"
-                 @update="updateContextMenu" />
-  </div>
+  </contextMenu>
 </template>
 <script lang="ts">
-import { defineComponent, reactive, PropType } from 'vue';
+import { defineComponent, ref } from 'vue';
 import contextMenu from '@/components/contextMenu/index.vue';
-import { ContextMenu, MenuItem } from '@/components/contextMenu/interface';
-
-// 右键事件
-function handleContextMenu(props: any) {
-    const context = reactive<ContextMenu>({
-        position: { clientX: 0, clientY: 0 },
-        show: false,
-        menuList: [],
-        selectedData: null,
-    });
-    function onContextMenu(value: MouseEvent) {
-        const target = value.target as any;
-        // 获取点击表格的 tr  所在的 索引位置
-        const index = target.parentElement.rowIndex;
-        const { clientX, clientY } = value;
-        Object.assign(context.position, { clientX, clientY });
-        context.show = true;
-        context.selectedData = props.dataSource[index];
-    }
-    // 关闭右键弹窗
-    function updateContextMenu(value: boolean) {
-        context.show = value;
-    }
-    return { context, onContextMenu, updateContextMenu };
-}
+import { MenuItem } from '@/components/contextMenu/interface';
 
 export default defineComponent({
     components: {
@@ -56,18 +32,18 @@ export default defineComponent({
             default: [],
             type: Array,
         },
-        contextMenuList: {
-            default: [],
-            type: Object as PropType<MenuItem[]>,
-        },
     },
     setup(props) {
-        const { context, onContextMenu, updateContextMenu } = handleContextMenu(props);
-        context.menuList = props.contextMenuList;
+        const contextMenuList = ref<MenuItem[]>([
+            {
+                lable: '修改',
+                callback: () => {
+                    console.log('lll');
+                },
+            },
+        ]);
         return {
-            onContextMenu,
-            context,
-            updateContextMenu,
+            contextMenuList,
         };
     },
 });
@@ -82,7 +58,6 @@ export default defineComponent({
     height: 100%;
     .ant-spin-nested-loading {
         .ant-spin-container {
-
         }
     }
     .ant-table td {
@@ -93,7 +68,8 @@ export default defineComponent({
             width: 100px;
         }
     }
-    .ant-table-fixed,.ant-table-body {
+    .ant-table-fixed,
+    .ant-table-body {
         .ant-table-row-hover {
             td.ant-table-row-cell-break-word {
                 background-color: @m-blue3 !important;

+ 5 - 0
src/funcode/index.ts

@@ -75,4 +75,9 @@ export const funCode: Code = {
     WareHouseStateChangeRsp: 1900688,    /// 仓库状态修改响应
 
 
+    GldErmcpSpotContractOperateReq: 1900711,    /// 现货合同操作请求(1179653)
+    GldErmcpSpotContractOperateRsp: 1900712,    /// 现货合同操作响应(1179654)
+
+    ContractOperateApplyReq: 1179656, // 合同操作请求(1179656)
+    ContractOperateApplyRsp: 1179657, // 合同操作响应(1179657)
 };

+ 4 - 4
src/goServiceAPI/ermcp/customInfo/index.ts

@@ -1,9 +1,9 @@
 /** ================================= 客户资料 ================================**/
 
-import { commonSearch_go } from '@/goServiceAPI/index';
+import {BaseResponse, commonSearch_go, commonUpdate_go} from '@/goServiceAPI/index';
 import APP from '@/services';
 import * as type from './interface';
-import { QueryCustomInfoType } from './type';
+import { QueryCustomInfoEnum } from './type';
 
 /**
  * 查询客户资料
@@ -11,7 +11,7 @@ import { QueryCustomInfoType } from './type';
  * @param queryType 查询类型(1:未提交 2:待审核 3:正常 4:停用)
  * @returns 
  */
-export function QueryCustomInfo(queryType: QueryCustomInfoType): Promise<type.QueryCustomInfoType[]> {
+export function QueryCustomInfo(queryType: QueryCustomInfoEnum): Promise<type.QueryCustomInfoType[]> {
     const MemberUserID = APP.get('userAccount').memberuserid;
     return commonSearch_go('/Ermcp/QueryUserInfo', { MemberUserID, queryType })
         .catch(err => {
@@ -27,7 +27,7 @@ export function QueryCustomInfo(queryType: QueryCustomInfoType): Promise<type.Qu
  * @constructor
  */
 // export function QueryModifyUserInfo(userInfoApply: type.ModifyUserInfoApplyReq): Promise<BaseResponse> {
-//     return commonUpdate_go('/Ermcp/ModifyUserInfoApply', { userInfoApply })
+//     return commonUpdate_go('/Ermcp/ModifyUserInfoApply',  userInfoApply )
 //         .catch(err => {
 //             throw new Error(`新增客户申请: ${err.message}`);
 //         })

+ 1 - 1
src/goServiceAPI/ermcp/customInfo/type.ts

@@ -1 +1 @@
-export type QueryCustomInfoType = 1 | 2 | 3 | 4;
+export type QueryCustomInfoEnum = 1 | 2 | 3 | 4;

+ 16 - 1
src/goServiceAPI/ermcp/inventory-review/index.ts

@@ -1 +1,16 @@
-/** ================================= 库存审核 ================================**/
+import {commonSearch_go} from "@/goServiceAPI";
+import {Ermcp3AreaStockApply, QueryAreaStockApplyReq} from "@/goServiceAPI/ermcp/inventory-review/interface";
+
+/** ================================= 库存审核 ================================**/
+
+/**
+ * 查询库存申请(出入库记录|库存审核)  /Ermcp3/QueryAreaStockApply
+ * @param req.userid 用户ID(必填)
+ * @constructor
+ */
+export function QueryAreaStock(req: QueryAreaStockApplyReq): Promise<Ermcp3AreaStockApply[]> {
+    return commonSearch_go('/Ermcp3/QueryAreaStockApply', req)
+        .catch(err => {
+            throw new Error(`查询库存申请: ${err.message}`);
+        })
+}

+ 59 - 0
src/goServiceAPI/ermcp/inventory-review/interface.ts

@@ -0,0 +1,59 @@
+// 查询库存请求
+export interface QueryAreaStockApplyReq{
+    userid: number  //    用户ID
+    deliverygoodsid?: number // 现货商品ID
+    inouttype?: string  // 出入库类型(可多项,逗号隔开) 1:采购入库 2:销售出库 3:生产入库 4:生产出库
+    spotcontractid?: number // 合同ID
+    wrstandardid?: number // 品类ID
+    spotgoodsbrandid?: number // 品牌ID
+    warehouseinfoid?: number // 仓库ID
+    applystatus?: string // 申请状态(可多项,逗号隔开)1:待审核 2:审核通过 3:审核拒绝 4:处理失败 5:已撤回
+}
+
+
+// 查询库存返回
+export interface Ermcp3AreaStockApply{
+    applyid	:number;//申请人
+    applyname	:string;//申请人名称
+    applyremark	:string;//申请备注
+    applysrc	:number;//申请来源 - 1:管理端 2:终端
+    applystatus	:number;//申请状态 - 1:待审核 2:审核通过 3:审核拒绝 4:处理失败 5:已撤回
+    applytime	:string;//申请时间
+    auditid	:number;//审核人
+    auditname	:string;//审核人名称
+    auditremark	:string;//审核备注
+    auditsrc	:number;//审核来源 - 1:管理端 2:终端
+    audittime	:string;//审核时间
+    audittradedate	:string;//审核交易日(yyyyMMdd)
+    brandname	:string;//品牌名称
+    buynickname	:string;//采购方昵称
+    buyuserid	:number;//采购方userid
+    buyusername	:string;//采购方名称
+    contractno	:string;//合同编号
+    contractqty	:number;//合同量
+    contracttype	:number;//现货合同类型 - 1:采购 -1:销售
+    deliverygoodscode	:string;//现货品种代码
+    deliverygoodsid	:number;//现货品种id
+    deliverygoodsname	:string;//现货品种名称
+    enumdicname	:string;//现货商品单位名称
+    inoutapplyid	:string;//申请ID(6number;
+//7+Unix秒时间戳(1number;
+//位)+xxxxxx)
+    inouttype	:number;//出入库类型 - 1:采购入库 2:销售出库 3:生产入库 4:生产出库
+    pricetype	:number;//定价类型 - 1:一口价 2:点价 3:暂定价
+    qty	:number;//数量
+    sellnickname	:string;//销售方昵称
+    selluserid	:number;//销售方userid
+    sellusername	:string;//销售方名称
+    spotcontractid	:string;//关联现货合同ID
+    spotgoodsbrandid	:number;//现货品牌ID
+    unitid	:number;//单位id
+    userid	:number;//机构ID
+    warehousecode	:string;//仓库代码
+    warehouseinfoid	:string;//现货仓库ID
+    warehousename	:string;//仓库名称
+    warehousetype	:number;//仓库类型 - 1 厂库 2 自有库 3 合作库
+    wrstandardcode	:string;//品类代码
+    wrstandardid	:number;//品类ID
+    wrstandardname	:string;//品类名称
+}

+ 6 - 6
src/goServiceAPI/ermcp/spot-contract/index.ts

@@ -1,7 +1,6 @@
 /** ================================= 现货合同 ================================**/
-import APP from "@/services";
-import {commonSearch_go} from "@/goServiceAPI";
-import {Ermcp3ContractReq, Ermcp3ContractRsp} from "@/goServiceAPI/ermcp/spot-contract/interface";
+import { commonSearch_go } from "@/goServiceAPI";
+import { Ermcp3ContractReq, Ermcp3ContractRsp } from "@/goServiceAPI/ermcp/spot-contract/interface";
 
 /**
  * 查询现货合同 /Ermcp3/QuerySpotContract
@@ -11,9 +10,10 @@ import {Ermcp3ContractReq, Ermcp3ContractRsp} from "@/goServiceAPI/ermcp/spot-co
  * @param req.contractid 合同ID(SpotContractId) (非必填)
  * @constructor
  */
-export function QuerySpotContract( req : Ermcp3ContractReq) : Promise<Ermcp3ContractRsp[]>{
-    const areauserid = APP.get('userAccount').memberuserid; // 所属机构id
-    return commonSearch_go('/Ermcp3/QuerySpotContract', {areauserid ,  ...req})
+export function QuerySpotContract(req: Ermcp3ContractReq): Promise<Ermcp3ContractRsp[]> {
+    // const areauserid = APP.get('userAccount').memberuserid; // 所属机构id
+    const areauserid = 10000; // 所属机构id
+    return commonSearch_go('/Ermcp3/QuerySpotContract', { areauserid, ...req })
         .catch(err => {
             throw new Error(`查询现货合同: ${err.message}`);
         })

+ 62 - 62
src/goServiceAPI/ermcp/spot-contract/interface.ts

@@ -1,71 +1,71 @@
 /**
  * 现货合同请求
  */
-export interface Ermcp3ContractReq{
-    querytype:  number    //  查询类型 1-未提交 2-待审核 3-履约中 4-已完成
-    userid? :   number    //  用户ID
-    usertype? : number    //  用户类型 2-机构 7-企业成员
-    contractid? : string  //  合同ID(SpotContractId)
+export interface Ermcp3ContractReq {
+    querytype: number    //  查询类型 1-未提交 2-待审核 3-履约中 4-已完成
+    userid?: number    //  用户ID
+    usertype?: number    //  用户类型 2-机构 7-企业成员
+    contractid?: string  //  合同ID(SpotContractId)
 }
 
 /**
  * 现货合同返回
  */
-export interface Ermcp3ContractRsp{
-    accountid	:string;//期货账户id
-    amount	:number;//金额 [1:一口价、3:暂定价]
-    attachment	:string;//附件
-    auditremark	:string;//审核意见
-    audittime	:string;//审核时间
-    biztype	:number;//业务类型 1-套保 2-套利
-    brandname	:string;//品牌名称
-    buynickname	:string;//销售方昵称
-    buyuserid	:number;//采购方ID
-    buyusername	:string;//采购方名称
-    contracctstatus	:number;//合同状态 - number;
-//:未提交 1:待审核 2:执行中 3:正常完结 4:审核拒绝 5:异常完结 6:已撤回
-    contractmargin	:number;//合同保证金
-    contractno	:string;//现货合同编号
-    contracttype	:number;//现货合同类型 - 1:采购 -1:销售
-    convertfactor	:number;//标仓系数(品类)
-    createtime	:string;//创建时间
-    deliveryenddate	:string;//交收期(结束)
-    deliverygoodscode	:string;//现货品种代码
-    deliverygoodsid	:number;//现货品种ID
-    deliverygoodsname	:string;//现货品种名称
-    deliverystartdate	:string;//交收期(开始)
-    enddate	:string;//点价结束日期 [2:点价 3:暂定价]
-    enumdicname	:string;//单位名称
-    goodscode	:string;//点价合约代码
-    goodsid	:number;//点价合约ID - number;
-//:为现货,其它为期货商品合约ID [2:点价 3:暂定价]
-    goodsname	:string;//点价商品名称
-    margin	:number;//当前保证金
-    meruserid	:number;//跟单员id
-    meruserlogincode	:string;//跟单员登录代码
-    price	:number;//价格\暂定价 [1:一口价、3:暂定价]
-    pricemove	:number;//升贴水 [2:点价 3:暂定价]
-    pricetype	:number;//定价类型 - 1:一口价 2:点价 3:暂定价
-    producttype	:number;//产品类型 - 1:标准仓单 2:等标 3:非标
-    qty	:number;//数量
-    remark	:string;//备注
-    saleuserid	:number;//业务员id
-    saleuserlogincode	:string;//业务员登录代码
-    sellnickname	:string;//采购方昵称
-    selluserid	:number;//销售方ID
-    sellusername	:string;//销售方名称
-    spotcontractid	:string;//现货合同ID(6number;
-//2+Unix秒时间戳(1number;
-//位)+xxxxxx)
-    spotgoodsbrandid	:number;//现货品牌ID(DGFactoryItem表的ID)
-    spotgoodsdesc	:string;//商品型号
-    startdate	:string;//点价开始日期 [2:点价 3:暂定价]
-    tradeuserid	:number;//交易员id
-    tradeuserlogincode	:string;//交易员登录代码
-    unitid	:number;//单位id(取品类上的单位id)
-    updatetime	:string;//更新时间
-    userid	:number;//所属机构ID
-    wrstandardcode	:string;//品类代码
-    wrstandardid	:number;//品类ID
-    wrstandardname	:string;//品类名称
+export interface Ermcp3ContractRsp {
+    accountid: string;//期货账户id
+    amount: number;//金额 [1:一口价、3:暂定价]
+    attachment: string;//附件
+    auditremark: string;//审核意见
+    audittime: string;//审核时间
+    biztype: number;//业务类型 1-套保 2-套利
+    brandname: string;//品牌名称
+    buynickname: string;//销售方昵称
+    buyuserid: number;//采购方ID
+    buyusername: string;//采购方名称
+    contracctstatus: number;//合同状态 - number;
+    //:未提交 1:待审核 2:执行中 3:正常完结 4:审核拒绝 5:异常完结 6:已撤回
+    contractmargin: number;//合同保证金
+    contractno: string;//现货合同编号
+    contracttype: number;//现货合同类型 - 1:采购 -1:销售
+    convertfactor: number;//标仓系数(品类)
+    createtime: string;//创建时间
+    deliveryenddate: string;//交收期(结束)
+    deliverygoodscode: string;//现货品种代码
+    deliverygoodsid: number;//现货品种ID
+    deliverygoodsname: string;//现货品种名称
+    deliverystartdate: string;//交收期(开始)
+    enddate: string;//点价结束日期 [2:点价 3:暂定价]
+    enumdicname: string;//单位名称
+    goodscode: string;//点价合约代码
+    goodsid: number;//点价合约ID - number;
+    //:为现货,其它为期货商品合约ID [2:点价 3:暂定价]
+    goodsname: string;//点价商品名称
+    margin: number;//当前保证金
+    meruserid: number;//跟单员id
+    meruserlogincode: string;//跟单员登录代码
+    price: number;//价格\暂定价 [1:一口价、3:暂定价]
+    pricemove: number;//升贴水 [2:点价 3:暂定价]
+    pricetype: number;//定价类型 - 1:一口价 2:点价 3:暂定价
+    producttype: number;//产品类型 - 1:标准仓单 2:等标 3:非标
+    qty: number;//数量
+    remark: string;//备注
+    saleuserid: number;//业务员id
+    saleuserlogincode: string;//业务员登录代码
+    sellnickname: string;//采购方昵称
+    selluserid: number;//销售方ID
+    sellusername: string;//销售方名称
+    spotcontractid: string;//现货合同ID(6number;
+    //2+Unix秒时间戳(1number;
+    //位)+xxxxxx)
+    spotgoodsbrandid: number;//现货品牌ID(DGFactoryItem表的ID)
+    spotgoodsdesc: string;//商品型号
+    startdate: string;//点价开始日期 [2:点价 3:暂定价]
+    tradeuserid: number;//交易员id
+    tradeuserlogincode: string;//交易员登录代码
+    unitid: number;//单位id(取品类上的单位id)
+    updatetime: string;//更新时间
+    userid: number;//所属机构ID
+    wrstandardcode: string;//品类代码
+    wrstandardid: number;//品类ID
+    wrstandardname: string;//品类名称
 }

+ 1 - 2
src/layout/top.vue

@@ -1,7 +1,6 @@
 <template>
   <a-layout class="layout-top">
-    <a-layout-header class="m-layout-header"
-                     @contextmenu.prevent>
+    <a-layout-header class="m-layout-header">
       <div>
         <img src="../assets/images/logoHeader.png" />
         <span>深圳市多元世纪信息技术股份有限公司</span>

+ 0 - 0
src/protoService/accountinfo/index.ts


+ 0 - 0
src/protoService/accountinfo/interface.ts


+ 39 - 0
src/protoService/contract/index.ts

@@ -0,0 +1,39 @@
+import {DeliveryGoodsApplyReq} from "@/protoService/delivery/interface";
+import {buildProtoReq50, parseProtoRsp50} from "@/services/socket/protobuf/buildReq";
+import APP from "@/services";
+import {Callback} from "@/utils/websocket";
+import {ErmcpContractOperateApplyReq} from "@/protoService/contract/interface";
+
+/**
+ * 合同
+ * @param info ContractOperateApplyInfo 操作信息
+ * @param operateType Int 操作类型-1:登记2:确认3:拒绝4:撤销
+ * @param remark String 备注
+ * @param operateApplyID Long 暂时传0 操作申请ID(603+Unix秒时间戳(10位)+xxxxxx)//不知道是啥玩意
+ */
+export const operationContractReq = (param: ErmcpContractOperateApplyReq): Promise<any> => {
+    return new Promise((resolve, reject) => {
+        const params = {
+            protobufName: 'ContractOperateApplyReq',
+            funCodeName: 'ContractOperateApplyReq',
+            reqParams:  param,
+            msgHeadParams: {
+                AccountID: param.accountid,
+                MarketID: 18,
+                GoodsID: 0,
+            }
+        };
+        const package50 = buildProtoReq50(params);
+        APP.sendTradingServer(package50, undefined, {
+            onSuccess: (res) => {
+                const { isSuccess, result } = parseProtoRsp50(res, 'ContractOperateApplyRsp');
+                if (isSuccess) {
+                    resolve(result);
+                } else {
+                    reject(result);
+                }
+            },
+            onFail: (err) => reject(err.message),
+        } as Callback);
+    });
+}

+ 28 - 0
src/protoService/contract/interface.ts

@@ -0,0 +1,28 @@
+// 合同操作请求 0 29 170
+export interface ErmcpContractOperateApplyReq {
+    accountid: number
+    OperateApplyID: number // uint64 操作申请ID(603+Unix秒时间戳(10位)+xxxxxx)
+    OperateType: number // uint32 操作类型-1:登记2:确认3:拒绝4:撤销
+    OperateSrc: number // uint32 操作来源-1:管理端2:终端
+    UserID: number // uint64 操作用户ID
+    Remark: string // string 备注
+    ClientTicket: string  // string 客户端流水号
+    Info : ErmcpContractOperateApplyInfo // ErmcpContractOperateApplyInfo 合同操作信息
+}
+// 合同操作响应 0 29 171
+export interface ErmcpContractOperateApplyRsp {
+    RetCode: number // int32 返回码
+    RetDesc: string // string 描述信息
+    OperateApplyID: number // uint64 操作申请ID(603+Unix秒时间戳(10位)+xxxxxx)
+    OperateType: number // uint32 操作类型-1:登记2:确认3:拒绝4:撤销
+    OperateSrc: number // uint32 操作来源-1:管理端2:终端
+    ClientTicket: string // string 客户端流水号
+}
+
+// 合同操作信息 0 29 169
+export interface ErmcpContractOperateApplyInfo {
+    OperateApplyType: number // uint32 操作申请类型-1:点价2:结算3:款项4:发票
+    RelatedID: number // uint64 现货合同ID(602+Unix秒时间戳(10位)+xxxxxx)
+    DetailJson : Uint8Array // bytes 明细JSON
+    AttachUrl: Uint8Array // bytes 附件
+}

+ 0 - 2
src/protoService/delivery/index.ts

@@ -1,6 +1,4 @@
 import {DeliveryGoodsApplyReq} from "@/protoService/delivery/interface";
-import {getUserId} from "@/services/bus/account";
-import {getUUID} from "@/utils/tool/common";
 import {buildProtoReq50, parseProtoRsp50} from "@/services/socket/protobuf/buildReq";
 import APP from "@/services";
 import {Callback} from "@/utils/websocket";

+ 39 - 0
src/protoService/spotcontract/index.ts

@@ -0,0 +1,39 @@
+import {buildProtoReq50, parseProtoRsp50} from "@/services/socket/protobuf/buildReq";
+import APP from "@/services";
+import {Callback} from "@/utils/websocket";
+import {GldErmcpSpotContractOperateReq} from "@/protoService/spotcontract/interface";
+
+/**(重点提醒 这里属于管理端接口,仅用于新增)以上来自android代码  回头需要确认
+ * 获取新增采购合同报文
+ * @param contractInfo SpotContractInfo 新增合同信息
+ * @param OperateType String 操作类型-1:保存草稿2:提交申请3:审核通过4:审核拒绝5:撤回6:正常完结7:异常终止
+ * @param Remark String 备注
+ * @param SpotContractID String 现货合同ID(602+Unix秒时间戳(10位)+xxxxxx)
+ * @param
+ */
+export const orderContract = (param: GldErmcpSpotContractOperateReq): Promise<any> => {
+    return new Promise((resolve, reject) => {
+        const params = {
+            protobufName: 'GldErmcpSpotContractOperateReq',
+            funCodeName: 'GldErmcpSpotContractOperateReq',
+            reqParams: param,
+            msgHeadParams: {
+                AccountID: param.accountid,
+                MarketID: 18,
+                GoodsID: 0,
+            }
+        };
+        const package50 = buildProtoReq50(params);
+        APP.sendTradingServer(package50, undefined, {
+            onSuccess: (res) => {
+                const { isSuccess, result } = parseProtoRsp50(res, 'GldErmcpSpotContractOperateRsp');
+                if (isSuccess) {
+                    resolve(result);
+                } else {
+                    reject(result);
+                }
+            },
+            onFail: (err) => reject(err.message),
+        } as Callback);
+    });
+}

+ 59 - 0
src/protoService/spotcontract/interface.ts

@@ -0,0 +1,59 @@
+// 现货合同操作请求 0 29 167
+export interface GldErmcpSpotContractOperateReq {
+    accountid: number  // header
+    SpotContractID: number // uint64 现货合同ID(602+Unix秒时间戳(10位)+xxxxxx)
+    OperateType : number // uint32 操作类型-1:保存草稿2:提交申请3:审核通过4:审核拒绝5:撤回6:正常完结7:异常终止
+    OperateSrc : number // uint32 操作来源-1:管理端2:终端
+    UserID: number // uint64 操作用户ID
+    Remark: string // string 操作备注
+    ClientTicket: string // string 客户端流水号
+    Info: GldSpotContractInfo // GldSpotContractInfo 现货合同信息
+}
+// 现货合同操作响应 0 29 168
+export interface GldErmcpSpotContractOperateRsp {
+    RetCode: number // int32 返回码
+    RetDesc: string // string 描述信息
+    SpotContractID: number // uint64 现货合同ID(602+Unix秒时间戳(10位)+xxxxxx)
+    OperateType: number// uint32 操作类型-1:保存草稿2:提交申请3:审核通过4:审核拒绝5:撤回6:正常完结7:异常终止
+    OperateSrc: number // uint32 操作来源-1:管理端2:终端
+    ClientTicket: string // string 客户端流水号
+}
+
+// 现货合同信息 0 29 166
+export interface GldSpotContractInfo {
+    TradeDate: string // string 交易日(yyyyMMdd)
+    ContractNo: string // string 现货合同编号
+    ContractType: number// int32 现货合同类型-1:采购-1:销售
+    UserID :number // uint64 机构ID
+    BuyUserID :number // uint64 采购方ID
+    SellUserID :number // uint64 客户ID
+    SignDate : string // string 签订日期
+    ContractAttachment : Uint8Array // bytes 合同附件
+    ContractMargin : number // double 合同保证金
+    DeliveryGoodsID : number  // uint64 现货品种ID
+    WrStandardID : number  // uint64 现货商品ID
+    ProductType : number  // uint32 产品类型-1:标准仓单2:等标3:非标
+    ConvertFactor : number  // double 标仓系数
+    SpotGoodsDesc : string // string 商品型号
+    PriceType : number // uint32 定价类型-1:一口价2:点价3:暂定价
+    Qty  : number // double 数量
+    Price : number// double 价格暂定价[1:一口价、3:暂定价]
+    Amount : number // double 金额[1:一口价、3:暂定价]
+    DeliveryStartDate : string// string 交收期(开始)
+    DeliveryEndDate: string // string 交收期(结束)
+    GoodsID: number // uint64 点价合约ID-0:为现货,其它为期货商品合约ID[2:点价3:暂定价]
+    PriceMove: number// double 升贴水[2:点价3:暂定价]
+    StartDate: string // string 点价开始日期[2:点价3:暂定价]
+    EndDate: string // string 点价结束日期[2:点价3:暂定价]
+    PointDesc: string // string 点价备注[2:点价3:暂定价]
+    DeliveryDesc: string  // string 交收方式
+    MerUserID: number // uint64 跟单员ID
+    TradeUserID: number // uint64 交易员ID
+    PricedQty: number // double 已定价量
+    PricedAmount: number // double 已定价金额
+    SpotGoodsBrandID: number // uint64 现货品牌ID
+    Remark: string // string 合同备注
+    SaleUserID: number // uint64 业务员ID
+    AccountID: number // uint64 期货账户ID
+    BizType: number // uint32 业务类型 - 1:套保 2:套利
+}

+ 8 - 0
src/setup/controlModal/interface.ts

@@ -3,5 +3,13 @@ export interface ModalName {
     notice: string; // 消息
     logout: string; // 退出登录
     drawer: string; // 下单通用界面
+
     addCustomInfo: string; // 新增客户资料
+    modifyCustomInfo: string; // 修改客户资料
+    disableCustomInfo: string; // 停用客户资料
+    deleteCustomInfo: string; // 删除客户资料
+    recoverCustomInfo: string; // 恢复客户资料
+    customDetail: string; // 客户资料详情
+
+    addSpotContract: string; // 新增现货合同
 }

+ 2 - 1
src/setup/router/index.ts

@@ -1,6 +1,6 @@
 import { OperationTabMenu } from '@/goServiceAPI/commonService/interface';
 import APP from '@/services';
-import { ref, unref } from 'vue';
+import { provide, ref, unref } from 'vue';
 import { Router, useRouter } from 'vue-router';
 
 // 处理 动态路由
@@ -38,5 +38,6 @@ export function handleRouterMenu() {
 
         router.push({ name: item.code });
     }
+    provide('thirdMenuList', list)
     return { list, selectMenu, getMenuList };
 }

+ 47 - 0
src/views/information/custom/compoments/customDetail/index.vue

@@ -0,0 +1,47 @@
+<template>
+  <!-- 客户资料详情-->
+  <a-modal class="custom-detail"
+           title="客户资料详情"
+           v-model:visible="visible"
+           @cancel="cancel"
+           width="890px">
+    <template #footer>
+      <a-button key="submit"
+                type="primary"
+                :loading="loading"
+                @click="submit">完成</a-button>
+    </template>
+  </a-modal>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue';
+import { closeModal } from '@/setup/controlModal/index';
+
+export default defineComponent({
+    name: 'custom-detail',
+    components: {},
+    setup() {
+        const { visible, cancel } = closeModal('customDetail');
+        const loading = ref<boolean>(false);
+        function submit() {
+            loading.value = true;
+            setTimeout(() => {
+                loading.value = false;
+                cancel();
+            }, 2000);
+        }
+        return {
+            visible,
+            cancel,
+            submit,
+            loading,
+        };
+    },
+});
+</script>
+
+<style lang="less">
+.custom-detail {
+}
+</style>;

+ 47 - 0
src/views/information/custom/compoments/deleteCustom/index.vue

@@ -0,0 +1,47 @@
+<template>
+  <!-- 恢复客户资料-->
+  <a-modal class="recover-custom"
+           title="恢复客户资料"
+           v-model:visible="visible"
+           @cancel="cancel"
+           width="890px">
+    <template #footer>
+      <a-button key="submit"
+                type="primary"
+                :loading="loading"
+                @click="submit">完成</a-button>
+    </template>
+  </a-modal>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue';
+import { closeModal } from '@/setup/controlModal/index';
+
+export default defineComponent({
+    name: 'recover-custom',
+    components: {},
+    setup() {
+        const { visible, cancel } = closeModal('deleteCustomInfo');
+        const loading = ref<boolean>(false);
+        function submit() {
+            loading.value = true;
+            setTimeout(() => {
+                loading.value = false;
+                cancel();
+            }, 2000);
+        }
+        return {
+            visible,
+            cancel,
+            submit,
+            loading,
+        };
+    },
+});
+</script>
+
+<style lang="less">
+.recover-custom {
+}
+</style>;

+ 47 - 0
src/views/information/custom/compoments/disableCustom/index.vue

@@ -0,0 +1,47 @@
+<template>
+  <!-- 停用客户资料-->
+  <a-modal class="custom-disable"
+           title="停用客户资料"
+           v-model:visible="visible"
+           @cancel="cancel"
+           width="890px">
+    <template #footer>
+      <a-button key="submit"
+                type="primary"
+                :loading="loading"
+                @click="submit">完成</a-button>
+    </template>
+  </a-modal>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue';
+import { closeModal } from '@/setup/controlModal/index';
+
+export default defineComponent({
+    name: 'custom-disable',
+    components: {},
+    setup() {
+        const { visible, cancel } = closeModal('disableCustomInfo');
+        const loading = ref<boolean>(false);
+        function submit() {
+            loading.value = true;
+            setTimeout(() => {
+                loading.value = false;
+                cancel();
+            }, 2000);
+        }
+        return {
+            visible,
+            cancel,
+            submit,
+            loading,
+        };
+    },
+});
+</script>
+
+<style lang="less">
+.custom-disable {
+}
+</style>;

+ 16 - 25
src/views/information/custom/compoments/filterTable/index.vue

@@ -6,8 +6,7 @@
               style="width: 120px"
               v-model:value="userinfotype"
               placeholder="全部客户类型"
-              @change="handleChange"
-            >
+              @change="handleChange">
       <a-select-option value="1">个人</a-select-option>
       <a-select-option value="2">企业</a-select-option>
     </a-select>
@@ -20,18 +19,16 @@
     <a-input v-model:value="phone"
              class="tableConditionInput"
              placeholder="模糊搜索手机号码" />
-    <a-button class="selectBtn"  @click="search">查询</a-button>
-    <a-button class="selectBtn"  @click="reset">重置</a-button>
-    <a-button class="operBtn" @click="add">新增</a-button>
-    <!-- 新增弹窗 -->
-    <AddCustom />
+    <a-button class="selectBtn"
+              @click="search">查询</a-button>
+    <a-button class="selectBtn"
+              @click="reset">重置</a-button>
+    <slot></slot>
   </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, ref, SetupContext } from 'vue';
-import AddCustom from '../addCustom/index.vue';
-import { openModal } from '@/setup/controlModal/index';
 
 // 搜索
 function handleSearch(context: SetupContext) {
@@ -66,18 +63,10 @@ function handleSearch(context: SetupContext) {
 
 export default defineComponent({
     name: 'filter-custom-table',
-    components: {
-        AddCustom,
-    },
+    components: {},
     setup(props, context) {
-        const { openAction } = openModal('addCustomInfo');
-        function add() {
-            openAction();
-            context.emit('add');
-        }
         return {
             ...handleSearch(context),
-            add,
         };
     },
 });
@@ -94,7 +83,7 @@ export default defineComponent({
     margin-right: 10px;
     // background: #252D34;
     // .rounded-corners(3px);
-    .ant-select-selector{
+    .ant-select-selector {
         height: 30px;
         padding: 0 8px;
         background: @m-grey9;
@@ -110,10 +99,10 @@ export default defineComponent({
         color: @m-grey1;
     }
     .ant-select-selection-item {
-         color: @m-white1;
+        color: @m-white1;
     }
 }
-.conditionSelect+.conditionSelect {
+.conditionSelect + .conditionSelect {
     margin-left: 10px;
 }
 .selectBtn.ant-btn {
@@ -127,17 +116,19 @@ export default defineComponent({
     color: @m-white0;
     font-size: 14px;
     .rounded-corners(3px);
-    &:hover,&:focus {
+    &:hover,
+    &:focus {
         background: linear-gradient(0deg, @m-grey15-hover 0%, @m-grey16-hover 98%);
-        color: rgba(@m-white0, .8);
+        color: rgba(@m-white0, 0.8);
         border: 0;
     }
 }
 .operBtn.ant-btn:extend(.selectBtn.ant-btn) {
     background: linear-gradient(0deg, @m-blue6 0%, @m-blue7 99%);
-    &:hover,&:focus {
+    &:hover,
+    &:focus {
         background: linear-gradient(0deg, @m-blue6-hover 0%, @m-blue7-hover 99%);
-        color: rgba(@m-white0, .8);
+        color: rgba(@m-white0, 0.8);
         border: 0;
     }
 }

+ 47 - 0
src/views/information/custom/compoments/modifyCustom/index.vue

@@ -0,0 +1,47 @@
+<template>
+  <!-- 修改客户资料-->
+  <a-modal class="modify-custom"
+           title="修改客户资料"
+           v-model:visible="visible"
+           @cancel="cancel"
+           width="890px">
+    <template #footer>
+      <a-button key="submit"
+                type="primary"
+                :loading="loading"
+                @click="submit">完成</a-button>
+    </template>
+  </a-modal>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue';
+import { closeModal } from '@/setup/controlModal/index';
+
+export default defineComponent({
+    name: 'modify-custom',
+    components: {},
+    setup() {
+        const { visible, cancel } = closeModal('modifyCustomInfo');
+        const loading = ref<boolean>(false);
+        function submit() {
+            loading.value = true;
+            setTimeout(() => {
+                loading.value = false;
+                cancel();
+            }, 2000);
+        }
+        return {
+            visible,
+            cancel,
+            submit,
+            loading,
+        };
+    },
+});
+</script>
+
+<style lang="less">
+.modify-custom {
+}
+</style>;

+ 47 - 0
src/views/information/custom/compoments/recover/index.vue

@@ -0,0 +1,47 @@
+<template>
+  <!-- 修改客户资料-->
+  <a-modal class="modify-custom"
+           title="修改客户资料"
+           v-model:visible="visible"
+           @cancel="cancel"
+           width="890px">
+    <template #footer>
+      <a-button key="submit"
+                type="primary"
+                :loading="loading"
+                @click="submit">完成</a-button>
+    </template>
+  </a-modal>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue';
+import { closeModal } from '@/setup/controlModal/index';
+
+export default defineComponent({
+    name: 'modify-custom',
+    components: {},
+    setup() {
+        const { visible, cancel } = closeModal('recoverCustomInfo');
+        const loading = ref<boolean>(false);
+        function submit() {
+            loading.value = true;
+            setTimeout(() => {
+                loading.value = false;
+                cancel();
+            }, 2000);
+        }
+        return {
+            visible,
+            cancel,
+            submit,
+            loading,
+        };
+    },
+});
+</script>
+
+<style lang="less">
+.modify-custom {
+}
+</style>;

+ 1 - 1
src/views/information/custom/index.vue

@@ -9,7 +9,7 @@
 </template>
 
 <script lang="ts">
-import { defineComponent, ref } from 'vue';
+import { defineComponent } from 'vue';
 import firstMenu from '@/components/firstMenu/index.vue';
 import { initData } from '@/setup/methods/index';
 import { handleRouterMenu } from '@/setup/router/index';

+ 72 - 97
src/views/information/custom/list/normal-use/index.vue

@@ -2,124 +2,99 @@
   <!-- 客户信息: 正常 -->
   <div class="custom-normal"
        :loading="loading">
-    <filterCustomTable @add="add"
-                       @search="search" />
-    <a-table class="topTable"
-             :columns="columns"
-             :pagination="false"
-             rowKey="key"
-             :data-source="customList"
-             :bordered="true">
-      <template #userinfotype="{ text }">
-        <a>{{ text === '2' ? '企业' : '个人'}}</a>
-      </template>
-    </a-table>
+    <filterCustomTable @search="search">
+      <a-button class="operBtn"
+                v-if="hasPermission('custom_info_btn_add')"
+                @click="openAction">新增</a-button>
+    </filterCustomTable>
+    <contextMenu :contextMenuList="contextMenuList"
+                 :tableList="customList">
+      <a-table :columns="columns"
+               class="topTable"
+               :pagination="false"
+               rowKey="key"
+               :data-source="customList">
+        <template #userinfotype="{ text }">
+          <a>{{ text === '2' ? '企业' : '个人'}}</a>
+        </template>
+      </a-table>
+    </contextMenu>
+    <!-- 详情 -->
+    <CustomDetail />
+    <!-- 修改 -->
+    <ModifyCustom />
+    <!-- 停用 -->
+    <DisableCustom />
   </div>
 </template>
 
 <script lang="ts">
-import { defineComponent, Ref, ref } from 'vue';
+import { defineComponent, onUnmounted, Ref, ref, watchEffect } from 'vue';
 
 import { initData } from '@/setup/methods/index';
-import { QueryCustomInfo } from '@/goServiceAPI/ermcp/customInfo/index';
-import { QueryCustomInfoType } from '@/goServiceAPI/ermcp/customInfo/interface';
 import filterCustomTable from '@/views/information/custom/compoments/filterTable/index.vue';
-import { getTableHead, ColumnType } from '@/services/bus/table';
-import { message } from 'ant-design-vue';
-import { useRouter } from 'vue-router';
+import { MenuItem } from '@/components/contextMenu/interface';
+import contextMenu from '@/components/contextMenu/index.vue';
+import { getCustomList } from '../setup';
+import { openModal } from '@/setup/controlModal/index';
+import CustomDetail from '@/views/information/custom/compoments/customDetail/index.vue';
+import ModifyCustom from '@/views/information/custom/compoments/modifyCustom/index.vue';
+import DisableCustom from '@/views/information/custom/compoments/disableCustom/index.vue';
 
-// 查询客户资料列表
-function getCustomList() {
-    const router = useRouter();
-    const pathArr = router.currentRoute.value.fullPath.split('/');
-    console.log('pathArr', pathArr);
-
-    // 表格数据
-    const customList = ref<QueryCustomInfoType[]>([]);
-    // 表头数据
-    const columns = ref<ColumnType[]>([]);
-    // 过滤项
-    const filteredInfo = ref();
-    const loading = ref<boolean>(false);
-    // 获取表头
-    function getColumns() {
-        const list = getTableHead('table_pcweb_userinfo');
-        const filtered = filteredInfo.value || {};
-        columns.value.length = 0;
-        list.forEach((e, i) => {
-            const { columnfield, columntitle, aligntype } = e;
-            const item: ColumnType = {
-                key: String(i),
-                dataIndex: columnfield, // 表格数据对应的key
-                title: columntitle,
-                align: aligntype === 1 ? 'center' : aligntype === 2 ? 'left' : 'right',
-                slots: { customRender: columnfield },
-            };
-            // 以下添加过滤数据对应的方法
-            if (e.columntitle === '客户类型') {
-                item.onFilter = (value: string, record: QueryCustomInfoType) => record.userinfotype.includes(String(value));
-                item.filteredValue = filtered.userinfotype || null;
-            }
-            if (e.columntitle === '客户简称') {
-                item.onFilter = (value: string, record: QueryCustomInfoType) => record.nickname.includes(value);
-                item.filteredValue = filtered.nickname || null;
-            }
-            if (e.columntitle === '客户名称') {
-                item.onFilter = (value: string, record: QueryCustomInfoType) => record.contactname.includes(value);
-                item.filteredValue = filtered.contactname || null;
-            }
-            if (e.columntitle === '手机号码') {
-                item.onFilter = (value: string, record: QueryCustomInfoType) => record.mobile.includes(value);
-                item.filteredValue = filtered.mobile || null;
-            }
-            columns.value.push(item);
-        });
-        console.log('columns', columns);
-    }
-    // 查询列表
-    function actionQuery() {
-        loading.value = true;
-        QueryCustomInfo(3)
-            .then((res) => {
-                customList.value = res.map((e, i) => {
-                    return { ...e, key: String(i) };
-                });
-                loading.value = false;
-                console.log('查询列表', customList);
-            })
-            .catch((err) => {
-                message.error(err);
-                loading.value = false;
-            });
-    }
-    // 查询
-    function search(value: any) {
-        filteredInfo.value = value;
-        getColumns();
-        console.log('search', value);
+// 处理详情
+function handleDetail(contextMenuList: Ref<MenuItem[]>) {
+    const { openAction } = openModal('customDetail');
+    contextMenuList.value.push({ lable: '详情', callback: openAction });
+}
+// 处理修改
+function handleModify(contextMenuList: Ref<MenuItem[]>) {
+    const { openAction } = openModal('modifyCustomInfo');
+    function modifyAction() {
+        contextMenuList.value.push({ lable: '修改', callback: openAction });
     }
-    return { customList, actionQuery, columns, filteredInfo, getColumns, search, loading };
+    return { modifyAction };
 }
 
-// 处理新增资料
-
-function add() {
-    console.log('add');
+// 处理停用
+function handleDisable(contextMenuList: Ref<MenuItem[]>) {
+    const { openAction } = openModal('disableCustomInfo');
+    function disableAction() {
+        contextMenuList.value.push({ lable: '停用', callback: openAction });
+    }
+    return { disableAction };
 }
-
 export default defineComponent({
     name: 'custom-normal',
     components: {
         filterCustomTable,
+        contextMenu,
+        CustomDetail,
+        ModifyCustom,
+        DisableCustom,
     },
     setup() {
-        const { customList, actionQuery, columns, getColumns, search, loading } = getCustomList();
+        const { customList, actionQuery, columns, getColumns, search, loading, handlePermission } = getCustomList();
+        const { hasPermission } = handlePermission('custom_info_normal');
+        const contextMenuList = ref<MenuItem[]>([]);
+
+        const { openAction } = openModal('addCustomInfo');
+
+        handleDetail(contextMenuList);
+        const { modifyAction } = handleModify(contextMenuList);
+        const { disableAction } = handleDisable(contextMenuList);
+
+        const stop = watchEffect(() => {
+            hasPermission('custom_info_btn_modify') && modifyAction();
+            hasPermission('custom_info_btn_disable') && disableAction();
+        });
+        onUnmounted(() => {
+            stop();
+        });
         initData(() => {
-            actionQuery();
+            actionQuery(3);
             getColumns();
-            // 加载数据在这里
         });
-        return { customList, columns, search, loading, add };
+        return { customList, columns, search, loading, contextMenuList, hasPermission, openAction };
     },
 });
 </script>

+ 95 - 0
src/views/information/custom/list/setup.ts

@@ -0,0 +1,95 @@
+import { OperationTabMenu } from '@/goServiceAPI/commonService/interface';
+import { QueryCustomInfo } from '@/goServiceAPI/ermcp/customInfo';
+import { QueryCustomInfoType } from '@/goServiceAPI/ermcp/customInfo/interface';
+import { QueryCustomInfoEnum } from '@/goServiceAPI/ermcp/customInfo/type';
+import { ColumnType, getTableHead } from '@/services/bus/table';
+import { message } from 'ant-design-vue';
+import { inject, Ref, ref } from 'vue';
+
+// 客户资料列表
+export function getCustomList() {
+    // 表格数据
+    const customList = ref<QueryCustomInfoType[]>([]);
+    // 表头数据
+    const columns = ref<ColumnType[]>([]);
+    // 过滤项
+    const filteredInfo = ref();
+    const loading = ref<boolean>(false);
+    const permissionData = inject('thirdMenuList') as Ref<OperationTabMenu[]>
+    // 获取表头
+    function getColumns() {
+        const list = getTableHead('table_pcweb_userinfo');
+        const filtered = filteredInfo.value || {};
+        columns.value.length = 0;
+        list.forEach((e, i) => {
+            const { columnfield, columntitle, aligntype } = e;
+            const item: ColumnType = {
+                key: String(i),
+                dataIndex: columnfield, // 表格数据对应的key
+                title: columntitle,
+                align: aligntype === 1 ? 'center' : aligntype === 2 ? 'left' : 'right',
+                slots: { customRender: columnfield },
+            };
+            // 以下添加过滤数据对应的方法
+            if (e.columntitle === '客户类型') {
+                item.onFilter = (value: string, record: QueryCustomInfoType) => record.userinfotype.includes(String(value));
+                item.filteredValue = filtered.userinfotype || null;
+            }
+            if (e.columntitle === '客户简称') {
+                item.onFilter = (value: string, record: QueryCustomInfoType) => record.nickname.includes(value);
+                item.filteredValue = filtered.nickname || null;
+            }
+            if (e.columntitle === '客户名称') {
+                item.onFilter = (value: string, record: QueryCustomInfoType) => record.contactname.includes(value);
+                item.filteredValue = filtered.contactname || null;
+            }
+            if (e.columntitle === '手机号码') {
+                item.onFilter = (value: string, record: QueryCustomInfoType) => record.mobile.includes(value);
+                item.filteredValue = filtered.mobile || null;
+            }
+            columns.value.push(item);
+        });
+    }
+    // 查询列表
+    function actionQuery(type: QueryCustomInfoEnum) {
+        loading.value = true;
+        QueryCustomInfo(type)
+            .then((res) => {
+                customList.value = res.map((e, i) => {
+                    return { ...e, key: String(i) };
+                });
+                loading.value = false;
+                console.log('查询列表', customList);
+            })
+            .catch((err) => {
+                message.error(err);
+                loading.value = false;
+            });
+    }
+    // 查询
+    function search(value: any) {
+        filteredInfo.value = value;
+        getColumns();
+    }
+
+    // 处理按钮是否有权限
+    type customType = 'custom_info_normal' | 'custom_info_disabled' // 正常 | 停用
+    function handlePermission(menuType: customType) {
+        // 添加 | 修改 | 停用 | "恢复" | "删除"
+        type codeType = 'custom_info_btn_add' | 'custom_info_btn_modify' | 'custom_info_btn_disable' | "custom_info_btn_recover" | "custom_info_btn_delete";
+
+        // 判断按钮是否有权限
+        function hasPermission(type: codeType): boolean {
+            let result = false;
+            if (permissionData) {
+                const btnList = permissionData.value.find((e) => e.code === menuType);
+                if (btnList && btnList.children) {
+                    result = btnList.children.find((e) => e.code === type && e.type === 2) ? true : false;
+                }
+            }
+            return result;
+        }
+        return { hasPermission };
+    }
+    return { customList, actionQuery, columns, filteredInfo, getColumns, search, loading, handlePermission };
+}

+ 84 - 61
src/views/information/custom/list/stop-use/index.vue

@@ -1,83 +1,106 @@
 <template>
   <!-- 客户信息: 停用 -->
-  <div class="custom-stop">
-    客户信息: 停用
+  <div class="custom-normal"
+       :loading="loading">
+    <filterCustomTable @search="search">
+      <a-button class="operBtn"
+                v-if="hasPermission('custom_info_btn_add')"
+                @click="openAction">新增</a-button>
+    </filterCustomTable>
+    <contextMenu :contextMenuList="contextMenuList"
+                 :tableList="customList">
+      <a-table :columns="columns"
+               class="topTable"
+               :pagination="false"
+               rowKey="key"
+               :data-source="customList">
+        <template #userinfotype="{ text }">
+          <a>{{ text === '2' ? '企业' : '个人'}}</a>
+        </template>
+      </a-table>
+    </contextMenu>
+    <!-- 详情 -->
+    <CustomDetail />
+    <!-- 删除 -->
+    <DeleteCustom />
+    <!-- 恢复客户资料 -->
+    <RecoverCustom />
+
   </div>
 </template>
 
 <script lang="ts">
-import { defineComponent, ref } from 'vue';
-import { QueryCustomInfo } from '@/goServiceAPI/ermcp/customInfo/index';
-import { QueryCustomInfoType } from '@/goServiceAPI/ermcp/customInfo/interface';
-import { message } from 'ant-design-vue';
+import { defineComponent, onUnmounted, Ref, ref, watchEffect } from 'vue';
+
 import { initData } from '@/setup/methods/index';
+import filterCustomTable from '@/views/information/custom/compoments/filterTable/index.vue';
+import { MenuItem } from '@/components/contextMenu/interface';
+import contextMenu from '@/components/contextMenu/index.vue';
+import { getCustomList } from '../setup';
+import { openModal } from '@/setup/controlModal/index';
+import CustomDetail from '@/views/information/custom/compoments/customDetail/index.vue';
+import DeleteCustom from '@/views/information/custom/compoments/deleteCustom/index.vue';
+import RecoverCustom from '@/views/information/custom/compoments/recover/index.vue';
 
-// 查询客户资料列表
-function getCustomList() {
-    // const filteredInfo = ref();
-    // const sortedInfo = ref();
-    // const columns = computed(() => {
-    //     const filtered = filteredInfo.value || {};
-    //     const sorted = sortedInfo.value || {};
-    //     return [
-    //         {
-    //             title: '序号',
-    //             dataIndex: 'index',
-    //             key: 'index',
-    //             align: 'center',
-    //             width: 50,
-    //             customRender: (param: any) => `${param.index + 1}`,
-    //         },
-    //         {
-    //             title: 'Age',
-    //             dataIndex: 'age',
-    //             key: 'age',
-    //             sorter: (a: DataItem, b: DataItem) => a.age - b.age,
-    //             sortOrder: sorted.columnKey === 'age' && sorted.order,
-    //         },
-    //         {
-    //             title: 'Address',
-    //             dataIndex: 'address',
-    //             key: 'address',
-    //             filters: [
-    //                 { text: 'London', value: 'London' },
-    //                 { text: 'New York', value: 'New York' },
-    //             ],
-    //             filteredValue: filtered.address || null,
-    //             onFilter: (value: string, record: DataItem) => record.address.includes(value),
-    //             sorter: (a: DataItem, b: DataItem) => a.address.length - b.address.length,
-    //             sortOrder: sorted.columnKey === 'address' && sorted.order,
-    //             ellipsis: true,
-    //         },
-    //     ];
-    // });
-    const customList = ref<QueryCustomInfoType[]>([]);
-    function actionQuery() {
-        QueryCustomInfo(4)
-            .then((res) => {
-                console.log('L', res);
-            })
-            .catch((err) => message.error(err));
+// 处理详情
+function handleDetail(contextMenuList: Ref<MenuItem[]>) {
+    const { openAction } = openModal('customDetail');
+    contextMenuList.value.push({ lable: '详情', callback: openAction });
+}
+// 处理删除
+function handleDelete(contextMenuList: Ref<MenuItem[]>) {
+    const { openAction } = openModal('deleteCustomInfo');
+    function deleteAction() {
+        contextMenuList.value.push({ lable: '删除', callback: openAction });
     }
-
-    return { customList, actionQuery };
+    return { deleteAction };
+}
+// 处理恢复
+function handleRecover(contextMenuList: Ref<MenuItem[]>) {
+    const { openAction } = openModal('recoverCustomInfo');
+    function recoverAction() {
+        contextMenuList.value.push({ lable: '删除', callback: openAction });
+    }
+    return { recoverAction };
 }
 
 export default defineComponent({
-    name: 'custom-stop',
-    components: {},
+    name: 'custom-normal',
+    components: {
+        filterCustomTable,
+        contextMenu,
+        CustomDetail,
+        DeleteCustom,
+        RecoverCustom,
+    },
     setup() {
-        const { customList, actionQuery } = getCustomList();
+        const { customList, actionQuery, columns, getColumns, search, loading, handlePermission } = getCustomList();
+        const { hasPermission } = handlePermission('custom_info_normal');
+        const contextMenuList = ref<MenuItem[]>([]);
+
+        const { openAction } = openModal('addCustomInfo');
+
+        handleDetail(contextMenuList);
+        const { deleteAction } = handleDelete(contextMenuList);
+        const { recoverAction } = handleRecover(contextMenuList);
+
+        const stop = watchEffect(() => {
+            hasPermission('custom_info_btn_recover') && recoverAction();
+            hasPermission('custom_info_btn_delete') && deleteAction();
+        });
+        onUnmounted(() => {
+            stop();
+        });
         initData(() => {
-            actionQuery();
-            // 加载数据在这里
+            actionQuery(4);
+            getColumns();
         });
-        return { customList };
+        return { customList, columns, search, loading, contextMenuList, hasPermission, openAction };
     },
 });
 </script>
 
 <style lang="less">
-.custom-stop {
+.custom-normal {
 }
 </style>;

+ 49 - 0
src/views/information/spot-contract/components/add/index.vue

@@ -0,0 +1,49 @@
+<template>
+  <!-- 新增客户资料 -->
+  <a-modal class="add-spot-contract"
+           title="新增现货合同"
+           v-model:visible="visible"
+           @cancel="cancel"
+           width="890px">
+    <template #footer>
+      <a-button key="submit"
+                type="primary"
+                :loading="loading"
+                @click="submit">完成</a-button>
+    </template>
+  </a-modal>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref } from 'vue';
+import { closeModal } from '@/setup/controlModal/index';
+import { initData } from '@/setup/methods/index';
+
+export default defineComponent({
+    name: 'add-spot-contract',
+    components: {},
+    setup() {
+        const { visible, cancel } = closeModal('addSpotContract');
+        const loading = ref<boolean>(false);
+        function submit() {
+            loading.value = true;
+            setTimeout(() => {
+                loading.value = false;
+                cancel();
+            }, 2000);
+        }
+        initData(() => {});
+        return {
+            visible,
+            cancel,
+            submit,
+            loading,
+        };
+    },
+});
+</script>
+
+<style lang="less">
+.add-spot-contract {
+}
+</style>;

+ 154 - 0
src/views/information/spot-contract/components/filterTable/index.vue

@@ -0,0 +1,154 @@
+<template>
+  <!-- 过滤客户资料表格 -->
+  <div class="filter-custom-table">
+    <a-select label-in-value
+              class="conditionSelect"
+              style="width: 120px"
+              v-model:value="contracttype"
+              placeholder="全部合同类型"
+              @change="handleChange">
+      <a-select-option value="1">采购</a-select-option>
+      <a-select-option value="-1">销售</a-select-option>
+    </a-select>
+    <a-select label-in-value
+              class="conditionSelect"
+              style="width: 120px"
+              v-model:value="pricetype"
+              placeholder="全部定价类型"
+              @change="handlePricetype">
+      <a-select-option value="1">一口价</a-select-option>
+      <a-select-option value="2">点价</a-select-option>
+      <a-select-option value="3">暂定价</a-select-option>
+    </a-select>
+    <a-input v-model:value="contractno"
+             class="tableConditionInput"
+             placeholder="模糊搜索合同编号" />
+    <a-input v-model:value="negative"
+             class="tableConditionInput"
+             placeholder="模糊搜索对手方" />
+    <a-button class="selectBtn"
+              @click="search">查询</a-button>
+    <a-button class="selectBtn"
+              @click="reset">重置</a-button>
+    <slot></slot>
+
+    <!-- 新增弹窗 -->
+
+  </div>
+</template>
+
+<script lang="ts">
+import { defineComponent, ref, SetupContext } from 'vue';
+
+// 搜索
+function handleSearch(context: SetupContext) {
+    const contractno = ref<string>('');
+    const negative = ref<string>('');
+    interface Value {
+        key: string;
+        value: string;
+    }
+    // 全部合同类型
+    let useType = '';
+    const contracttype = ref<number>(0);
+    function handleChange(value: Value) {
+        useType = value.value;
+        search();
+    }
+    // 全部定价类型
+    const pricetype = ref<number>(0);
+    let cachePricetype = '';
+    function handlePricetype(value: Value) {
+        cachePricetype = value.value;
+        search();
+    }
+    function search() {
+        const result = { contractno: [contractno.value], negative: [negative.value], contracttype: [useType], pricetype: [cachePricetype] };
+        context.emit('search', result);
+    }
+    function reset() {
+        contractno.value = '';
+        negative.value = '';
+
+        contracttype.value = 0;
+        useType = '';
+        pricetype.value = 0;
+        cachePricetype = '';
+        search();
+    }
+
+    return { contractno, negative, search, reset, contracttype, handleChange, pricetype, handlePricetype };
+}
+
+export default defineComponent({
+    name: 'filter-spot-contract-table',
+    components: {},
+    setup(props, context) {
+        return {
+            ...handleSearch(context),
+        };
+    },
+});
+</script>
+
+<style lang="less">
+.filter-custom-table {
+    width: 100%;
+    display: inline-flex;
+    padding-top: 9px;
+    padding-bottom: 6px;
+}
+.ant-select-single:not(.ant-select-customize-input) {
+    margin-right: 10px;
+    // background: #252D34;
+    // .rounded-corners(3px);
+    .ant-select-selector {
+        height: 30px;
+        padding: 0 8px;
+        background: @m-grey9;
+        border: none;
+        .rounded-corners(3px);
+        color: @m-grey10;
+        .ant-select-arrow {
+            right: 8px;
+            color: @m-grey1;
+        }
+    }
+    .ant-select-arrow {
+        color: @m-grey1;
+    }
+    .ant-select-selection-item {
+        color: @m-white1;
+    }
+}
+.conditionSelect + .conditionSelect {
+    margin-left: 10px;
+}
+.selectBtn.ant-btn {
+    margin-left: 10px;
+    width: 80px;
+    height: 30px;
+    line-height: 30px;
+    text-align: center;
+    background: linear-gradient(0deg, @m-grey15 0%, @m-grey16 98%);
+    border: 0;
+    color: @m-white0;
+    font-size: 14px;
+    .rounded-corners(3px);
+    &:hover,
+    &:focus {
+        background: linear-gradient(0deg, @m-grey15-hover 0%, @m-grey16-hover 98%);
+        color: rgba(@m-white0, 0.8);
+        border: 0;
+    }
+}
+.operBtn.ant-btn:extend(.selectBtn.ant-btn) {
+    background: linear-gradient(0deg, @m-blue6 0%, @m-blue7 99%);
+    &:hover,
+    &:focus {
+        background: linear-gradient(0deg, @m-blue6-hover 0%, @m-blue7-hover 99%);
+        color: rgba(@m-white0, 0.8);
+        border: 0;
+    }
+}
+</style>;

+ 37 - 60
src/views/information/spot-contract/list/not-commit/index.vue

@@ -1,78 +1,55 @@
 <template>
   <!-- 现货合同: 未提交-->
   <div class="spot-contract-not-commit">
-    现货合同: 未提交
+    <filterCustomTable @search="search">
+      <a-button class="operBtn"
+                v-if="hasPermission('spot_contract_btn_add')"
+                @click="openAction">新增</a-button>
+    </filterCustomTable>
+    <contextMenu :contextMenuList="contextMenuList"
+                 :tableList="spotContractList">
+      <a-table :columns="columns"
+               class="topTable"
+               :pagination="false"
+               rowKey="key"
+               :data-source="spotContractList">
+        <!-- <template #userinfotype="{ text }">
+          <a>{{ text === '2' ? '企业' : '个人'}}</a>
+        </template> -->
+      </a-table>
+    </contextMenu>
+    <!-- 新增现货合同 -->
+    <AddSpotContract />
   </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, ref } from 'vue';
-import { QueryCustomInfo } from '@/goServiceAPI/ermcp/customInfo/index';
-import { QueryCustomInfoType } from '@/goServiceAPI/ermcp/customInfo/interface';
-import { message } from 'ant-design-vue';
 import { initData } from '@/setup/methods/index';
-
-// 查询客户资料列表
-function getCustomList() {
-    // const filteredInfo = ref();
-    // const sortedInfo = ref();
-    // const columns = computed(() => {
-    //     const filtered = filteredInfo.value || {};
-    //     const sorted = sortedInfo.value || {};
-    //     return [
-    //         {
-    //             title: '序号',
-    //             dataIndex: 'index',
-    //             key: 'index',
-    //             align: 'center',
-    //             width: 50,
-    //             customRender: (param: any) => `${param.index + 1}`,
-    //         },
-    //         {
-    //             title: 'Age',
-    //             dataIndex: 'age',
-    //             key: 'age',
-    //             sorter: (a: DataItem, b: DataItem) => a.age - b.age,
-    //             sortOrder: sorted.columnKey === 'age' && sorted.order,
-    //         },
-    //         {
-    //             title: 'Address',
-    //             dataIndex: 'address',
-    //             key: 'address',
-    //             filters: [
-    //                 { text: 'London', value: 'London' },
-    //                 { text: 'New York', value: 'New York' },
-    //             ],
-    //             filteredValue: filtered.address || null,
-    //             onFilter: (value: string, record: DataItem) => record.address.includes(value),
-    //             sorter: (a: DataItem, b: DataItem) => a.address.length - b.address.length,
-    //             sortOrder: sorted.columnKey === 'address' && sorted.order,
-    //             ellipsis: true,
-    //         },
-    //     ];
-    // });
-    const customList = ref<QueryCustomInfoType[]>([]);
-    function actionQuery() {
-        QueryCustomInfo(4)
-            .then((res) => {
-                console.log('L', res);
-            })
-            .catch((err) => message.error(err));
-    }
-
-    return { customList, actionQuery };
-}
+import filterCustomTable from '@/views/information/spot-contract/components/filterTable/index.vue';
+import { getCustomList } from '../setup';
+import { openModal } from '@/setup/controlModal/index';
+import contextMenu from '@/components/contextMenu/index.vue';
+import { MenuItem } from '@/components/contextMenu/interface';
+import AddSpotContract from '@/views/information/spot-contract/components/add/index.vue';
 
 export default defineComponent({
     name: 'spot-contract-not-commit',
-    components: {},
+    components: {
+        filterCustomTable,
+        contextMenu,
+        AddSpotContract,
+    },
     setup() {
-        const { customList, actionQuery } = getCustomList();
+        const { spotContractList, actionQuery, columns, getColumns, search, loading, handlePermission } = getCustomList();
+        const { hasPermission } = handlePermission('spot_contract_unsubmitted');
+        const { openAction } = openModal('addSpotContract');
+        const contextMenuList = ref<MenuItem[]>([]);
         initData(() => {
-            actionQuery();
-            // 加载数据在这里
+            actionQuery(2);
+            getColumns();
         });
-        return { customList };
+        return { spotContractList, columns, search, contextMenuList, openAction, loading, hasPermission };
     },
 });
 </script>

+ 105 - 0
src/views/information/spot-contract/list/setup.ts

@@ -0,0 +1,105 @@
+import { OperationTabMenu } from '@/goServiceAPI/commonService/interface';
+import { QuerySpotContract } from '@/goServiceAPI/ermcp/spot-contract/index';
+import { Ermcp3ContractRsp } from '@/goServiceAPI/ermcp/spot-contract/interface';
+import { ColumnType, getTableHead } from '@/services/bus/table';
+import { message } from 'ant-design-vue';
+import { inject, Ref, ref } from 'vue';
+
+// 处理现货列表
+export function getCustomList() {
+    // 表格数据
+    const spotContractList = ref<Ermcp3ContractRsp[]>([]);
+    // 表头数据
+    const columns = ref<ColumnType[]>([]);
+    // 过滤项
+    const filteredInfo = ref();
+    const loading = ref<boolean>(false);
+    const permissionData = inject('thirdMenuList') as Ref<OperationTabMenu[]>
+    // 获取表头
+    function getColumns() {
+        const list = getTableHead('table_pcweb_delivery');
+        const filtered = filteredInfo.value || {};
+        columns.value.length = 0;
+        list.forEach((e, i) => {
+            const { columnfield, columntitle, aligntype } = e;
+            const item: ColumnType = {
+                key: String(i),
+                dataIndex: columnfield, // 表格数据对应的key
+                title: columntitle,
+                align: aligntype === 1 ? 'center' : aligntype === 2 ? 'left' : 'right',
+                slots: { customRender: columnfield },
+            };
+            // 以下添加过滤数据对应的方法
+            if (e.columntitle === '类型') {
+                item.onFilter = (value: string, record: Ermcp3ContractRsp) => String(record.contracttype).includes(value)
+                item.filteredValue = filtered.contracttype || null;
+            }
+            if (e.columntitle === '定价类型') {
+                item.onFilter = (value: string, record: Ermcp3ContractRsp) => String(record.pricetype).includes(value)
+                item.filteredValue = filtered.pricetype || null;
+            }
+            if (e.columntitle === '合同编号') {
+                item.onFilter = (value: string, record: Ermcp3ContractRsp) => record.contractno.includes(value);
+                item.filteredValue = filtered.contractno || null;
+            }
+            if (e.columntitle === '对手方') {
+                item.onFilter = (value: string, record: Ermcp3ContractRsp) => {
+                    if (record.contracttype === 1) { //采购方
+                        return record.sellusername.includes(value)
+                    } else { // 销售
+                        return record.buyusername.includes(value)
+                    }
+                };
+                item.filteredValue = filtered.negative || null;
+            }
+            columns.value.push(item);
+        });
+        console.log('columns', columns);
+
+    }
+    // 1-未提交 2-待审核 3-履约中 4-已完成
+    type EnumType = 1 | 2 | 3 | 4;
+    // 查询列表
+    function actionQuery(type: EnumType) {
+        loading.value = true;
+        QuerySpotContract({ querytype: type })
+            .then((res) => {
+                spotContractList.value = res.map((e, i) => {
+                    return { ...e, key: String(i) };
+                });
+                loading.value = false;
+                console.log('查询列表', spotContractList);
+            })
+            .catch((err) => {
+                message.error(err);
+                loading.value = false;
+            });
+    }
+    // 查询
+    function search(value: any) {
+        filteredInfo.value = value;
+        getColumns();
+    }
+
+    // 处理按钮是否有权限
+    type customType = 'spot_contract_unsubmitted' | "spot_contract_checkpending" | "spot_contract_performance" | "spot_contract_finished"
+    // 未提交 | "待审核" | "履约中" | "已完成"
+    function handlePermission(menuType: customType) {
+        // "新增" | "重新提交" | "修改" | "删除" | 
+        type codeType = "spot_contract_btn_add" | "spot_contract_btn_resubmit" | "spot_contract_btn_modify" | "spot_contract_btn_delete";
+
+        // 判断按钮是否有权限
+        function hasPermission(type: codeType): boolean {
+            let result = false;
+            if (permissionData) {
+                const btnList = permissionData.value.find((e) => e.code === menuType);
+                if (btnList && btnList.children) {
+                    result = btnList.children.find((e) => e.code === type && e.type === 2) ? true : false;
+                }
+            }
+            return result;
+        }
+        return { hasPermission };
+    }
+    return { spotContractList, actionQuery, columns, filteredInfo, getColumns, search, loading, handlePermission };
+}

+ 1 - 2
src/views/search/outaccount_status/index.vue

@@ -1,6 +1,5 @@
 <template>
-  <div class="account-status"
-       @contextmenu.prevent>
+  <div class="account-status">
     <firstMenu :list="menulist"
                :value="'value'"
                @selectMenu="selectMenu" />