Просмотр исходного кода

feat:"订单页面增加短信提醒记录功能,添加终端管理功能"

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

BIN
src/assets/device/alarmClock_Add.png


BIN
src/assets/home/M22.png


BIN
src/assets/joinPayMch/front.png


BIN
src/assets/mqtt/key.png


BIN
src/assets/mqtt/order.png


+ 1 - 0
src/common/js/utils.js

@@ -35,6 +35,7 @@ export const $M_Menus = {
   "M19": t("role.apkMan"),//apk管理
   // "M20":t("role.merchantMan"),//商户管理
   "M21": t("role.mqtt"),//MQTT
+  "M22": '终端管理',//终端管理
 }
 // 判断值是否是数字 true:数值型的,false:非数值型
 export const $M_IsNaN = (num) => {

+ 10 - 1
src/components/SimpleHeader.vue

@@ -7,7 +7,7 @@
       <i class="nbicon nbmore moreIcon"></i>
     </header>
   </div> -->
-  <van-nav-bar v-if="!isback" :title="name" left-arrow @click-left="onClickLeft"/>
+  <van-nav-bar v-if="!isback" :title="name" :border="isBorder" left-arrow @click-left="onClickLeft" :style="barStyle"/>
   <van-nav-bar v-else :title="name" />
 </template>
 
@@ -37,6 +37,15 @@ export default {
     targetPath: {
       type: String,
       default: ''
+    },
+    // 是否显示下边框
+    isBorder: {
+      type: Boolean,
+      default: true
+    },
+    barStyle: {
+      type: Object,
+      default: () => ({})
     }
   },
   emits: ['callback'],

+ 9 - 18
src/components/dateSelectList/index.vue

@@ -14,8 +14,8 @@
           {{ $t('dateSelectList.other') }}
           <div class="block3 flex-col"></div>
         </div>
-        <!-- 日期选择 -->
-        <van-calendar color="#4d6add" v-model:show="calendarShow" type="range" :max-range="186" :show-confirm="false"
+        <!-- 按日统计 -->
+        <van-calendar color="#4d6add" v-model:show="calendarShow" type="range" :max-range="366" :show-confirm="false"
           :allow-same-day="true" :min-date="minDate" :max-date="maxDate" @confirm="calendarConfirm" />
         <!-- 选择统计类型 -->
         <van-popup v-model:show="timeTypeShow" position="bottom">
@@ -23,10 +23,8 @@
             @cancel="timeTypeCancel" />
         </van-popup>
         <!-- 按月统计 -->
-        <van-popup v-model:show="monthDateShow" position="bottom">
-          <van-date-picker v-model="monthDate" :title="$t('dateSelectList.monthDate')" :min-date="minDate" :max-date="maxDate" @confirm="monthDateConfirm" @cancel="monthDateCancel"
-            :columns-type="monthDateType" />
-        </van-popup>
+        <van-calendar color="#4d6add" v-model:show="monthDateShow" type="range" :max-range="366" :show-confirm="false"
+          :allow-same-day="true" :min-date="minDate" :max-date="maxDate" @confirm="monthDateConfirm" />
       </div>
     </div>
   </div>
@@ -56,7 +54,6 @@ export default {
     const timeChange = (data) => {
       timeType.value = data;
       // 当时时间类型切换为其他时间弹出日期控件
-      // (data === "4") ? calendarShow.value = true : outputDate();
       (data === "4") ? timeTypeShow.value = true : outputDate();
     };
     let calendarDate = [];
@@ -64,7 +61,6 @@ export default {
     // 其他时间日期组件确认返回
     const calendarConfirm = (data) => {
       calendarShow.value = false;
-      console.log(data);
       calendarDate = data;
       outputDate();
     };
@@ -155,12 +151,9 @@ export default {
             dateUtil.formateDate(endTime, "yyyy-MM-dd") + " 23:59:59";
         } else {
           // 按月统计
-          params.chartType = "month";
-          startTime = new Date(monthDate.value[0] + '-' + monthDate.value[1] + '-01');
-          endTime = new Date(monthDate.value[0], monthDate.value[1], 0);
-          // endTime = new Date(monthEndDate.value[0] + '-' + monthEndDate.value[1] + '-01');
-          console.log("startTime", startTime);
-          console.log("endTime", endTime);
+          params.chartType = "year";
+          startTime = calendarDate[0];
+          endTime = calendarDate[1];
           params.startDate =
             dateUtil.formateDate(startTime, "yyyy-MM-dd") + " 00:00:00";
           params.endDate =
@@ -178,7 +171,6 @@ export default {
       { text: t('dateSelectList.monthType'), value: "2" },
     ];
     const timeTypeConfirm = ({ selectedOptions }) => {
-      console.log('selectedOptions[0].text', selectedOptions[0].value);
       // 按日统计
       chartType.value = selectedOptions[0].value;
       if (selectedOptions[0].value == '1') {
@@ -199,9 +191,8 @@ export default {
     const monthDateShow = ref(false);
     const monthDate = ref([currentYear, currentMonth]);
     const monthDateType = ['year', 'month'];
-    const monthDateConfirm = () => {
-      const date1 = new Date(monthDate.value[0], monthDate.value[1], 0);
-      console.log('date1', date1);
+    const monthDateConfirm = (data) => {
+      calendarDate = data;
       monthDateShow.value = false;
       outputDate();
     }

+ 2 - 1
src/main.js

@@ -5,7 +5,7 @@ import {
   PullRefresh, List, Tab, Tabs, SubmitBar, Toast, Skeleton, RadioGroup, Radio, NoticeBar, ActionSheet, Cascader, Col, Row,
   Slider, DatePicker, Switch, Calendar, Picker, Uploader, Tag, DropdownMenu, DropdownItem, Notify, ConfigProvider, NavBar,
   Area, Popover, Collapse, CollapseItem, PickerGroup, TimePicker, BackTop, Progress, Tabbar, TabbarItem, Search, FloatingBubble,
-  TextEllipsis, Step, Steps
+  TextEllipsis, Step, Steps, Sticky
 } from 'vant';
 import { Image as VanImage } from 'vant';
 import App from './App.vue'
@@ -96,6 +96,7 @@ app.use(ActionBarButton)
   .use(TextEllipsis)
   .use(Step)
   .use(Steps)
+  .use(Sticky)
 
 app.use(router)
 app.use(store)

+ 42 - 0
src/router/index.js

@@ -202,6 +202,13 @@ const router = createRouter({
       component: () => import("@/views/settlement/index"),
       meta: { index: 1 },
     },
+    // 结算账号
+    {
+      path: "/bindBankCard",
+      name: "bindBankCard",
+      component: () => import("@/views/bindBankCard/index"),
+      meta: { index: 1 },
+    },
     // 公告编辑
     {
       path: "/announcement",
@@ -604,6 +611,41 @@ const router = createRouter({
       component: () => import("@/views/mqtt/topic/index"),
       meta: { index: 1 },
     },
+    // 终端管理
+    {
+      path: "/terminal",
+      name: "terminal",
+      component: () => import("@/views/terminal/index"),
+      meta: { index: 1 },
+    },
+    // 终端列表
+    {
+      path: "/terminalList",
+      name: "terminalList",
+      component: () => import("@/views/terminal/list"),
+      meta: { index: 1 },
+    },
+    // 终端分销
+    {
+      path: "/distribution",
+      name: "distribution",
+      component: () => import("@/views/terminal/distribution"),
+      meta: { index: 1 },
+    },
+    // 密钥管理
+    {
+      path: "/secretKey",
+      name: "secretKey",
+      component: () => import("@/views/terminal/secretKey"),
+      meta: { index: 1 },
+    },
+    // 分销管理
+    {
+      path: "/check",
+      name: "check",
+      component: () => import("@/views/terminal/check"),
+      meta: { index: 1 },
+    },
   ],
 });
 // 路由守卫处理

+ 49 - 0
src/service/terminal/index.js

@@ -0,0 +1,49 @@
+
+import axios from '../../utils/axios';
+import { stringToUrl } from '@/common/js/utils';
+
+// 终端列表
+export function getTerminalList(params) {
+  return axios.get(`/THIRD-SERVER/terminal/terminalList?${stringToUrl(params)}`, params);
+}
+
+// 生成终端
+export function generatingTerminal(params) {
+    return axios.post(`/THIRD-SERVER/terminal/addTerminal`, params);
+}
+
+// 获取终端分销
+export function getTerminalProportion(params) {
+  return axios.post(`/THIRD-SERVER/terminalProportion/getTerminalProportion`, params);
+}
+
+// 提交终端比例
+export function submitProportion(params) {
+  return axios.post(`/THIRD-SERVER/terminalProportion/submit`, params);
+}
+
+// 获取待审核记录
+export function getProportionCheck(params) {
+  return axios.post(`/THIRD-SERVER/terminalProportion/getTerminalProportionCheck`, params);
+}
+
+// 修改审核状态
+
+export function checkProportion(params) {
+  return axios.post(`/THIRD-SERVER/terminalProportion/checkProportion`, params);
+}
+
+// 获取密钥
+export function getSecretKey(params) {
+  return axios.get(`/THIRD-SERVER/merchantInfo/getSecretKey?${stringToUrl(params)}`, params);
+}
+
+// 生成密钥
+export function generateSecretKey(params) {
+  return axios.get(`/THIRD-SERVER/merchantInfo/generateSecretKey?${stringToUrl(params)}`, params);
+}
+
+// 获取审核记录
+export function getProportionCheckList(params) {
+  return axios.post(`/THIRD-SERVER/terminalProportion/getTerminalProportionCheckList`, params);
+}

+ 8 - 2
src/styles/orderCenter/index.less

@@ -43,10 +43,16 @@
         }
 
         .main5 {
-          cursor: pointer;
+          
+
+          .label1 {
+            width: 20px;
+            cursor: pointer;
+          }
 
           .label2 {
-            width: 16px;
+            width: 18px;
+            cursor: pointer;
           }
         }
       }

+ 0 - 1
src/views/apkManage/index.vue

@@ -18,7 +18,6 @@
     </div>
     <div v-else class="headCon l-flex-between o-plr-20 o-pt-26 o-pb-12 kBordBott">
       <div class="l-flex-RC">
-        <!-- <img class="ruleIcon o-mr-10" src="@/assets/advertManage/ruleIcon.png" alt="" /> -->
         <div class="ruleIcon"></div>
         <div class="c-text-color c-text-b c-text-15">
           {{ $t("advertManage.advertRule.total") }}

+ 201 - 0
src/views/bindBankCard/index.vue

@@ -0,0 +1,201 @@
+<template>
+  <!-- 提现账号 -->
+  <div class="shandeMchPage flex-col" style="background-color: #f5f5f5;">
+    <s-header :name="$t('joinpayMch.settlementAccount')" :noback="false" :isBorder="false"></s-header>
+    <van-steps :active="currentSwipeItem">
+      <van-step v-for="(item, index) in stepItem" :key="index">
+        <template #active-icon>
+          <div class="steps-active-icon">
+            <span>
+              {{ item.value }}
+            </span>
+          </div>
+        </template>
+        <template #inactive-icon>
+          <div class="steps-inactive-icon">
+            <span>
+              {{ item.value }}
+            </span>
+          </div>
+        </template>
+        <template #finish-icon>
+          <div class="steps-finish-icon">
+            <van-icon name="success" size="10px" color="#ffffff" />
+          </div>
+        </template>
+        <span>{{ item.title }}</span>
+      </van-step>
+    </van-steps>
+    <div class="tabsContainer">
+      <div class="element"></div>
+      <van-tabs v-model:active="active" swipeable>
+        <van-tab title="个人">
+          <div style="border-radius: 0 0 20px 20px; background-color: #ffffff; min-height: auto">
+            <div style="padding: 10px 15px;">
+              <van-icon name="friends-o" size="15px" style="margin-right: 5px;" />
+              <span style="font-size: 15px; font-weight: 1000;">收款人证件(大陆)</span>
+            </div>
+            <div class="cardRow" style="margin-bottom: 0px;">
+              <div class="cardLi">
+                <van-uploader v-model="cardNegativeList" :max-size="2 * 1024 * 1024" :max-count="1"
+                  :after-read="afterRead" :preview-size="[300, 160]" :before-delete="deleteCertFront"
+                  @oversize="onOversize" upload-text="身份证人像面" />
+              </div>
+              <div class="cardLi">
+                <van-uploader v-model="cardPositiveList" :max-size="2 * 1024 * 1024" :max-count="1"
+                  :after-read="afterRead" :preview-size="[300, 160]" :before-delete="deleteCertBack"
+                  @oversize="onOversize" upload-text="身份证国徽面" />
+              </div>
+            </div>
+          </div>
+        </van-tab>
+        <van-tab title="企业商户">结算卡信息</van-tab>
+      </van-tabs>
+    </div>
+    <div class="fixed-bottom-btn">
+      <van-button type="primary" size="large" class="fixed-bottom-btn-content" color="linear-gradient(to right, #7185d6, #4d6add)" >下一步</van-button>
+    </div>
+    <!-- 
+    <div style="height: 10px;">
+    </div> -->
+  </div>
+</template>
+
+<script>
+import { onMounted, ref } from "vue";
+import sHeader from "../../components/SimpleHeader";
+
+export default {
+  components: { sHeader },
+  setup() {
+    const currentSwipeItem = ref(0);
+    const stepItem = ref([
+      {
+        title: "证件信息",
+        value: "1",
+      },
+      {
+        title: "结算卡信息",
+        value: "2",
+      },
+      {
+        title: "信息审核",
+        value: "3",
+      },
+      {
+        title: "签约",
+        value: "4",
+      },
+    ])
+    onMounted(async () => {
+    });
+
+    return {
+      currentSwipeItem,
+      stepItem
+    };
+  },
+};
+</script>
+
+<style lang="less" scoped>
+@import "../../common/style/common.less";
+
+.cardRow {
+  width: 100%;
+  // display: flex;
+
+  .cardLi {
+    // width: 50%;
+    text-align: center;
+    padding: 0.5em;
+  }
+
+}
+
+.van-steps {
+  background: transparent; // 如果背景是白色就不需要了,默认是白色的
+  padding: 0 30px 20px 30px;
+  // margin: 80px auto;
+  // overflow: visible; //如果不需要文字,或者不需要调整位置,可以不设置
+  background-color: #4d6add;
+
+  .steps-active-icon {
+    color: #ffffff;
+  }
+
+  :deep(.van-step__circle-container) {
+    background-color: #7185d6; // 如果背景是白色就不需要了,默认是白色的
+    width: 10px;
+    align-items: center;
+    text-align: center;
+    padding: 4px 8px;
+    border-radius: 50%;
+  }
+
+  :deep(.van-step__title--active) {
+    color: #ffffff;
+  }
+
+  :deep(.van-step--horizontal .van-step__line) {
+    height: 2px; // 自定义调整进度条的粗细
+    top: 28px; // 自定义调整进度条的位置
+    background-color: #7185d6;
+  }
+
+  :deep(.van-step--finish .van-step__line) {
+    background-color: #ffffff; //自定义激活时进度条的颜色
+  }
+
+  :deep(.van-step--finish .van-step__title) {
+    color: #ffffff; //自定义激活时进度条的颜色
+  }
+
+}
+
+.tabsContainer {
+  .element {
+    position: absolute;
+    top: 105px;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    height: 10px;
+    background-color: #ffffff;
+    /* 设置背景颜色 */
+    border-radius: 20px 20px 0 0;
+    /* 左上和右上角圆角 */
+    background-clip: content-box;
+    /* 只应用于内容区域,不包括圆角 */
+  }
+}
+
+
+:deep(.van-nav-bar) {
+  background-color: #4d6add;
+}
+
+:deep(.van-nav-bar__title) {
+  color: #ffffff !important;
+}
+
+:deep(.van-nav-bar .van-icon ) {
+  color: #ffffff !important;
+}
+
+.fixed-bottom-btn {
+  position: fixed;
+  bottom: 0; /* 距离底部的距离,可以根据需要调整 */
+  left: 0;
+  width: 100%;
+  z-index: 100;
+  background-color: #ffffff;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+:deep(.van-button) {
+  border-radius: 15px;
+  margin: 10px;
+}
+</style>

+ 4 - 1
src/views/commonTools/index.vue

@@ -85,7 +85,7 @@ export default {
             if (!isAccount) {
                 //  如果是公司人type=0,要把账号权限添加上去
                 if (user.type === 0) {
-                    pushToolList.value.push({
+                    pushToolList.push({
                         label: t("home.accountPermission"),
                         value: "M8"
                     });
@@ -147,6 +147,9 @@ export default {
                 case "M20":
                     router.push({ path: "/merchantManage" });
                     break;
+                case "M22":
+                    router.push({ path: "/terminal" });
+                    break;
             }
         };
 

+ 0 - 15
src/views/device/deviceSet.vue

@@ -237,19 +237,6 @@ import { styleUrl } from "../../common/js/utils";
 export default {
   name: "deviceSet",
   components: { sHeader, kCascader, kDialog },
-  // // 路由守卫
-  // beforeRouteEnter(to, from, next) {
-  //   console.log("to", to);
-  //   console.log("from", from);
-  //   // 不能获取组件实例
-  //   // 因为当守卫执行前,组件实例还没被创建
-  //   if (from.name === "editTag") {
-  //     let tagList = sessionStorage.getItem("tagList") || "[]";
-  //     this.tagsList.arr = JSON.parse(tagList);
-  //     sessionStorage.removeItem("tagList");
-  //   }
-  //   next();
-  // },
   setup() {
     // 广告规则列表
     const adRuleList = ref([]);
@@ -317,7 +304,6 @@ export default {
     const onConfirm = ({ selectedOptions }) => {
       paymentValue.value = selectedOptions[0].text;
       deviceDetal.value.payType = selectedOptions[0].value;
-      // console.log(deviceDetal.value.payType);
       showPayment.value = false;
     };
     // 初始化页面获取列表
@@ -339,7 +325,6 @@ export default {
     const getLabelDetail = () => {
       Api_getGetEquipmentToLabel({ equipmentId: route.query.deviceId }).then(
         (res) => {
-          // console.log("res", res);
           if (res.data.code === "00000") {
             tagsList.arr = res.data.data;
             // 储存数据到vuex

+ 0 - 8
src/views/distributionSet/detail.vue

@@ -303,10 +303,6 @@ export default {
     }
     // 点击删除
     const toDele = (idx) => {
-      // if (distPropList.length === 1) {
-      //   showToast(t('distributionSet.addDist.distPropRange'));
-      //   return;
-      // }
       distPropList.splice(idx, 1);
     }
     // 分销比例规则
@@ -315,13 +311,9 @@ export default {
     const getDeviceListFun = async () => {
       const { data } = await getEquipmentList({ adminId: user.id });
       if (data.code === '00000') {
-        // deviceList.value = data.data.map(item => {
-        //     return {name:item.name,clientId}
-        // });
         busiPopList.value = data.data.map(item => {
           return { name: item.name != null ? item.name : item.clientId, clientId: item.clientId }
         });
-        // console.log(busiPopList.value);
       }
     }
     // 设备编码选择框

+ 13 - 11
src/views/home/index.vue

@@ -530,10 +530,6 @@ export default {
     const combinedList = ref([]); // 设备销额集合
     const calculateTotal = (item) => {
       let total = 0;
-      // total += item.coins;
-      // total += item.bills;
-      // total += item.coinsBills;
-      // total += item.creditCard;
       if (typeof item.coinsBills === 'number' && !isNaN(item.coinsBills)) {
         total += item.coinsBills;
       }
@@ -541,7 +537,6 @@ export default {
       if (typeof item.creditCard === 'number' && !isNaN(item.creditCard)) {
         total += item.creditCard;
       }
-      // total += item.electronicPayment;
       return total;
     }
 
@@ -566,8 +561,6 @@ export default {
 
 
             const machineSalesData = {
-              // totalSales: totalSalesVal,
-              // totalCash: totalCashVal,
               machineName: machineNameVal,
               coins: coinsVal,
               bills: billsVal,
@@ -685,10 +678,16 @@ export default {
       }
 
       if (user.type === 0) {
-        pushToolList.value.push({
-          label: t("role.mqtt"),
-          value: "M21"
-        });
+        pushToolList.value.push(
+          {
+            label: t("role.mqtt"),
+            value: "M21"
+          },
+          {
+            label: "终端管理",
+            value: "M22"
+          }
+        );
       }
 
       // 如果没有账号权限
@@ -768,6 +767,9 @@ export default {
         case "M21":
           router.push({ path: "/mqtt" });
           break;
+        case "M22":
+          router.push({ path: "/terminal" });
+          break;
       }
     };
 

+ 141 - 10
src/views/orderCenter/index.vue

@@ -17,15 +17,14 @@
             </div>
             <!-- 订单中心搜索 -->
             <div class="flex-col">
-              <div class="main5 flex-row justify-between" @click="searchClick()">
-                <img class="label2" src="@/assets/device/searchIcon.png" />
+              <div class="main5 flex-row justify-between" >
+                <img v-if="user.type < 2 " class="label1 o-pr-20" src="@/assets/taskMessage/refundIcon.png" @click="pushPageList('/refundReminder')"/>
+                <img class="label2" src="@/assets/device/searchIcon.png" @click="searchClick()"/>
               </div>
             </div>
           </div>
         </div>
-        <!-- <img class="img1" referrerpolicy="no-referrer" src="@/assets/line.png" /> -->
         <dateSelectList @update="update($event)"></dateSelectList>
-        <!-- <typeSelectList @upselectdata="upselectdata($event)"></typeSelectList> -->
         <typeDownMenu @upselectdata="upselectdata($event)"></typeDownMenu>
         <!-- 销售数据 -->
         <div v-if="!noData(salesVolume, salesNumber, orderNumber)" class="o-plr-8 o-pt-15">
@@ -237,6 +236,14 @@
         <div style="display: flex; justify-content: center; padding-bottom: 20px;">
           <van-button size="small"
             v-if="refundObject.status === 1 && user.ifForeign === '0' && user.type < 2 && orderType != '3'"
+            @click="clickSendList(refundObject.sn)" round type="primary" style="padding: 15px 15px; margin-top: 20px;"
+            color="#9F79EE">
+            提醒记录
+          </van-button>
+          <div v-if="refundObject.status === 1 && user.ifForeign === '0' && user.type < 2" style="width: 20px;">
+          </div>
+          <van-button size="small"
+            v-if="refundObject.status === 1 && user.ifForeign === '0' && user.type < 2 && orderType != '3'"
             @click="sentRefundMessage(refundObject)" round type="primary" style="padding: 15px 15px; margin-top: 20px;"
             color="#4dc193">
             退款提醒
@@ -282,6 +289,35 @@
         </div>
       </template>
     </kDialog>
+    <van-dialog v-model:show="sendListshow" title="提醒记录" class="record-dialog">
+      <div class="record-list">
+        <!-- 表格头部 -->
+        <div class="list-header van-hairline--bottom">
+          <div class="header-item">发送时间</div>
+          <div class="header-item">接收状态</div>
+        </div>
+
+        <!-- 数据列表 -->
+        <div class="scroll-wrapper">
+          <template v-if="sendList.length > 0">
+            <div v-for="(item, index) in sendList" :key="index" class="list-item van-hairline--bottom">
+              <div class="item-cell time">{{ Format_time(item.createDate, 'YYYY/MM/DD HH:mm:ss') }}</div>
+              <div class="item-cell">
+                <van-tag :type="getStatusType(item.status)" size="medium">
+                  {{ getStatusText(item.status) }}
+                </van-tag>
+              </div>
+            </div>
+          </template>
+
+        <!-- 空状态 -->
+        <div v-else class="empty-tip">
+            <van-icon name="info" />
+            暂无提醒记录
+          </div>
+        </div>
+      </div>
+    </van-dialog>
   </div>
 </template>
 <script>
@@ -302,10 +338,12 @@ import { getLoginUser, $M_IsDate, Format_time, $M_ExportFile, styleUrl } from ".
 import { getHuifuId, checkBalance } from "../../service/huifuMch/index";
 import dateUtil from "../../utils/dateUtil";
 import dateSelectList from "../../components/dateSelectList";
-// import typeSelectList from "../../components/typeSelectList";
+import { refundRecord } from "@/service/taskMessage";
 import typeDownMenu from "../../components/typeDownMenu";
 import { getStatistics } from "../../service/home";
 import { useI18n } from "vue-i18n";
+import { useRouter } from "vue-router";
+
 export default {
   name: "order",
   components: { sHeader, orderSearch, dateSelectList, typeDownMenu, kNoData, kDialog },
@@ -330,6 +368,11 @@ export default {
     const isInvoice = ref(0);
     // 账户余额
     const balance = ref(0);
+    // 提醒记录弹窗
+    const sendListshow = ref(false);
+    // 提醒记录
+    const sendList = ref([]);
+    const router = useRouter();
     // 更新是否开发票
     const updateInvoice = async (id) => {
       const params = {
@@ -388,11 +431,7 @@ export default {
         refundNum.value = [];
         checkedAll.value = false;
         totalRefund.value = 0;
-        // cofficentForm.price = row.price;
-        // cofficentForm.maxPrice = row.price;
         cofficentForm.id = row.id;
-        // cofficentForm.maxNumber = row.productNumber;
-        // cofficentForm.productNumber = row.productNumber;
         row.orderDetails.forEach(item => {
           if (item.refundStatus == '1' || item.refundStatus == '2') {
             orderDetails.value.push(item);
@@ -924,6 +963,41 @@ export default {
         });
       }
     };
+    // 短信提醒记录弹窗
+    const clickSendList = async (sn) => {
+      sendListshow.value = true;
+      const searchParams = reactive({
+        sendAdminId: user.id, // 当前登录账户的id
+        current: 1, // 当前页
+        size: 20, // 页大小
+        sn: sn, // 订单编号
+      });
+      const { data } = await refundRecord(
+        Object.assign({}, searchParams)
+      );
+      if (data.code === "00000") {
+        sendList.value = data.data.records;
+        console.log(sendList.value);
+      }
+    };
+    const getStatusText = (status) => {
+      return {
+        0: '等待返回',
+        1: '接收成功',
+        2: '接受失败'
+      }[status] || '未知状态'
+    };
+    const getStatusType = (status) => {
+      return {
+        0: 'warning',
+        1: 'success',
+        2: 'error'
+      }[status] || '未知状态'
+    };
+    // 跳转
+    const pushPageList = (url) => {
+      router.push(url);
+    }
     return {
       user,
       loading,
@@ -978,7 +1052,13 @@ export default {
       isInvoice,
       updateInvoice,
       total,
-      balance
+      balance,
+      sendListshow,
+      clickSendList,
+      sendList,
+      getStatusText,
+      getStatusType,
+      pushPageList,
     };
   },
 };
@@ -986,4 +1066,55 @@ export default {
 <style lang="less" scoped>
 @import "../../common/style/common.less";
 @import "../../styles/orderCenter/index.less";
+
+.record-dialog {
+  .record-list {
+    // width: 80vw;
+    max-width: 600px;
+
+    .list-header {
+      display: flex;
+      padding: 12px;
+      // background: #fafafa;
+
+      .header-item {
+        flex: 1;
+        font-weight: 500;
+        color: #333;
+      }
+    }
+
+    .scroll-wrapper {
+      max-height: 60vh;
+      overflow-y: auto;
+
+      .list-item {
+        display: flex;
+        align-items: center;
+        padding: 12px;
+
+        .item-cell {
+          flex: 1;
+
+          &.time {
+            font-size: 13px;
+            color: #666;
+          }
+        }
+      }
+
+      .empty-tip {
+        padding: 20px;
+        text-align: center;
+        color: #999;
+
+        .van-icon {
+          display: block;
+          margin: 0 auto 8px;
+          font-size: 24px;
+        }
+      }
+    }
+  }
+}
 </style>

+ 2 - 2
src/views/taskMessage/proportion/index.vue

@@ -99,7 +99,7 @@
                 </van-button>
               </div>
               <div class="itemRow" style="display: flex; justify-content: flex-end">
-                <span v-if="item.checkType === '0' && user.type > 1" style="color: #FFA500"> {{ $t('taskMessage.toBeApproved') }}</span>
+                <span v-if="item.checkType === '0' && (user.type > 1 && user.type < 4)" style="color: #FFA500"> {{ $t('taskMessage.toBeApproved') }}</span>
                 <span v-if="item.checkType === '1'" style="color: #1989fa"> {{ $t('taskMessage.adopt') }}</span>
                 <span v-if="item.checkType === '2'" style="color: #ff0033"> {{ $t('taskMessage.cancel') }}</span>
                 <span v-if="item.checkType === '3'" style="color: #ff0000"> {{ $t('taskMessage.fail') }}</span>
@@ -267,7 +267,7 @@ export default {
         searchParams.adminId = user.id;
         searchGetList();
         // 如果是type大于1,那么不能有操作的权限
-        if (user.type > 1) {
+        if (user.type > 1 && user.type < 4) {
           isOper.value = false;
         }
       }

+ 306 - 0
src/views/terminal/check/index.vue

@@ -0,0 +1,306 @@
+<template>
+    <!-- 分销申请审批 -->
+    <div class="taskMessagePage flex-col">
+        <s-header name="分销管理" :noback="false"></s-header>
+        <div class="taskMessageBox flex-col">
+            <van-list v-model:loading="loading" v-model:error="error" :error-text="$t('common.reqFailClkReload')"
+                :finished="finished" :finished-text="$t('common.noMoreTxt')" offset="300" :immediate-check="false"
+                @load="onLoad">
+                <div class="searchRow flex-row justify-between">
+                    <div class="flex-col">
+                        <div class="flex-row justify-between bd3">
+                            <div class="flex-col outer4 proportionIcon"></div>
+                            <span class="flex-col txt2">{{ $t('taskMessage.total') }}<span class="discountNumber">{{
+            checkListTotal
+        }}</span>{{ $t('taskMessage.recordsInTotal') }}</span>
+                        </div>
+                    </div>
+                    <div class="l-flex-RC">
+                        <div @click="reviewedClk" class="label3 o-mr-10">{{
+            $t('taskMessage.toViewAppro')
+        }}</div>
+                    </div>
+                </div>
+                <div class="listBox">
+                    <div v-for="(item, index) in checkList" :key="index" class="listItem">
+                        <div class="itemBox">
+                            <div class="itemRow">
+                                <span class="itemTitle">终端编号:&nbsp;</span>
+                                {{ item.terminalNo }}
+                            </div>
+                            <!-- 平台的 -->
+                            <div class="itemRow">
+                                <span class="itemTitle">手续费:&nbsp;</span>
+                                <!-- <span class="itemTitle discount">手续费:&nbsp;</span> -->
+                                {{ item.proportion }}%
+                            </div>
+                            <!-- 机主的 -->
+                            <div class="itemRow">
+                                <span class="itemTitle">分销人:&nbsp;</span>
+                                终端商户
+                                <span class="itemTitle discount">{{ $t('taskMessage.proportion') }}:&nbsp;</span>
+                                {{ item.adminProportion }}%
+                            </div>
+                            <!-- 分账方的 -->
+                            <div class="itemRow" v-if="item.type >= 2">
+                                <span class="itemTitle">分销人:&nbsp;</span>
+                                {{ item.agencyName }}
+                                <span class="itemTitle discount">{{ $t('taskMessage.proportion') }}:&nbsp;</span>
+                                {{ item.agencyProportion }}%
+                            </div>
+                            <!-- 分账方4个 -->
+                            <div class="itemRow" v-if="item.type >= 3">
+                                <span class="itemTitle">分销人:&nbsp;</span>
+                                {{ item.merchantName }}
+                                <span class="itemTitle discount">{{ $t('taskMessage.proportion') }}:&nbsp;</span>
+                                {{ item.merchantProportion }}%
+                            </div>
+                            <!-- 分账方5个以上 -->
+                            <div class="itemRow" v-if="item.type >= 4">
+                                <span class="itemTitle">分销人:&nbsp;</span>
+                                {{ item.personageName }}
+                                <span class="itemTitle discount">{{ $t('taskMessage.proportion') }}:&nbsp;</span>
+                                {{ item.personageProportion }}%
+                            </div>
+                            <div class="itemRow">
+                                <span class="itemTitle">{{ $t('taskMessage.applicationTime') }}:&nbsp;</span>
+                                {{ showDateTime(item.createDate) }}
+                            </div>
+                            <div class="itemRow" v-if="item.status != 0 && item.status != 2">
+                                <span class="itemTitle">{{ $t('taskMessage.approvalTime') }}:&nbsp;</span>
+                                {{ showDateTime(item.modifyDate) }}
+                            </div>
+                            <div class="itemRow" style="display: flex; justify-content: flex-end"
+                                v-if="item.status === 0 && user.type == 0">
+                                <van-button span="5" round type="primary" style="
+                      height: 2em;
+                      padding: 0 1em;
+                      margin: 0 0.5em;
+                      background: rgb(255 0 0 / 20%);
+                      color: #ff0000;
+                      border-color: #ff0000;
+                    " @click="changeStatusFun(item, 3)">
+                                    {{ $t('taskMessage.fail') }}
+                                </van-button>
+                                <van-button span="5" round type="primary" style="
+                      height: 2em;
+                      padding: 0 1em;
+                      margin: 0 0.5em;
+                      background: rgb(25 137 250 / 20%);
+                      color: #1989fa;
+                    " @click="changeStatusFun(item, 1)">
+                                    {{ $t('taskMessage.adopt') }}
+                                </van-button>
+                            </div>
+                            <div class="itemRow" style="display: flex; justify-content: flex-end">
+                                <span v-if="item.status === 0 && (user.type > 1 && user.type < 4)"
+                                    style="color: #FFA500"> {{ $t('taskMessage.toBeApproved') }}</span>
+                                <span v-if="item.status === 1" style="color: #1989fa"> {{ $t('taskMessage.adopt')
+                                    }}</span>
+                                <span v-if="item.status === 2" style="color: #ff0033"> {{ $t('taskMessage.cancel')
+                                    }}</span>
+                                <span v-if="item.status === 3" style="color: #ff0000"> {{ $t('taskMessage.fail')
+                                    }}</span>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </van-list>
+        </div>
+    </div>
+</template>
+<script>
+import { onMounted, reactive, ref, toRefs } from "vue";
+import sHeader from "../../../components/SimpleHeader.vue";
+import { getProportionCheckList } from "../../../service/terminal";
+import { getLoginUser } from "@/common/js/utils";
+import dateUtil from "@/utils/dateUtil";
+import { showFailToast } from "vant";
+
+
+export default {
+    components: { sHeader },
+    setup() {
+        const user = getLoginUser();
+        const loading = ref(false); // 加载状态
+        const error = ref(false); // 错误状态
+        const finished = ref(false); // 结束翻页状态
+        const checkListTotal = ref(0); // 列表总数
+        const checkList = ref([]); // 列表集合
+        let searchParams = reactive({
+            adminId: "", // 当前登录账户的id
+            terminalNo: "", // 设备编号
+            current: 1, // 当前页
+            size: 20, // 页大小
+            status: null, // 审核状态
+        });
+        // 获取审核记录
+        const getProportionCheckListFun = async () => {
+            const { data } = await getProportionCheckList(
+                Object.assign({}, searchParams)
+            );
+            if (data.code === "00000") {
+                // 列表值叠加
+                checkList.value = checkList.value.concat(
+                    data.data.records
+                );
+                checkListTotal.value = data.data.total;
+                if (checkList.value.length === data.data.total) {
+                    finished.value = true;
+                }
+                loading.value = false;
+            } else {
+                showFailToast(data.message);
+            }
+        }
+
+        // 滚动加载
+        const onLoad = () => {
+            if (!finished.value) {
+                searchParams.current = searchParams.current + 1;
+                getProportionCheckListFun();
+            }
+        };
+
+        const showDateTime = (date) => {
+            return date
+                ? dateUtil.formateDate(new Date(date), "yyyy/MM/dd hh:mm:ss")
+                : "";
+        };
+        // 点击查看待审核
+        const reviewedClk = () => {
+            // 改为未审核状态
+            searchParams.status = 0;
+            searchParams.current = 1;
+            checkList.value = [];
+            getProportionCheckListFun();
+        };
+        onMounted(async () => {
+            if (user && user.type > 1 && user.type < 4) {
+                searchParams.adminId = user.id;
+                getProportionCheckListFun();
+            }
+        });
+        return {
+            loading,
+            error,
+            finished,
+            checkList,
+            checkListTotal,
+            onLoad,
+            getProportionCheckListFun,
+            showDateTime,
+            user,
+            reviewedClk,
+            ...toRefs(searchParams),
+        };
+    }
+};
+
+</script>
+
+<style lang="less" scoped>
+@import "../../../common/style/common.less";
+
+.taskMessagePage {
+    width: 100%;
+
+    .taskMessageBox {
+        width: 100%;
+        height: calc(100% - 60px);
+        overflow: auto;
+
+        .searchRow {
+
+            padding: 0.5rem 0.5rem;
+            background: rgba(255, 255, 255, 1) url("../../../assets/home/line.png") bottom center no-repeat;
+            background-size: 100%;
+            align-items: center;
+
+            .bd3 {
+
+                .outer4 {
+                    width: 19px;
+                    height: 19px;
+                    margin-right: 5px;
+                    background: url("../../../assets/alarmHistory/icon.png") top center no-repeat;
+                    background-size: 100%;
+
+                    &.proportionIcon {
+                        background: url("../../../assets/taskMessage/retailIcon.png") top center no-repeat;
+                        background-size: 100%;
+                    }
+                }
+
+                .txt2 {
+                    overflow-wrap: break-word;
+                    color: rgba(64, 77, 116, 1);
+                    font-size: 15px;
+                    font-family: PingFangSC-Semibold;
+                    text-align: left;
+                    white-space: nowrap;
+                    display: block;
+                    font-weight: bold;
+
+                    .discountNumber {
+                        font-size: 18px;
+                        color: #df5e4c;
+                    }
+                }
+            }
+
+            .label3 {
+                color: #4d6add;
+            }
+
+            .main5 {
+                width: auto;
+
+                .label2 {
+                    width: 0.5rem;
+                    height: 0.5rem;
+                    margin-right: 5px;
+                    cursor: pointer;
+                }
+            }
+        }
+
+        .van-tabs__line {
+            background-color: #4d6add !important;
+        }
+
+        .van-tab--active .van-tab__text--ellipsis {
+            color: #4d6add;
+        }
+
+        .listBox {
+            .listItem {
+                width: 100%;
+                background: url("../../../assets/home/line.png") bottom center no-repeat;
+                background-size: 100%;
+                position: relative;
+                display: inline-block;
+
+                .itemBox {
+                    width: 92%;
+                    margin: 20px auto;
+                    font-size: 12px;
+                    line-height: 1.64;
+
+                    .itemRow {
+                        width: 100%;
+                    }
+
+                    .itemTitle {
+                        color: #8787a6;
+                    }
+
+                    .discount {
+                        padding-left: 2em;
+                    }
+                }
+            }
+        }
+    }
+}
+</style>

+ 407 - 0
src/views/terminal/distribution/index.vue

@@ -0,0 +1,407 @@
+<template>
+    <!-- 分销设置 -->
+    <div class="distributionDetailIdx">
+        <s-header name="分销设置" :noback="false"></s-header>
+        <div class="cust_vantBorder">
+            <div class="kBordBott">
+                <van-field disabled colon :border="false" v-model="cofficentForm.terminalNo" clearable label-width="110"
+                    name="terminalNo" label="终端编号" />
+                <div class="l-flex-RC o-p-5 c-text-13 c-text-b">
+                    <div v-if="proportionCheck"
+                        style="padding: var(--van-cell-vertical-padding) var(--van-cell-horizontal-padding);">
+                        {{ $t('distributionSet.addDist.pendingRecord') }}
+                    </div>
+                    <div v-else style="padding: var(--van-cell-vertical-padding) var(--van-cell-horizontal-padding);">
+                        {{ $t('distributionSet.addDist.distInof') }}
+                    </div>
+                </div>
+            </div>
+            <div v-if="proportionCheck">
+                <div class="l-flex-RC"
+                    style="padding: var(--van-cell-vertical-padding) var(--van-cell-horizontal-padding);">
+                    <div class="c-text-13">
+                        &nbsp;&nbsp;手续费比例:
+                    </div>
+                    <div class="c-text-14 c-text-b c-text-color">{{ proportionCheck.proportion }}%</div>
+                </div>
+                <div class="l-flex-RC"
+                    style="padding: var(--van-cell-vertical-padding) var(--van-cell-horizontal-padding);">
+                    <div class="c-text-13">
+                        &nbsp;&nbsp;{{ $t('distributionSet.addDist.myDistProport') }}:
+                    </div>
+                    <div class="c-text-14 c-text-b c-text-color">{{ proportionCheck.adminProportion }}%</div>
+                </div>
+                <div v-if="proportionCheck.agencyId" class="l-flex-RC"
+                    style="padding: var(--van-cell-vertical-padding) var(--van-cell-horizontal-padding);">
+                    <div class="l-flex-RC o-pr-20">
+                        <div class="c-text-13">
+                            &nbsp;&nbsp;{{ $t('device.accountNoOfDistributorLabel') }}:
+                        </div>
+                        <div class="c-text-14 c-text-b c-text-color">{{ proportionCheck.agencyName }}</div>
+                    </div>
+                    <div class="l-flex-RC">
+                        <div class="c-text-13">
+                            &nbsp;&nbsp;{{ $t('device.distributionProportionLabel') }}:
+                        </div>
+                        <div class="c-text-14 c-text-b c-text-color">{{ proportionCheck.agencyProportion }}%</div>
+                    </div>
+                </div>
+                <div v-if="proportionCheck.merchantId" class="l-flex-RC"
+                    style="padding: var(--van-cell-vertical-padding) var(--van-cell-horizontal-padding);">
+                    <div class="l-flex-RC o-pr-20">
+                        <div class="c-text-13">
+                            &nbsp;&nbsp;{{ $t('device.accountNoOfDistributorLabel') }}:
+                        </div>
+                        <div class="c-text-14 c-text-b c-text-color">{{ proportionCheck.merchantName }}</div>
+                    </div>
+                    <div class="l-flex-RC">
+                        <div class="c-text-13">
+                            &nbsp;&nbsp;{{ $t('device.distributionProportionLabel') }}:
+                        </div>
+                        <div class="c-text-14 c-text-b c-text-color">{{ proportionCheck.merchantProportion }}%</div>
+                    </div>
+                </div>
+                <div v-if="proportionCheck.personageId" class="l-flex-RC"
+                    style="padding: var(--van-cell-vertical-padding) var(--van-cell-horizontal-padding);">
+                    <div class="l-flex-RC o-pr-20">
+                        <div class="c-text-13">
+                            &nbsp;&nbsp;{{ $t('device.accountNoOfDistributorLabel') }}:
+                        </div>
+                        <div class="c-text-14 c-text-b c-text-color">{{ proportionCheck.personageName }}</div>
+                    </div>
+                    <div class="l-flex-RC">
+                        <div class="c-text-13">
+                            &nbsp;&nbsp;{{ $t('device.distributionProportionLabel') }}:
+                        </div>
+                        <div class="c-text-14 c-text-b c-text-color">{{ proportionCheck.personageProportion }}%</div>
+                    </div>
+                </div>
+                <div style="margin: 50px;">
+                    <van-button round block type="primary" @click="cancelDistri(proportionCheck.id)">
+                        {{ $t('device.cancelForApproval') }}
+                    </van-button>
+                </div>
+            </div>
+            <div v-else>
+                <van-form show-error-message @submit="onSubmit">
+                    <div class="noPaddingTopCell l-flex-RC">
+                        <div class="c-text-13 c-text-b c-text-color" style="padding: 15px">
+                            &nbsp;&nbsp;手续费比例:
+                        </div>
+                        <div class="c-text-13 c-text-b c-text-color">{{ cofficentForm.distProp }}%</div>
+                    </div>
+                    <div class="l-flex-RC">
+                        <div class="c-text-13 c-text-b c-text-color" style="padding: 15px">
+                            &nbsp;&nbsp;{{ $t('distributionSet.addDist.myDistProport') }}:
+                        </div>
+                        <div class="c-text-13 c-text-b c-text-color">{{ myDistProp }}%</div>
+                    </div>
+                    <div v-for="(item, index) in distPropList" :key="index" class="kBordBott">
+                        <van-field colon :border="false" required v-model="item.name1" clearable label-width="110"
+                            name="name1" :label="$t('device.accountNoOfDistributorLabel')"
+                            :placeholder="$t('device.accountNoOfDistributorPlaceholder')"
+                            :rules="[{ required: true, message: $t('device.accountNoOfDistributorPlaceholder') }]" />
+                        <div class="l-flex-between noPaddingRCell">
+                            <div class="l-flex-RC">
+                                <van-field type="digit" colon :border="false" required v-model="item.name2" clearable
+                                    label-width="110" name="name2" :label="$t('device.distributionProportionLabel')"
+                                    :placeholder="$t('device.distributionProportionPlaceholder')"
+                                    @update:model-value="checkRatio(index)"
+                                    :rules="[{ required: true, message: $t('device.distributionProportionPlaceholder') }, { required: true, validator: distPropVali, message: $t('distributionSet.addDist.distPropRange'), trigger: ['onChange', 'onBlur', 'onSubmit'] }]" />
+                                <span class="o-pl-10 c-text-18 c-text-b" style="color: #434D74;">%</span>
+                            </div>
+                            <div @click="toDele(index)" class="l-flex-RC" style="color: #FE5D55;">
+                                <van-icon size="18" name="delete-o" />
+                                <span class="c-text-12">{{ $t('device.delete') }}</span>
+                            </div>
+                        </div>
+                    </div>
+                    <div v-if="distPropList.length <= 2" @click="toAdd"
+                        class="kBordBott l-flex-center o-ptb-20 c-text-14 c-text-w6">
+                        +{{ $t('device.continueToAddDistributors') }}
+                    </div>
+                    <div style="margin: 50px;">
+                        <van-button round block type="primary" native-type="submit">
+                            {{ $t('device.submitForApproval') }}
+                        </van-button>
+                    </div>
+                </van-form>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+import sHeader from "../../../components/SimpleHeader.vue";
+import { onMounted, reactive, computed, ref } from "vue";
+import { getTerminalProportion, submitProportion, getProportionCheck, checkProportion } from "../../../service/terminal";
+import { useRoute, useRouter } from "vue-router";
+import { showFailToast, showNotify, showSuccessToast, showConfirmDialog } from "vant";
+import { getLoginUser } from "@/common/js/utils";
+
+export default {
+    components: {
+        sHeader
+    },
+    setup() {
+        const user = getLoginUser();
+        const route = useRoute();
+        const router = useRouter();
+        const cofficentForm = reactive({
+            terminalNo: '',
+            distProp: 1,
+        });
+        // 分销人列表
+        const distPropList = reactive([]);
+        // 待审核记录
+        const proportionCheck = ref({});
+        // 获取是否有待审核记录
+        const getCheckPending = async () => {
+            const { data } = await getProportionCheck({ terminalId: route.query.terminalId });
+            if (data.code === '00000') {
+                // 存在审核记录,则不能再提交
+                proportionCheck.value = data.data;
+            }
+        }
+        // 获取分销比例
+        const getProportion = async () => {
+            const { data } = await getTerminalProportion(
+                Object.assign({}, { terminalId: route.query.terminalId })
+            );
+            if (data.code === "00000") {
+                cofficentForm.clientId = data.data.clientId;
+                cofficentForm.distProp = data.data.proportion;
+                // 存在第一个分销人账号和分销比,填充
+                if (data.data.agencyId && data.data.agencyProportion !== '') {
+                    distPropList[0] = {};
+                    distPropList[0]['name1'] = data.data.agencyId;
+                    distPropList[0]['name2'] = data.data.agencyProportion;
+                }// 存在第二个分销人账号和分销比,填充
+                if (data.data.merchantId && data.data.merchantProportion !== '') {
+                    distPropList[1] = {};
+                    distPropList[1]['name1'] = data.data.merchantId;
+                    distPropList[1]['name2'] = data.data.merchantProportion;
+                }// 存在第三个分销人账号和分销比,填充
+                if (data.data.personageId && data.data.personageProportion !== '') {
+                    distPropList[2] = {};
+                    distPropList[2]['name1'] = data.data.personageId;
+                    distPropList[2]['name2'] = data.data.personageProportion;
+                }
+            }
+
+        };
+        // 我的分销比例
+        const myDistProp = computed(() => {
+            // 计算出分销人的总分销
+            const totalProp = distPropList.reduce((pre, cur) => {
+                return Number(cur.name2 || 0) + pre;
+            }, 0);
+            const scaleValue = (100 - Number(cofficentForm.distProp || 0) - Number(totalProp));
+            return scaleValue;
+        });
+        // 点击添加分销人
+        const toAdd = () => {
+            distPropList.push({
+                name1: '',
+                name2: ''
+            })
+        }
+        // 点击删除
+        const toDele = (idx) => {
+            distPropList.splice(idx, 1);
+        }
+        // 分销比例规则
+        const distPropVali = (val) => /^(?:[1-9]|[1-9]\d)$/.test(val);
+        // 校验填写比例
+        const checkRatio = (index) => {
+            console.log(index);
+            if (myDistProp.value < 0) {
+                distPropList[index]['name2'] = 0;
+                showNotify({
+                    message: "分销总比例不能大于100",
+                    duration: 2000,
+                    background: '#f0ad4e',
+                });
+            }
+        }
+        // 提交
+        const onSubmit = async () => {
+            let param = {
+                adminId: user.id,
+                terminalId: route.query.terminalId,
+                terminalNo: cofficentForm.terminalNo,
+                type: distPropList.length + 1,
+                proportion: cofficentForm.distProp,
+                agencyName: distPropList[0] ? distPropList[0]['name1'] : '',
+                merchantName: distPropList[1] ? distPropList[1]['name1'] : '',
+                personageName: distPropList[2] ? distPropList[2]['name1'] : '',
+                agencyProportion: distPropList[0] ? distPropList[0]['name2'] : '',
+                merchantProportion: distPropList[1] ? distPropList[1]['name2'] : '',
+                personageProportion: distPropList[2] ? distPropList[2]['name2'] : '',
+                adminProportion: myDistProp.value,
+            }
+            const { data } = await submitProportion(
+                Object.assign({}, param)
+            );
+            if (data.code === "00000") {
+                showSuccessToast("提交成功");
+                setTimeout(() => {
+                    router.go(0);
+                }, 500);
+            } else {
+                showFailToast(data.message);
+            }
+        }
+        // 撤销审核
+        const cancelDistri = async (value) => {
+            showConfirmDialog({
+                title: '提醒',
+                message: '确认撤销此条分销申请吗?',
+            }).then(async () => {
+                const { data } = await checkProportion({ id: value, status: 2 });
+                if (data.code == "00000") {
+                    showSuccessToast('撤销成功');
+                    setTimeout(() => {
+                        router.go(0);
+                    }, 1000);
+                } else {
+                    showFailToast(data.message);
+                }
+            }).catch((error) => {
+                console.error(error);
+            })
+        }
+        onMounted(async () => {
+            cofficentForm.terminalNo = route.query.terminalNo;
+            getProportion();
+            getCheckPending();
+        });
+        return {
+            cofficentForm,
+            distPropList,
+            myDistProp,
+            toAdd,
+            toDele,
+            distPropVali,
+            checkRatio,
+            onSubmit,
+            proportionCheck,
+            cancelDistri
+        };
+    }
+};
+</script>
+<style lang="less" scoped>
+@import "../../../common/style/common.less";
+
+.distributionSetIdx {
+    .van-tabs--line .van-tabs__wrap {
+        height: 30px;
+    }
+
+    .van-pull-refresh {
+        height: calc(100vh - 120px);
+        overflow: auto;
+    }
+
+    .headCon {
+        .leftImg {
+            width: 19px;
+            height: 19px;
+            background: url('../../../assets/distributionSet/leftIcon.png') top center no-repeat;
+            background-size: 100%;
+        }
+
+        .leftTxt {
+            color: #434d74;
+
+            .leftNum {
+                padding-left: 5px;
+                color: #df5e4c;
+            }
+        }
+
+        .rightCon {
+            color: #4d6add;
+        }
+    }
+
+    .van-tabs__line {
+        background-color: #4d6add !important;
+    }
+
+    .van-tab--active .van-tab__text--ellipsis {
+        color: #4d6add;
+    }
+
+    .contentCon {
+        height: calc(100% - 120px);
+
+        .content {
+            margin-top: 6px;
+
+            .titleName {
+                color: #8787a6;
+            }
+
+            .valueName {
+                color: #404d74;
+            }
+
+            .valueName1 {
+                width: 90px;
+                display: inline-block;
+            }
+
+            .effective {
+                color: #4dc193;
+            }
+
+            .cancel {
+                color: #f5b33a;
+            }
+
+            .rejected {
+                color: #df5e4c;
+            }
+        }
+
+        .approval {
+            color: #f5b33a;
+        }
+
+        .cancelBtn {
+            height: 25px;
+            padding: 0 5px;
+        }
+    }
+}
+
+.distributionDetailIdx {
+    overflow: auto;
+
+    .kBordBott {
+        color: #404d74;
+    }
+
+    .noPaddingTopCell {
+        .van-cell {
+            padding-right: 0;
+            width: 250px;
+        }
+    }
+
+    .noPaddingRCell {
+        padding-right: var(--van-cell-horizontal-padding);
+
+        .van-cell {
+            padding-right: 0;
+            width: 250px;
+        }
+    }
+
+    .van-button--primary {
+        border-color: #4d6add;
+        background-color: #4d6add;
+    }
+}
+</style>

+ 148 - 0
src/views/terminal/index.vue

@@ -0,0 +1,148 @@
+<template>
+    <!-- MQTT管理 -->
+    <div class="taskMessagePage flex-col">
+        <s-header name="终端管理" :noback="false"></s-header>
+        <div class="taskMessageBox flex-col">
+            <!-- 终端列表 -->
+            <div class="taskListRow flex-col" @click="pushPageList('/terminalList')">
+                <div class="taskIcon topicIcon"></div>
+                <div class="taskRight">
+                    <div class="taskTitle">终端列表</div>
+                </div>
+            </div>
+            <!-- 订单管理 -->
+            <div class="taskListRow flex-col">
+                <div class="taskIcon orderIcon"></div>
+                <div class="taskRight">
+                    <div class="taskTitle">订单管理</div>
+                </div>
+            </div>
+            <!-- 分销管理 -->
+            <div class="taskListRow flex-col" @click="pushPageList('/check')">
+                <div class="taskIcon messageIcon"></div>
+                <div class="taskRight">
+                    <div class="taskTitle">分销管理</div>
+                </div>
+            </div>
+            <!-- 密钥管理 -->
+            <div class="taskListRow flex-col" @click="pushPageList('/secretKey')">
+                <div class="taskIcon keyIcon"></div>
+                <div class="taskRight">
+                    <div class="taskTitle">密钥管理</div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import { onMounted } from 'vue';
+import sHeader from "../../components/SimpleHeader.vue";
+import { useRouter } from "vue-router";
+
+export default {
+    components: { sHeader },
+    setup() {
+        const router = useRouter();
+        // 初始化页面获取列表
+        const pushPageList = (url) => {
+            router.push(url);
+        };
+        onMounted(async () => { });
+        return {
+            pushPageList,
+        };
+    }
+};
+</script>
+
+<style lang="less" scoped>
+@import "../../common/style/common.less";
+.taskMessagePage {
+    width: 100%;
+  
+    .taskMessageBox {
+      width: 100%;
+      height: calc(100% - 60px);
+      overflow: auto;
+  
+      .taskListRow {
+        height: 53px;
+        flex-wrap: wrap;
+  
+        .taskIcon {
+          width: 13%;
+          height: 100%;
+          position: relative;
+  
+          &.messageIcon::after {
+            content: '';
+            position: absolute;
+            background: #fff url('../../assets/mqtt/message.png') top center no-repeat;
+            background-size: 100%;
+            width: 0.6rem;
+            height: 0.6rem;
+            right: 0.18rem;
+            top: 0.45rem;
+          }
+
+          &.orderIcon::after {
+            content: '';
+            position: absolute;
+            background: #fff url('../../assets/mqtt/order.png') top center no-repeat;
+            background-size: 100%;
+            width: 0.55rem;
+            height: 0.55rem;
+            right: 0.20rem;
+            top: 0.45rem;
+          }
+
+          &.topicIcon::after {
+            content: '';
+            position: absolute;
+            background: #fff url('../../assets/mqtt/topic.png') top center no-repeat;
+            background-size: 100%;
+            width: 0.55rem;
+            height: 0.55rem;
+            right: 0.20rem;
+            top: 0.45rem;
+          }
+
+          &.keyIcon::after {
+            content: '';
+            position: absolute;
+            background: #fff url('../../assets/mqtt/key.png') top center no-repeat;
+            background-size: 100%;
+            width: 0.55rem;
+            height: 0.55rem;
+            right: 0.20rem;
+            top: 0.45rem;
+          }
+  
+        }
+  
+        .taskRight {
+          width: 87%;
+          height: 100%;
+          position: relative;
+          border-bottom: 1px solid #e7eaf7;
+  
+          &::after {
+            content: '';
+            position: absolute;
+            width: 6px;
+            height: 12px;
+            background: url('../../assets/accountOperation/right.png') top center no-repeat;
+            background-size: 100%;
+            right: 0.55rem;
+            top: 0.5rem;
+          }
+  
+          .taskTitle {
+            line-height: 53px;
+          }
+        }
+      }
+    }
+  }
+</style>

+ 249 - 0
src/views/terminal/list/index.vue

@@ -0,0 +1,249 @@
+<template>
+    <!-- 终端管理 -->
+    <div class="terminalListBox flex-col">
+        <s-header name="终端管理" :noback="false"></s-header>
+        <div class="searchRow flex-row justify-between">
+            <div class="flex-col">
+                <div class="flex-row justify-between bd3">
+                    <div class="flex-col outer4"></div>
+                    <span class="flex-col txt2">{{ $t('alarmHistory.common') }}<span class="discountNumber">{{
+            terminalTotal
+        }}</span>{{ $t('alarmHistory.recordsTotal') }}</span>
+                </div>
+            </div>
+            <div class="flex-col">
+                <div class="main5 flex-row justify-between" @click="showAdd = true">
+                    <img class="label2 o-mr-5" src="../../../assets/device/alarmClock_Add.png" />
+                </div>
+            </div>
+        </div>
+        <van-list v-model:loading="loading" v-model:error="error" :error-text="$t('alarmHistory.requestFailed')"
+            :finished="finished" :finished-text="$t('alarmHistory.noMore')" offset="300" :immediate-check="false"
+            @load="onLoad">
+            <div class="listBox">
+                <div v-for="(item, index) in terminalList" :key="index" class="listItem">
+                    <div class="container">
+                        <div class="itemBox">
+                            <div class="itemRow">
+                                <span class="itemTitle">
+                                    终端名称:&nbsp;
+                                </span>
+                                {{ item.name }}
+                            </div>
+                            <div class="itemRow">
+                                <span class="itemTitle">
+                                    终端编号:&nbsp;
+                                </span>
+                                {{ item.number }}
+                            </div>
+                        </div>
+                        <div>
+                            <van-button type="primary" style="padding: 10px;" @click="distribution(item)">分销</van-button>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </van-list>
+        <van-dialog v-model:show="showAdd" title="生成终端" show-cancel-button @confirm="addTerminal">
+            <van-field v-model="name" label="终端名称" placeholder="请填写终端名称" label-align="center" />
+        </van-dialog>
+    </div>
+</template>
+<script>
+import sHeader from "../../../components/SimpleHeader.vue";
+import { onMounted, reactive, ref, toRefs } from "vue";
+import { getTerminalList, generatingTerminal } from "../../../service/terminal";
+import { getLoginUser } from "@/common/js/utils";
+import { showFailToast, showNotify, showSuccessToast, } from "vant";
+import { useRouter } from "vue-router";
+
+
+export default {
+    components: { sHeader },
+    setup() {
+        const router = useRouter();
+        const user = getLoginUser();
+        const loading = ref(false); // 加载状态
+        const error = ref(false); // 错误状态
+        const finished = ref(false); // 结束翻页状态
+        const terminalTotal = ref(0); // 列表总数
+        const terminalList = ref([]); // 列表集合
+        const showAdd = ref(false); //弹窗展示
+        let searchParams = reactive({
+            adminId: "", // 当前登录账户的id
+            current: 1, // 当前页
+            size: 20, // 页大小
+            name: "", // 机器名称
+        });
+        // 获取设备列表
+        const getList = async () => {
+            const { data } = await getTerminalList(
+                Object.assign({}, searchParams)
+            );
+            if (data.code === "00000") {
+                // 列表值叠加
+                terminalList.value = terminalList.value.concat(
+                    data.data.records
+                );
+                terminalTotal.value = data.data.total;
+                if (terminalList.value.length === data.data.total) {
+                    finished.value = true;
+                }
+                loading.value = false;
+            } else {
+                showFailToast(data.message);
+            }
+        };
+        // 滚动加载
+        const onLoad = () => {
+            if (!finished.value) {
+                searchParams.current = searchParams.current + 1;
+                getList();
+            }
+        };
+        // 生成终端
+        const addTerminal = async () => {
+            if (searchParams.name == null || searchParams.name === "") {
+                showNotify({ type: 'warning', message: '请输入终端名称' });
+            } else {
+                const { data } = await generatingTerminal(
+                    Object.assign({}, searchParams)
+                );
+                if (data.code === "00000") {
+                    showSuccessToast("生成成功");
+                    setTimeout(() => {
+                        searchParams.current = 1;
+                        terminalList.value = [];
+                        getList();
+                    }, 500);
+                } else {
+                    showFailToast(data.message);
+                }
+            }
+        };
+        // 分销跳转
+        const distribution = (e) => {
+            router.push({ path: "distribution", query: { terminalId: e.id, terminalNo: e.number	} });
+        };
+        onMounted(async () => {
+            if (user) {
+                searchParams.adminId = user.id;
+                getList();
+            }
+        });
+
+        return {
+            loading,
+            error,
+            finished,
+            onLoad,
+            terminalTotal,
+            terminalList,
+            showAdd,
+            addTerminal,
+            distribution,
+            ...toRefs(searchParams),
+        };
+    },
+};
+</script>
+<style lang="less" scoped>
+@import "../../../common/style/common.less";
+
+.terminalListBox {
+    width: 100%;
+    height: calc(100% - 44px);
+    overflow: auto;
+
+    .searchRow {
+        width: 90%;
+        height: 48px;
+        margin: 0 auto;
+        background: rgba(255, 255, 255, 1) url("../../../assets/home/line.png") bottom center no-repeat;
+        background-size: 100%;
+        align-items: center;
+
+        .bd3 {
+            width: 87px;
+            height: 16px;
+
+            .outer4 {
+                width: 16px;
+                height: 20px;
+                background: url("../../../assets/alarmHistory/icon.png") top center no-repeat;
+                background-size: 100%;
+            }
+
+            .txt2 {
+                width: 65px;
+                height: 14px;
+                overflow-wrap: break-word;
+                color: rgba(64, 77, 116, 1);
+                font-size: 15px;
+                font-family: PingFangSC-Semibold;
+                text-align: left;
+                white-space: nowrap;
+                line-height: 15px;
+                display: block;
+                font-weight: bold;
+
+                .discountNumber {
+                    font-size: 18px;
+                    color: red;
+                }
+            }
+        }
+
+        .main5 {
+            width: auto;
+            cursor: pointer;
+
+            .label2 {
+                width: 20px;
+                height: 20px;
+                margin-right: 5px;
+            }
+        }
+    }
+
+    .listBox {
+        .listItem {
+            width: 100%;
+            background: url("../../../assets/home/line.png") bottom center no-repeat;
+            background-size: 100%;
+            position: relative;
+            display: inline-block;
+
+            .container {
+                display: flex;
+                justify-content: space-between;
+                /* 左右对齐 */
+                align-items: center;
+                /* 顶部对齐 */
+                margin: 20px;
+                /* 根据父容器宽度 */
+                .itemBox {
+                    flex: 1;
+                    font-size: 12px;
+                    line-height: 1.65;
+    
+                    .itemRow {
+                        width: 80%;
+                    }
+    
+                    .itemTitle {
+                        color: #8787a6;
+                    }
+    
+                }
+            }
+
+        }
+    }
+}
+
+.van-button--primary {
+    border-color: #4d6add;
+    background-color: #4d6add;
+}
+</style>

+ 0 - 0
src/views/terminal/order/index.vue


+ 139 - 0
src/views/terminal/secretKey/index.vue

@@ -0,0 +1,139 @@
+<template>
+    <!-- 密钥管理 -->
+    <div class="terminalListBox flex-col">
+        <s-header name="密钥管理" :noback="false"></s-header>
+        <div class="outer flex-col justify-center ">
+            <div class="l-flex-RC">
+                <div class="outer1 flex-col"></div>
+                <div class="TextGroup flex-col">
+                    <span class="txt">参数信息</span>
+                </div>
+            </div>
+        </div>
+        <van-cell-group inset>
+            <van-field v-model="merichantInfo.id" label="sys_id"
+                :placeholder="merichantInfo.id == null ? '未生成' : merichantInfo.id" :readonly=true >
+                <template v-if="merichantInfo.id != null" #button>
+                    <van-button size="small" type="primary" style="padding: 5px;" @click="copyText(merichantInfo.id)">复制</van-button>
+                </template>
+            </van-field>
+        </van-cell-group>
+        <div class="outer flex-col justify-center ">
+            <div class="l-flex-RC">
+                <div class="outer1 flex-col"></div>
+                <div class="TextGroup flex-col">
+                    <span class="txt">密钥信息</span>
+                </div>
+            </div>
+        </div>
+        <van-cell-group inset>
+            <van-field v-model="merichantInfo.publicKey" rows="5" label="商户公钥" type="textarea" :autosize="{ maxHeight: 150 }"
+                :placeholder="merichantInfo.publicKey == null ? '未生成' : merichantInfo.publicKey" :readonly=true>
+                <template v-if="merichantInfo.publicKey != null" #button>
+                    <van-button size="small" type="primary" style="padding: 5px;" @click="copyText(merichantInfo.publicKey)">复制</van-button>
+                </template></van-field>
+            <van-field v-model="merichantInfo.privateKey" rows="5" label="商户私钥" type="textarea" :autosize="{ maxHeight: 150 }"
+                :placeholder="merichantInfo.privateKey == null ? '未生成' : merichantInfo.privateKey" :readonly=true>
+                <template v-if="merichantInfo.privateKey != null" #button>
+                    <van-button size="small" type="primary" style="padding: 5px;" @click="copyText(merichantInfo.privateKey)">复制</van-button>
+                </template>
+            </van-field>
+            <br>
+        </van-cell-group>
+        <div style="margin: 10px 100px;" v-if="merichantInfo.id == null">
+            <van-button round block type="primary" native-type="submit" @click="generateMerchantSecretkey">
+                生成
+            </van-button>
+        </div>
+    </div>
+</template>
+<script>
+import { ref } from "vue";
+import sHeader from "../../../components/SimpleHeader.vue";
+import { getSecretKey, generateSecretKey } from "../../../service/terminal";
+import { getLoginUser } from "@/common/js/utils";
+import { onMounted } from "vue";
+import { useRouter } from "vue-router";
+import { showSuccessToast } from "vant";
+
+
+export default {
+    components: { sHeader },
+    setup() {
+        const user = getLoginUser();
+        const router = useRouter();
+        const merichantInfo = ref({});
+        // 获取密钥
+        const getMerchantSecretkey = async () => {
+            const { data } = await getSecretKey({
+                adminId: user.id,
+            });
+            if (data.code === "00000") {
+                if (data.data !== null) {
+                    merichantInfo.value = data.data;
+                }
+            }
+        };
+        // 生成密钥
+        const generateMerchantSecretkey = async () => {
+            const { data } = await generateSecretKey({
+                adminId: user.id,
+            });
+            if (data.code === "00000") {
+                showSuccessToast("生成成功");
+                setTimeout(() => {
+                    router.go(0);
+                }, 1000);
+            }
+        };
+        // 复制密钥
+        const copyText = (text) => {
+            navigator.clipboard.writeText(text);
+            showSuccessToast("复制成功");
+        };
+
+        onMounted(async () => {
+            getMerchantSecretkey();
+        });
+
+        return {
+            merichantInfo,
+            copyText,
+            generateMerchantSecretkey
+        };
+    },
+};
+</script>
+<style lang="less" scoped>
+@import "../../../common/style/common.less";
+
+.outer {
+    background: rgba(255, 255, 255, 1) url("../../../assets/home/line.png") bottom center no-repeat;
+    background-size: 100% auto;
+    padding: 20px 20px;
+
+    .outer1 {
+        position: relative;
+        width: 15px;
+        height: 15px;
+        margin-right: 5px;
+        background: url("../../../assets/home/machineSales.png") center no-repeat;
+        background-size: 100%;
+    }
+
+    .TextGroup {
+
+        .txt {
+            overflow-wrap: break-word;
+            color: rgba(64, 77, 116, 1);
+            font-size: 0.4rem;
+            font-family: PingFangSC-Semibold;
+            text-align: left;
+            white-space: nowrap;
+            line-height: 0.4rem;
+            display: block;
+        }
+
+    }
+}
+</style>

+ 46 - 30
src/views/user.vue

@@ -235,12 +235,20 @@
           </div>
 
           <!-- 提现帐号 -->
-          <div v-if="isInland && (user.type == 2 || user.type == 3)" class="taskListRow l-flex-RC" @click="pushPageList('/settlement')">
+          <div v-if="isInland && (user.type == 2 || user.type == 3)" class="taskListRow l-flex-RC"
+            @click="pushPageList('/settlement')">
             <div class="taskIcon joinPayMchIcon"></div>
             <div class="taskRight">
               <div class="taskTitle">{{ $t("user.settlementAccount") }}</div>
             </div>
           </div>
+          <!-- 提现帐号 -->
+          <div v-if="user.type == 0" class="taskListRow l-flex-RC" @click="pushPageList('/bindBankCard')">
+            <div class="taskIcon joinPayMchIcon"></div>
+            <div class="taskRight">
+              <div class="taskTitle">绑定银行卡</div>
+            </div>
+          </div>
 
           <!-- 公告编辑 -->
           <div v-if="user.type == '0'" class="taskListRow l-flex-RC" @click="pushPageList('/announcement')">
@@ -851,44 +859,52 @@ export default {
     const name = ref("");
     // 国内省市
     const getArea = async () => {
-      const { data } = await getAreaById({
-        areaId: areaId.value,
-      });
-      if (data.code === "00000") {
-        fullName.value = data.data.fullName;
-        name.value = data.data.name;
-        if (fullName.value != name.value) {
-          fullName.value = fullName.value.replace(name.value, "").trim();
-          fullName.value = fullName.value + "/" + name.value;
+      try {        
+        const { data } = await getAreaById({
+          areaId: areaId.value,
+        });
+        if (data.code === "00000") {
+          fullName.value = data.data.fullName;
+          name.value = data.data.name;
+          if (fullName.value != name.value) {
+            fullName.value = fullName.value.replace(name.value, "").trim();
+            fullName.value = fullName.value + "/" + name.value;
+          }
+          fieldValue.value = fullName.value;
         }
-        fieldValue.value = fullName.value;
+      } catch (error) {
+        console.error(error);
       }
     };
     const countryValue = ref("");
     const cityValue = ref("");
     // 国外城市
     const getCities = async () => {
-      const { data } = await getCitiesById({
-        areaId: areaId.value,
-      });
-      if (data.data != "") {
-        const citiesCode = data.data.split('/')[0];
-        const countriesCode = data.data.split('/')[1];
-        countryOptions.value.find(item => {
-          if (item.value === countriesCode) {
-            countryValue.value = item.text;
-            item.children.find(item => {
-              if (item.value === citiesCode) {
-                cityValue.value = item.text;
-              }
-            });
-          }
+      try {
+        const { data } = await getCitiesById({
+          areaId: areaId.value,
         });
-        if (countryValue.value == cityValue.value) {
-          fieldValue.value = cityValue.value;
-        } else {
-          fieldValue.value = countryValue.value + "/" + cityValue.value;
+        if (data.data != "") {
+          const citiesCode = data.data.split('/')[0];
+          const countriesCode = data.data.split('/')[1];
+          countryOptions.value.find(item => {
+            if (item.value === countriesCode) {
+              countryValue.value = item.text;
+              item.children.find(item => {
+                if (item.value === citiesCode) {
+                  cityValue.value = item.text;
+                }
+              });
+            }
+          });
+          if (countryValue.value == cityValue.value) {
+            fieldValue.value = cityValue.value;
+          } else {
+            fieldValue.value = countryValue.value + "/" + cityValue.value;
+          }
         }
+      } catch (error) {
+        console.error(error);
       }
     };