DESKTOP-SVI9JE1\muzen 1 سال پیش
والد
کامیت
fd2e4e8943

+ 17 - 0
src/api/main.js

@@ -6,4 +6,21 @@ export function address() {
     url: `/oms/exchange/query/province/city/area`,
     method: 'get'
   })
+}
+
+// 店铺
+export function store() {
+  return request({
+    url: `/oms/exchange/query/store`,
+    method: 'get'
+  })
+}
+
+// 产品型号
+export function goods(query) {
+  return request({
+    url: `/oms/reissue/goods/page`,
+    method: 'get',
+    params: query
+  })
 }

+ 9 - 0
src/api/mobile/order.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request' 
+
+// 列表
+export function list(mobile) {
+  return request({
+    url: `/oms/repairrecordOrder/searchByphone/${mobile}`,
+    method: 'get'
+  })
+}

+ 10 - 0
src/api/mobile/repair.js

@@ -0,0 +1,10 @@
+import request from "@/utils/request"
+
+// 推送
+export function submit(data) {
+  return request({
+    url: `/oms/repairrecordOrder/add`,
+    method: 'post',
+    data
+  })
+}

+ 2 - 2
src/api/mobile/apply.js

@@ -1,9 +1,9 @@
-import request from '@/utils/request'
+import request from "@/utils/request"
 
 // 维修申请
 export function submit(data) {
   return request({
-    url: `/oms/exchange/push`,
+    url: `/oms/exchange/save`,
     method: 'post',
     data
   })

+ 18 - 0
src/api/service/repair.js

@@ -0,0 +1,18 @@
+import request from "@/utils/request";
+
+// 列表
+export function list(query) {
+  return request({
+    url: `/oms/repairrecordOrder/list`,
+    method: "get",
+    params: query,
+  });
+}
+
+// 审核
+export function change(id, status) {
+  return request({
+    url: `/oms/repairrecordOrder/hitOrSold/${id}/${status}`,
+    method: "get"
+  })
+}

+ 19 - 0
src/api/service/replace.js

@@ -0,0 +1,19 @@
+import request from '@/utils/request'
+
+// 列表
+export function list(data) {
+  return request({
+    url: `/oms/exchange/queryPage`,
+    method: 'post',
+    data
+  }) 
+}
+
+// 推送
+export function push(data) {
+  return request({
+    url: `/oms/exchange/exchangePush`,
+    method: 'post',
+    data
+  })
+}

+ 11 - 2
src/api/service/resend.js

@@ -9,11 +9,20 @@ export function list(query) {
   });
 }
 
-// 推送
+// 新增
 export function submit(data) {
   return request({
-    url: `/oms/reissue/push`,
+    url: `/oms/reissue/save`,
     method: "post",
     data
   });
 }
+
+// 推送
+export function push(data) {
+  return request({
+    url: `/oms/reissue/reissuePush`,
+    method: 'post',
+    data
+  })
+} 

src/api/tool/gen.js → src/api/system/tool/gen.js


+ 22 - 1
src/assets/styles/index.scss

@@ -132,7 +132,28 @@ aside {
 }
 
 .pagination-container {
-  margin-top: 30px;
+  display: flex;
+  justify-content: center;
+  // margin: 16px 0;
+}
+
+.el-pagination.is-background .btn-prev,
+.el-pagination.is-background .btn-next,
+.el-pagination.is-background .el-pager li {
+  min-width: 30px;
+  height: 30px;
+  line-height: 30px;
+  background: none;
+  border: 1px solid #d9d9d9;
+}
+
+.el-pagination.is-background .btn-prev,
+.el-pagination.is-background .btn-next {
+  color: rgba(0, 0, 0, 0.25);
+}
+
+.el-pagination.is-background .el-pager li {
+  color: rgba(0, 0, 0, 0.65);
 }
 
 .text-center {

+ 5 - 5
src/assets/styles/ruoyi.scss

@@ -105,8 +105,8 @@
     position: relative;
     height: 25px;
     margin-bottom: 10px;
-    margin-top: 15px;
-    padding: 10px 20px !important;
+    // margin-top: 15px;
+    // padding: 10px 20px !important;
 }
 
 .el-dialog .pagination-container {
@@ -123,8 +123,8 @@
 }
 
 .pagination-container .el-pagination {
-	right: 0;
-	position: absolute;
+	// right: 0;
+	// position: absolute;
 }
 
 @media ( max-width : 768px) {
@@ -278,4 +278,4 @@
 /* 表格右侧工具栏样式 */
 .top-right-btn {
 	margin-left: auto;
-}
+}

+ 1 - 1
src/components/DictTag/index.vue

@@ -13,7 +13,7 @@
           :disable-transitions="true"
           :key="item.value + ''"
           :index="index"
-          :type="item.elTagType === 'primary' ? '' : item.elTagType"
+          :type="item.elTagType == 'primary' ? null : item.elTagType"
           :class="item.elTagClass"
         >{{ item.label + " " }}</el-tag>
       </template>

+ 1 - 1
src/components/Pagination/index.vue

@@ -96,7 +96,7 @@ function handleCurrentChange(val) {
 
 <style scoped>
 .pagination-container {
-  background: #fff;
+  /* background: #fff; */
   padding: 32px 16px;
 }
 .pagination-container.hidden {

+ 46 - 0
src/components/Steps/index.vue

@@ -0,0 +1,46 @@
+<template>
+  <div style="margin-bottom: 20px;">
+    <div>售后进度:</div>
+    <el-steps style="max-width: 600px" :active="1" finish-status="success">
+      <el-step v-for="item in data.steps" :title="item">
+        <template #icon>
+          <i class="spot el-step__line-inner" />
+        </template>
+      </el-step>
+    </el-steps>
+  </div>
+</template>
+
+<script setup>
+const data = reactive({
+  // 进度条
+  steps: ['待质检', '质检完成', '待维修', '维修中', '维修完成', '已发货'],
+})
+</script>
+
+<style lang="scss" scoped>
+:deep(.el-steps) {
+  .el-step__head {
+    margin-left: 6px;
+  }
+
+  .el-step__title {
+    font-size: 10px;
+    line-height: 1;
+  }
+
+  .el-step__icon {
+    width: 20px;
+    position: absolute;
+  }
+
+  .el-step__main {
+    margin-top: 30px;
+  }
+}
+
+.spot {
+  transform: scale(3);
+  border-radius: 50%;
+}
+</style>

+ 12 - 10
src/components/Upload/index.vue

@@ -1,8 +1,8 @@
 <template>
-  <el-upload ref="upload" :action="url ? url : reactiveData.action[listType]" :headers="reactiveData.headers"
-    :list-type="listType" name="multipartFile" :multiple="multiple" :data="data" :accept="accept"
-    :show-file-list="showFileList" :before-upload="beforeUpload" :on-success="onSuccess" :on-error="onError"
-    :before-remove="beforeRemove" :on-remove="handleRemove" :disabled="disabled">
+  <el-upload ref="upload" :action="action" :headers="reactiveData.headers" :list-type="listType" name="file"
+    :multiple="multiple" :data="data" :accept="accept" :show-file-list="showFileList" :before-upload="beforeUpload"
+    :on-success="onSuccess" :on-error="onError" :before-remove="beforeRemove" :on-remove="handleRemove"
+    :disabled="disabled">
     <div class="image" v-if="listType === 'picture-card'">
       <el-icon v-if="src === ''" size="28">
         <Plus />
@@ -64,11 +64,9 @@ const props = defineProps({
 // 上传地址
 const baseUrl = ref(import.meta.env.VITE_APP_BASE_API)
 
+const action = ref(`${baseUrl.value}/common/upload`)
+
 const reactiveData = reactive({
-  action: {
-    'text': `${baseUrl.value}/system/file/file/upload`,
-    'picture-card': `${baseUrl.value}/system/file/picture/upload`
-  },
   headers: { Authorization: "Bearer " + getToken() },
   // 上传文件
   form: [],
@@ -91,14 +89,14 @@ function beforeUpload(file) {
 
 // 上传成功
 function onSuccess(file) {
-  if (file.code === 0) {
+  if (file.code === 200) {
     loading.value = false
     type.value = 'success'
     title.value = '上传成功'
     if (props.multiple) {
       file.data.map(i => reactiveData.form.push(i))
     } else {
-      reactiveData.form.file = file.data
+      reactiveData.form.data = file
     }
     proxy.$emit('upload', reactiveData.form)
   } else {
@@ -146,5 +144,9 @@ defineExpose({
   display: flex;
   justify-content: center;
   align-items: center;
+
+  .el-image{
+    height: 100%;
+  }
 }
 </style>

+ 56 - 3
src/hooks/index.js

@@ -1,15 +1,68 @@
-import { address } from "@/api/main";
+import { address, store, goods } from "@/api/main";
 
+// 省市区
 export function useAddress() {
   const addressOptions = ref([]);
-
   const getAddress = () => {
     address().then((res) => {
       if (res.code === 0) {
-        addressOptions.value = res.data
+        addressOptions.value = res.data;
       }
     });
   };
 
   return { addressOptions, getAddress };
 }
+
+// 店铺
+export function useStore() {
+  const storeOptions = ref([]);
+  const getStore = () => {
+    store().then((res) => {
+      if (res.code === 0) {
+        storeOptions.value = res.data.records;
+      }
+    });
+  };
+  return { storeOptions, getStore };
+}
+
+// 产品型号
+export function useGoods() {
+  const goodsForm = ref({
+    pageNum: 1,
+    pageSize: 10,
+  });
+  const goodsOptions = ref([]);
+  const getGoods = () => {
+    goods(goodsForm.value).then((res) => {
+      if (res.code === 0) {
+        goodsOptions.value = res.data.records;
+      }
+    });
+  };
+  return { goodsForm, goodsOptions, getGoods };
+}
+
+// 非接口共用
+export function useCommon() {
+  // 推送状态
+  const pushStatusOptions = ref([
+    { value: 0, label: "待推送" },
+    { value: 1, label: "成功" },
+    { value: 2, label: "失败" },
+  ]);
+  // 售后类型
+  const applyTypeOptions = ref([
+    { value: 1, label: "补发" },
+    { value: 2, label: "换新" },
+    { value: 3, label: "维修" },
+  ]);
+  // 维修审核
+  const stepStatusOptions = ref([
+    { value: 1, label: "审核通过" },
+    { value: 2, label: "审核失败" },
+    { value: 3, label: "待审核" }
+  ]);
+  return { pushStatusOptions, applyTypeOptions, stepStatusOptions };
+}

+ 7 - 3
src/router/index.js

@@ -92,9 +92,13 @@ export const constantRoutes = [
       component: () => import('@/views/mobile/service'),
       name: 'Service'
     }, {
-      path: 'apply',
-      component: () => import('@/views/mobile/apply'),
-      name: 'Apply'
+      path: 'replace',
+      component: () => import('@/views/mobile/replace'),
+      name: 'Replace'
+    }, {
+      path: 'repair',
+      component: () => import('@/views/mobile/repair'),
+      name: 'Repair'
     }, {
       path: 'order',
       component: () => import('@/views/mobile/order'),

+ 0 - 167
src/views/mobile/apply.vue

@@ -1,167 +0,0 @@
-<template>
-  <div class='app-container'>
-    <div v-if="data.form.id" style="margin-bottom: 20px;">
-      <div>售后进度:</div>
-      <el-steps style="max-width: 600px" :active="1" finish-status="success">
-        <el-step v-for="item in data.steps" :title="item">
-          <template #icon>
-            <i class="spot el-step__line-inner" />
-          </template>
-        </el-step>
-      </el-steps>
-    </div>
-    <el-form :model="data.form" :rules="data.rules" ref="form" label-width="auto">
-      <el-form-item label="买家昵称" prop="buyerNick">
-        <el-input v-model="data.form.buyerNick" placeholder="请输入买家昵称" />
-      </el-form-item>
-      <el-form-item label="收货人" prop="contact">
-        <el-input v-model="data.form.contact" placeholder="请输入收货人名称" />
-      </el-form-item>
-      <el-form-item label="手机号" prop="mobile">
-        <el-input v-model="data.form.mobile" placeholder="请输入手机号" />
-      </el-form-item>
-      <el-form-item label="收货地址" prop="provinceName">
-        <div class="address">
-          <el-select v-model="data.form.provinceName" placeholder="省">
-            <el-option v-for="item in addressOptions" :key="item.id" :value="item.name" :label="item.name" />
-          </el-select>
-          <span>/</span>
-          <el-select v-model="data.form.cityName" placeholder="市">
-            <el-option v-for="item in cityOptions" :key="item.id" :value="item.name" :label="item.name" />
-          </el-select>
-          <span>/</span>
-          <el-select v-model="data.form.areaName" placeholder="区">
-            <el-option v-for="item in areaOptions" :key="item.id" :value="item.name" :label="item.name" />
-          </el-select>
-        </div>
-      </el-form-item>
-      <el-form-item label="详细地址" prop="address">
-        <el-input v-model="data.form.address" type="textarea" :autosize="{ minRows: 5 }" placeholder="请输入详细地址" />
-      </el-form-item>
-      <el-form-item label="数量" prop="quantity">
-        <el-input-number v-model="data.form.quantity" :min="1" />
-      </el-form-item>
-    </el-form>
-    <el-button class="submit" type="primary" round @click="getSubmit">提交</el-button>
-  </div>
-</template>
-
-<script setup>
-import { submit } from '@/api/mobile/apply'
-import { useAddress } from '@/hooks/index'
-const { addressOptions, getAddress } = useAddress()
-
-const { proxy } = getCurrentInstance()
-
-const data = reactive({
-  // 表单
-  form: {
-    shopCode: "A100001",
-    quantity: 0,
-    oid: "",
-    outSkuId: 564
-  },
-  // 进度条
-  steps: ['待质检', '质检完成', '待维修', '维修中', '维修完成', '已发货'],
-  // 校验
-  rules: {
-    buyerNick: [{ required: true, message: '请输入买家昵称', trigger: 'blur' }],
-    contact: [{ required: true, message: '请输入收货人姓名', trigger: 'blur' }],
-    mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
-    provinceName: [{ required: true, message: '请选择收货地址', trigger: 'change' }],
-    address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
-    quantity: [{ required: true, message: '请输入数量', trigger: 'blur' }],
-  }
-})
-
-// 计算属性
-const cityOptions = computed(() => {
-  return data.form.provinceName ? addressOptions.value.find(i => i.name == data.form.provinceName).childList : []
-})
-
-const areaOptions = computed(() => {
-  return data.form.cityName ? cityOptions.value.find(i => i.name == data.form.cityName).childList : []
-})
-
-// 提交
-const getSubmit = () => {
-  proxy.$refs.form.validate((valid) => {
-    if (valid) {
-      submit({ exchangeApplyOrderList: [data.form] }).then(res => {
-        if (res.code === 0) {
-          proxy.$modal.msgSuccess('提交成功!')
-          proxy.$refs.form.resetFields()
-          data.form = {
-            shopCode: "A100001",
-            quantity: 0,
-            oid: "",
-            outSkuId: 564
-          }
-        }
-      })
-    } else {
-      return false
-    }
-  })
-}
-
-onMounted(() => {
-  document.title = '换新申请'
-  getAddress()
-})
-</script>
-
-<style lang="scss" scoped>
-:deep(.el-steps) {
-  .el-step__head {
-    margin-left: 6px;
-  }
-
-  .el-step__title {
-    font-size: 10px;
-    line-height: 1;
-  }
-
-  .el-step__icon {
-    width: 20px;
-    position: absolute;
-  }
-
-  .el-step__main {
-    margin-top: 30px;
-  }
-}
-
-.spot {
-  transform: scale(3);
-  border-radius: 50%;
-}
-
-.el-form {
-  .info {
-    line-height: 1;
-    margin-top: 10px;
-    font-size: 8.5px;
-    opacity: 0.5;
-  }
-
-  .el-image {
-    width: 146px;
-  }
-
-  .address {
-    width: 100%;
-    display: flex;
-    align-items: center;
-
-    span {
-      margin: 0 4px
-    }
-  }
-}
-
-.submit {
-  width: 100%;
-  height: 40px;
-}
-</style>

+ 54 - 17
src/views/mobile/order.vue

@@ -1,42 +1,79 @@
 <template>
   <div class='app-container'>
-    <div class="list" v-for="item in 3" :key="item.id">
+    <el-form v-if="isCookie" label-position="top">
+      <el-form-item label="申请查询">
+        <el-input v-model="data.form.mobile" placeholder="请输入需要查询的手机号" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="getList">查询</el-button>
+      </el-form-item>
+    </el-form>
+    <div v-else class="list" v-for="item in data.tableData" :key="item.id">
       <div class="header between">
-        <span>寄回单号:GDHxxxxxxxx</span>
-        <span>换新</span>
+        <span>快递单号:{{ item.logisticsCode }}</span>
+        <span>{{ proxy.selectDictLabel(applyTypeOptions, item.type) }}</span>
       </div>
       <el-descriptions class="main" :column="1">
-        <el-descriptions-item label="姓名:"></el-descriptions-item>
-        <el-descriptions-item label="产品型号:"></el-descriptions-item>
-        <el-descriptions-item label="电话号码:"></el-descriptions-item>
-        <el-descriptions-item label="颜色:"></el-descriptions-item>
+        <el-descriptions-item label="姓名:">{{ item.name }}</el-descriptions-item>
+        <el-descriptions-item label="产品型号:">{{ item.goodsName }}</el-descriptions-item>
+        <el-descriptions-item label="电话号码:">{{ item.mobile }}</el-descriptions-item>
       </el-descriptions>
       <div class="footer between">
-        <span>填写时间:2024-05-24 14:00</span>
-        <span>仓库已发货</span>
+        <span>填写时间:{{ item.createTime }}</span>
+        <span>{{ proxy.selectDictLabel(stepStatusOptions, item.status) }}</span>
       </div>
     </div>
   </div>
 </template>
 
 <script setup>
-import { onMounted } from 'vue';
+import { list } from "@/api/mobile/order"
+import { useCommon } from "@/hooks/index"
+
+const { applyTypeOptions, stepStatusOptions } = useCommon()
+
+const { proxy } = getCurrentInstance()
+
+document.title = '申请查询'
+
+const data = reactive({
+  form: {},
+  tableData: []
+})
+
+// 是否输入手机号
+const isCookie = ref(true)
+// 遮罩层
+const loading = ref(false)
+
+// 列表
+const getList = () => {
+  loading.value = true
+  list(data.form.mobile).then(res => {
+    if (res.code === 0) {
+      data.tableData = res.data
+      loading.value = false
+      isCookie.value = false
+      sessionStorage.setItem('mobile', data.form.mobile)
+    }
+  })
+}
 
 onMounted(() => {
-  document.title = '申请查询'
+  data.form.mobile = sessionStorage.getItem('mobile')
+  isCookie.value = data.form.mobile ? false : true
+  if(!isCookie.value){
+    getList()
+  }
 })
 </script>
 
 <style lang="scss" scoped>
-.app-container {
-  background-color: #f7f7f7;
-}
-
 .list {
   border-radius: 8px;
   overflow: hidden;
-  background-color: #FFF;
   margin-bottom: 15px;
+  border: 1px solid #d0d0d0;
 }
 
 .header {
@@ -52,7 +89,7 @@ onMounted(() => {
 
 .footer {
   padding: 12px 10px;
-  border-top: 1px solid #f7f7f7;
+  border-top: 1px solid #d0d0d0;
   font-size: 14px;
 }
 

+ 186 - 0
src/views/mobile/repair.vue

@@ -0,0 +1,186 @@
+<template>
+  <div class='app-container' v-loading="loading">
+    <el-form :model="data.form" :rules="data.rules" ref="form" label-width="auto">
+      <el-form-item label="收货人" prop="receiverName">
+        <el-input v-model="data.form.receiverName" placeholder="请输入收货人" />
+      </el-form-item>
+      <el-form-item label="手机号" prop="mobile">
+        <el-input v-model="data.form.mobile" placeholder="请输入手机号" />
+      </el-form-item>
+      <el-form-item class="address" label="收货地址" required>
+        <el-form-item prop="province">
+          <el-select v-model="data.form.province" placeholder="省">
+            <el-option v-for="item in addressOptions" :key="item.id" :value="item.name" :label="item.name" />
+          </el-select>
+        </el-form-item>
+        <span>/</span>
+        <el-form-item prop="city">
+          <el-select v-model="data.form.city" placeholder="市">
+            <el-option v-for="item in cityOptions" :key="item.id" :value="item.name" :label="item.name" />
+          </el-select>
+        </el-form-item>
+        <span>/</span>
+        <el-form-item>
+          <el-select v-model="data.form.district" placeholder="区">
+            <el-option v-for="item in areaOptions" :key="item.id" :value="item.name" :label="item.name" />
+          </el-select>
+        </el-form-item>
+      </el-form-item>
+      <el-form-item label="详细地址" prop="address">
+        <el-input v-model="data.form.address" type="textarea" :autosize="{ minRows: 5 }" placeholder="请输入详细地址" />
+      </el-form-item>
+      <el-form-item label="维修数量" prop="repairQuantity">
+        <el-input-number v-model="data.form.repairQuantity" :min="1" />
+      </el-form-item>
+      <el-form-item label="产品型号" prop="specCode">
+        <el-select v-model="data.form.specCode" filterable remote :remote-method="remoteMethod" placeholder="请选择产品型号">
+          <el-option v-for="item in goodsOptions" :key="item.goodsId" :value="item.goodsId" :label="item.goodsName" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="物流公司" prop="logisticsName">
+        <el-input v-model="data.form.logisticsName" placeholder="请输入物流公司" />
+      </el-form-item>
+      <el-form-item label="快递单号" prop="logisticsCode">
+        <el-input v-model="data.form.logisticsCode" placeholder="请输入快递单号(示例:SF)" />
+      </el-form-item>
+      <el-form-item label="购买渠道" prop="shopCode">
+        <el-select v-model="data.form.shopCode" prop="shopCode" placeholder="请选择购买渠道" @change="handleChangeShopCode">
+          <el-option v-for="item in storeOptions" :key="item.storeCode" :value="item.storeCode"
+            :label="item.storeName" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="购买凭证" prop="proofPurchase">
+        <CustomUpload list-type="picture-card" :src="data.form.proofPurchase" @upload="upload" />
+        <div>
+          <div>示例:</div>
+          <el-image :src="data.img[0]" :preview-src-list="data.img" />
+        </div>
+      </el-form-item>
+    </el-form>
+    <el-button class="submit" type="primary" round @click="getSubmit">提交</el-button>
+  </div>
+</template>
+
+<script setup>
+import Steps from '@/components/Steps'
+import { submit } from '@/api/mobile/repair'
+import { useAddress, useStore, useGoods } from '@/hooks/index'
+const { addressOptions, getAddress } = useAddress()
+const { storeOptions, getStore } = useStore()
+const { goodsForm, goodsOptions, getGoods } = useGoods()
+const { proxy } = getCurrentInstance()
+
+document.title = '维修申请'
+
+const data = reactive({
+  form: {
+    province: "",
+    city: "",
+    district: "",
+    repairQuantity: 1
+  },
+  // 校验
+  rules: {
+    shopCode: [{ required: true, message: '请选择购买渠道', trigger: 'change' }],
+    receiverName: [{ required: true, message: '请输入收货人姓名', trigger: 'blur' }],
+    mobile: [{ required: true, pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
+    province: [{ required: true, message: '请选择省', trigger: 'change' }],
+    city: [{ required: true, message: '请选择市', trigger: 'change' }],
+    address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
+    repairQuantity: [{ required: true, message: '请输入数量', trigger: 'blur' }],
+    specCode: [{ required: true, message: '请选择产品型号', trigger: 'change' }],
+    logisticsName: [{ required: true, message: '请输入物流公司', trigger: 'blur' }],
+    logisticsCode: [{ required: true, message: '请输入快递单号', trigger: 'blur' }],
+    proofPurchase: [{ required: true, message: '请上传购买凭证', trigger: 'change' }]
+  },
+  // 购买凭证模板
+  img: [new URL(`../../assets/images/example.jpg`, import.meta.url).href]
+})
+
+// 遮罩层
+const loading = ref(false)
+
+// 计算属性
+const cityOptions = computed(() => {
+  data.form.city = ""
+  data.form.district = ""
+  return data.form.province ? addressOptions.value.find(i => i.name == data.form.province).childList : []
+})
+
+const areaOptions = computed(() => {
+  data.form.district = ""
+  return data.form.city ? cityOptions.value.find(i => i.name == data.form.city).childList : []
+})
+
+// 搜索产品型号
+const remoteMethod = (e) => {
+  goodsForm.value.goodsName = e
+  getGoods()
+}
+
+// 上传图片
+const upload = (file) => {
+  data.form.proofPurchase = file.data.url
+}
+
+// 购买渠道
+const handleChangeShopCode = (e) => {
+  data.form.shopNick = storeOptions.value.find(i => i.storeCode == e).storeName
+}
+
+// 提交
+const getSubmit = () => {
+  proxy.$refs.form.validate((valid) => {
+    if (valid) {
+      loading.value = true
+      submit(data.form).then(res => {
+        if (res.code === 200) {
+          proxy.$modal.msgSuccess('提交成功!')
+          proxy.$refs.form.resetFields()
+          data.form = {
+            province: "",
+            city: "",
+            district: "",
+            repairQuantity: 1
+          }
+          loading.value = false
+        }
+      })
+    } else {
+      return false
+    }
+  })
+}
+
+getAddress()
+getGoods()
+getStore()
+</script>
+
+<style lang="scss" scoped>
+.el-form {
+  .el-image {
+    width: 146px;
+  }
+
+  .address {
+    width: 100%;
+    display: flex;
+    align-items: center;
+
+    .el-form-item {
+      width: 100%;
+      flex: 1;
+    }
+
+    span {
+      margin: 0 4px
+    }
+  }
+}
+
+.submit {
+  width: 100%;
+  height: 40px;
+}
+</style>

+ 194 - 0
src/views/mobile/replace.vue

@@ -0,0 +1,194 @@
+<template>
+  <div class='app-container' v-loading="loading">
+    <el-form :model="data.form" :rules="data.rules" ref="form" label-width="auto">
+      <el-form-item label="收货人" prop="contact">
+        <el-input v-model="data.form.contact" placeholder="请输入收货人名称" />
+      </el-form-item>
+      <el-form-item label="手机号" prop="mobile">
+        <el-input v-model="data.form.mobile" placeholder="请输入手机号" />
+      </el-form-item>
+      <el-form-item class="address" label="收货地址" required>
+        <el-form-item prop="provinceName">
+          <el-select v-model="data.form.provinceName" placeholder="省">
+            <el-option v-for="item in addressOptions" :key="item.id" :value="item.name" :label="item.name" />
+          </el-select>
+        </el-form-item>
+        <span>/</span>
+        <el-form-item prop="cityName">
+          <el-select v-model="data.form.cityName" placeholder="市">
+            <el-option v-for="item in cityOptions" :key="item.id" :value="item.name" :label="item.name" />
+          </el-select>
+        </el-form-item>
+        <span>/</span>
+        <el-form-item>
+          <el-select v-model="data.form.areaName" placeholder="区">
+            <el-option v-for="item in areaOptions" :key="item.id" :value="item.name" :label="item.name" />
+          </el-select>
+        </el-form-item>
+      </el-form-item>
+      <el-form-item label="详细地址" prop="address">
+        <el-input v-model="data.form.address" type="textarea" :autosize="{ minRows: 5 }" placeholder="请输入详细地址" />
+      </el-form-item>
+      <el-form-item label="物流公司" prop="logisticsName">
+        <el-input v-model="data.form.logisticsName" placeholder="请输入物流公司" />
+      </el-form-item>
+      <el-form-item label="快递单号" prop="logisticsCode">
+        <el-input v-model="data.form.logisticsCode" placeholder="请输入快递单号(示例:SF)" />
+      </el-form-item>
+      <el-form-item label="产品型号" prop="specCode">
+        <el-select v-model="data.form.specCode" filterable remote :remote-method="remoteMethod" placeholder="请选择产品型号">
+          <el-option v-for="item in goodsOptions" :key="item.goodsId" :value="item.goodsId" :label="item.goodsName" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="数量" prop="quantity">
+        <el-input-number v-model="data.form.quantity" :min="1" />
+      </el-form-item>
+      <el-form-item label="购买渠道" prop="shopCode">
+        <el-select v-model="data.form.shopCode" prop="shopCode" placeholder="请选择购买渠道" @change="handleChangeShopCode">
+          <el-option v-for="item in storeOptions" :key="item.storeCode" :value="item.storeCode"
+            :label="item.storeName" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="购买凭证" prop="proofPurchase">
+        <CustomUpload list-type="picture-card" :src="data.form.proofPurchase" @upload="upload" />
+        <div>
+          <div>示例:</div>
+          <el-image :src="data.img[0]" :preview-src-list="data.img" />
+        </div>
+      </el-form-item>
+    </el-form>
+    <el-button class="submit" type="primary" round @click="getSubmit">提交</el-button>
+  </div>
+</template>
+
+<script setup>
+import Steps from '@/components/Steps'
+import { submit } from '@/api/mobile/replace'
+import { useAddress, useStore, useGoods } from '@/hooks/index'
+const { addressOptions, getAddress } = useAddress()
+const { storeOptions, getStore } = useStore()
+const { goodsForm, goodsOptions, getGoods } = useGoods()
+const { proxy } = getCurrentInstance()
+
+document.title = '换新申请'
+
+const data = reactive({
+  // 表单
+  form: {
+    quantity: 1,
+    oid: "",
+    outSkuId: 564,
+    provinceName: "",
+    cityName: "",
+    areaName: ""
+  },
+  // 校验
+  rules: {
+    shopCode: [{ required: true, message: '请选择购买渠道', trigger: 'change' }],
+    contact: [{ required: true, message: '请输入收货人姓名', trigger: 'blur' }],
+    mobile: [{ required: true, pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
+    provinceName: [{ required: true, message: '请选择省', trigger: 'change' }],
+    cityName: [{ required: true, message: '请选择市', trigger: 'change' }],
+    address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
+    logisticsName: [{ required: true, message: '请输入物流公司', trigger: 'blur' }],
+    logisticsCode: [{ required: true, message: '请输入快递单号', trigger: 'blur' }],
+    specCode: [{ required: true, message: '请选择产品型号', trigger: 'change' }],
+    quantity: [{ required: true, message: '请输入数量', trigger: 'blur' }],
+    proofPurchase: [{ required: true, message: '请上传购买凭证', trigger: 'change' }]
+  },
+  // 购买凭证模板
+  img: [new URL(`../../assets/images/example.jpg`, import.meta.url).href]
+})
+
+// 遮罩层
+const loading = ref(false)
+
+// 计算属性
+const cityOptions = computed(() => {
+  data.form.cityName = ""
+  data.form.areaName = ""
+  return data.form.provinceName ? addressOptions.value.find(i => i.name == data.form.provinceName).childList : []
+})
+
+const areaOptions = computed(() => {
+  data.form.areaName = ""
+  return data.form.cityName ? cityOptions.value.find(i => i.name == data.form.cityName).childList : []
+})
+
+// 搜索产品型号
+const remoteMethod = (e) => {
+  goodsForm.value.goodsName = e
+  getGoods()
+}
+
+// 上传图片
+const upload = (file) => {
+  data.form.proofPurchase = file.data.url
+}
+
+watch(() => data.form.contact, (val) => {
+  data.form.buyerNick = val
+})
+
+// 购买渠道
+const handleChangeShopCode = (e) => {
+  data.form.shopNick = storeOptions.value.find(i => i.storeCode == e).storeName
+}
+
+// 提交
+const getSubmit = () => {
+  proxy.$refs.form.validate((valid) => {
+    if (valid) {
+      loading.value = true
+      submit({ exchangeApplyOrderList: [data.form] }).then(res => {
+        if (res.code === 0) {
+          proxy.$modal.msgSuccess('提交成功!')
+          proxy.$refs.form.resetFields()
+          data.form = {
+            quantity: 1,
+            oid: "",
+            outSkuId: 564,
+            provinceName: "",
+            cityName: "",
+            areaName: ""
+          }
+          loading.value = false
+        }
+      })
+    } else {
+      return false
+    }
+  })
+}
+
+getAddress()
+getStore()
+</script>
+
+<style lang="scss" scoped>
+.el-form {
+  .el-image {
+    width: 146px;
+  }
+
+  .address {
+    width: 100%;
+    display: flex;
+    align-items: center;
+
+    .el-form-item {
+      width: 100%;
+      flex: 1;
+    }
+
+    span {
+      margin: 0 4px
+    }
+  }
+}
+
+.submit {
+  width: 100%;
+  height: 40px;
+}
+</style>

+ 8 - 10
src/views/mobile/service.vue

@@ -1,14 +1,12 @@
 <template>
   <div class='app-container'>
-    <!-- @click="getRouter('./apply')" -->
-    <div class="repair" >
+    <div class="repair" @click="getRouter('./repair')">
       <span>维修申请</span>
     </div>
-    <div class="change" @click="getRouter('./apply')">
+    <div class="change" @click="getRouter('./replace')">
       <span>换新申请</span>
     </div>
-    <!-- @click="getRouter('./order')" -->
-    <div class="order" >
+    <div class="order" @click="getRouter('./order')">
       <span>申请查询</span>
     </div>
     <div class="address" @click="getDialog">售后寄回地址</div>
@@ -17,7 +15,9 @@
       <div>
         <p style="text-indent: 2em;">整机性能保修1年,1年内,非人为损坏的产品性能问题全保,外观不在保修范围内,超过1年保修期或人为损坏支持有偿维修服务。</p>
 
-        <p style="text-indent: 2em;"><i style="color: red; font-style: normal">注意事项:</i>寄回维修或者换新请务必填写好工单信息,仓库拒收非登记快件,如因未填写工单信息产生丢件,概不处理!仓库不接收任何快递公司的到付件,请勿发到付!</p>
+        <p style="text-indent: 2em;"><i
+            style="color: red; font-style: normal">注意事项:</i>寄回维修或者换新请务必填写好工单信息,仓库拒收非登记快件,如因未填写工单信息产生丢件,概不处理!仓库不接收任何快递公司的到付件,请勿发到付!
+        </p>
 
         <p>售后地址:广东省东莞市厚街镇福民路11号3号楼2楼。</p>
 
@@ -32,6 +32,8 @@
 <script setup>
 const { proxy } = getCurrentInstance()
 
+document.title = '售后服务'
+
 const dialogVisible = ref(false)
 
 const getRouter = (path) => {
@@ -43,10 +45,6 @@ const getRouter = (path) => {
 const getDialog = () => {
   dialogVisible.value = true
 }
-
-onMounted(() => {
-  document.title = '售后服务'
-})
 </script>
 
 <style lang="scss" scoped>

+ 134 - 0
src/views/service/repair/index.vue

@@ -0,0 +1,134 @@
+<template>
+  <div class='app-container'>
+    <el-form inline>
+      <el-form-item label="当前状态:">
+        <el-select v-model="data.form.pushStatus" placeholder="请选择当前状态" style="width: 200px" clearable>
+          <el-option v-for="item in stepStatusOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="时间:">
+        <el-date-picker v-model="data.time" type="datetimerange" start-placeholder="开始时间" end-placeholder="结束时间"
+          value-format="YYYY-MM-DD HH:mm:ss" @change="handleChangeTime" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="getSearch">搜索</el-button>
+        <el-button icon="Refresh" @click="getRefresh">重置</el-button>
+        <el-button type="primary" icon="download" plain @click="getDownload">批量导出</el-button>
+      </el-form-item>
+    </el-form>
+    <el-table :data="data.tableData" v-loading="loading">
+      <el-table-column label="收货人" prop="receiverName" align="center" />
+      <el-table-column label="手机号" prop="mobile" align="center" />
+      <el-table-column label="收货地址" align="center">
+        <template #default="scope">
+          {{ scope.row.province }}{{ scope.row.city }}{{ scope.row.district }}{{ scope.row.address }}
+        </template>
+      </el-table-column>
+      <el-table-column label="购买凭证" align="center" width="100px">
+        <template #default="scope">
+          <el-image :src="scope.row.proofPurchase" />
+        </template>
+      </el-table-column>
+      <el-table-column label="产品型号" prop="goodsName" align="center" />
+      <el-table-column label="维修数量" prop="repairQuantity" align="center" />
+      <el-table-column label="当前状态" align="center" :formatter="statusFormatter" />
+      <el-table-column label="操作" align="center">
+        <template #default="scope">
+          <el-dropdown v-if="scope.row.status === 3">
+            <el-button type="primary" link>
+              审核<el-icon><arrow-down /></el-icon>
+            </el-button>
+            <template #dropdown>
+              <el-dropdown-menu>
+                <el-dropdown-item @click="getChange(scope.row.id, 1)">通过</el-dropdown-item>
+                <el-dropdown-item @click="getChange(scope.row.id, 2)">不通过</el-dropdown-item>
+              </el-dropdown-menu>
+            </template>
+          </el-dropdown>
+        </template>
+      </el-table-column>
+    </el-table>
+
+  </div>
+</template>
+
+<script setup>
+import { list, change } from '@/api/service/repair'
+import { useCommon } from '@/hooks/index'
+
+const { stepStatusOptions } = useCommon()
+
+const { proxy } = getCurrentInstance()
+
+const data = reactive({
+  form: {
+    pageNum: 1,
+    pageSize: 10
+  },
+  // 列表
+  tableData: [],
+  idList: []
+})
+
+// 遮罩层
+const loading = ref(false)
+// 总数据
+const total = ref(0)
+
+// 列表
+const getList = () => {
+  loading.value = true
+  list(data.form).then(res => {
+    if (res.code === 0) {
+      data.tableData = res.data.records
+      total.value = res.data.total
+      loading.value = false
+    }
+  })
+}
+
+// 时间
+const handleChangeTime = (e) => {
+  data.form.startTime = e[0]
+  data.form.endTime = e[1]
+}
+
+// 搜索
+const getSearch = () => {
+  data.form.pageNum = 1
+  getList()
+}
+
+// 重置
+const getRefresh = () => {
+  data.form = {
+    pageNum: 1,
+    pageSize: 10
+  }
+  getList()
+}
+
+// 审核
+const getChange = (id, status) => {
+  change(id, status).then(res => {
+    if(res.code === 0) {
+      proxy.$modal.msgSuccess('审核成功!')
+      getList()
+    }
+  })
+}
+
+// 导出
+const getDownload = () => {
+  proxy.download("oms/repairrecordOrder/export", data.form, `config_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+
+// 字典翻译
+const statusFormatter = (row) => {
+  return proxy.selectDictLabel(stepStatusOptions.value, row.status)
+}
+
+
+</script>

+ 128 - 0
src/views/service/replace/index.vue

@@ -0,0 +1,128 @@
+<template>
+  <div class='app-container'>
+    <el-form inline>
+      <el-form-item label="当前状态:">
+        <el-select v-model="data.form.pushStatus" placeholder="请选择当前状态" style="width: 200px" clearable>
+          <el-option v-for="item in pushStatusOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="时间:">
+        <el-date-picker v-model="data.time" type="datetimerange" start-placeholder="开始时间" end-placeholder="结束时间"
+          value-format="YYYY-MM-DD HH:mm:ss" @change="handleChangeTime" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="getSearch">搜索</el-button>
+        <el-button icon="Refresh" @click="getRefresh">重置</el-button>
+        <el-button type="primary" icon="Upload" plain @click="getPush(data.idList)"
+          :disabled="data.idList.length <= 0">批量推送</el-button>
+      </el-form-item>
+    </el-form>
+    <!-- 列表 -->
+    <el-table :data="data.tableData" v-loading="loading" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" align="center" />
+      <el-table-column label="买家昵称" prop="buyerNick" align="center" />
+      <el-table-column label="购买渠道" prop="shopNick" align="center" />
+      <el-table-column label="联系人" prop="contact" align="center" />
+      <el-table-column label="手机号" prop="mobile" align="center" />
+      <el-table-column label="详细地址" prop="address" align="center">
+        <template #default="scope">
+          <span>{{ scope.row.address.replace(/\^/g, '') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="数量" prop="quantity" align="center" />
+      <el-table-column label="购买凭证" align="center" width="100px">
+        <template #default="scope">
+          <el-image :src="scope.row.proofPurchase" />
+        </template>
+      </el-table-column>
+      <el-table-column label="当前状态" align="center" :formatter="statusFormatter" />
+      <el-table-column label="操作" align="center">
+        <template #default="scope">
+          <el-button v-if="scope.row.pushStatus === 0" type="primary" link @click="getPush([scope.row.id])">推送</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination v-show="total > 0" :total="total" v-model:page="data.form.pageNum" v-model:limit="data.form.pageSize"
+      @pagination="getList" />
+  </div>
+</template>
+
+<script setup>
+import { list, push } from "@/api/service/replace"
+import { useStore, useCommon } from '@/hooks/index'
+
+const { storeOptions, getStore } = useStore()
+const { pushStatusOptions } = useCommon()
+
+const { proxy } = getCurrentInstance()
+
+const data = reactive({
+  form: {
+    pageNum: 1,
+    pageSize: 10
+  },
+  idList: []
+})
+
+// 遮罩层
+const loading = ref(false)
+// 全数据
+const total = ref(0)
+
+// 列表
+const getList = () => {
+  loading.value = true
+  list(data.form).then(res => {
+    if (res.code === 0) {
+      data.tableData = res.data.records
+      total.value = res.data.total
+      loading.value = false
+    }
+  })
+}
+
+// 时间
+const handleChangeTime = (e) => {
+  data.form.startTime = e[0]
+  data.form.endTime = e[1]
+}
+
+// 搜索
+const getSearch = () => {
+  data.form.pageNum = 1
+  getList()
+}
+
+// 重置
+const getRefresh = () => {
+  data.form = {
+    pageNum: 1,
+    pageSize: 10
+  }
+  getList()
+}
+
+// 多选
+const handleSelectionChange = (e) => {
+  data.idList = []
+  e.map(i => data.idList.push(i.id))
+}
+
+// 推送
+const getPush = (id) => {
+  push({ idList: id }).then(res => {
+    if (res.code === 0) {
+      proxy.$modal.msgSuccess('推送成功!')
+      getList()
+    }
+  })
+}
+
+// 字典翻译
+function statusFormatter(row) {
+  return proxy.selectDictLabel(pushStatusOptions.value, row.pushStatus)
+}
+
+getStore()
+getList()
+</script>

+ 101 - 44
src/views/service/resend/index.vue

@@ -3,42 +3,57 @@
     <!-- 搜索 -->
     <el-form inline>
       <el-form-item>
-        <el-button type="primary" icon="Plus" @click="getDialog">推送</el-button>
+        <el-button type="primary" icon="Plus" @click="getDialog">新增</el-button>
+        <el-button type="primary" icon="Upload" plain :disabled="data.idsList.length <= 0"
+          @click="getPush(data.idsList)">批量推送</el-button>
       </el-form-item>
     </el-form>
     <!-- 列表 -->
-    <el-table :data="data.tableData">
-      <el-table-column label="店铺编码" align="center" prop="shopeCode" />
+    <el-table :data="data.tableData" v-loading="loading" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" align="center" />
+      <el-table-column label="购买渠道" align="center" prop="shopNick" />
       <el-table-column label="会员昵称" align="center" prop="buyerNick" />
-      <el-table-column label="收货人" align="center" prop="name" />
-      <el-table-column label="手机号" align="center" prop="mobile" />
+      <el-table-column label="收货人" align="center" prop="receiverInfo.name" />
+      <el-table-column label="手机号" align="center" prop="receiverInfo.mobile" />
       <el-table-column label="数量" align="center" prop="planQty" />
       <el-table-column label="物流公司" align="center" prop="logisticsName" />
       <el-table-column label="快递单号" align="center" prop="logisticsCode" />
       <el-table-column label="地址" align="center">
         <template #default="scope">
-          {{ scope.row.province }}{{ scope.row.city }}{{ scope.row.area }}{{ scope.row.detailAddress }}
+          {{ scope.row.receiverInfo.province }}{{ scope.row.receiverInfo.city }}{{ scope.row.receiverInfo.area }}{{
+          scope.row.receiverInfo.detailAddress }}
         </template>
       </el-table-column>
       <el-table-column label="备注" align="center" prop="buyerMessage" />
+      <el-table-column label="当前状态" align="center" :formatter="statusFormatter" />
+      <el-table-column label="操作" align="center">
+        <template #default="scope">
+          <el-button type="primary" link @click="getPush([scope.row.id])">推送</el-button>
+        </template>
+      </el-table-column>
     </el-table>
+    <pagination v-show="total > 0" :total="total" v-model:page="data.form.pageNum" v-model:limit="data.form.pageSize"
+      @pagination="getList" />
     <!-- 弹窗 -->
-    <el-dialog v-model="dialogVisible" title="新增" width="500px">
+    <el-dialog v-model="dialogVisible" title="新增" width="500px" :before-close="getClose">
       <el-form :model="data.dialogForm" :rules="data.rules" ref="dialogForm" label-width="auto">
-        <el-form-item label="店铺编码:" prop="shopCode">
-          <el-input v-model="data.dialogForm.shopCode" placeholder="请输入店铺编码" />
+        <el-form-item label="购买渠道:" prop="shopCode">
+          <el-select v-model="data.dialogForm.shopCode" placeholder="请选择店铺编码" @change="handleChangeShopCode">
+            <el-option v-for="item in storeOptions" :key="item.storeCode" :value="item.storeCode"
+              :label="item.storeName" />
+          </el-select>
         </el-form-item>
         <el-form-item label="会员昵称:" prop="buyerNick">
           <el-input v-model="data.dialogForm.buyerNick" placeholder="请输入会员昵称" />
         </el-form-item>
-        <el-form-item label="收货人:" prop="name">
-          <el-input v-model="data.receiverInfo.name" placeholder="请输入收货人" />
+        <el-form-item label="收货人:" prop="receiverInfo.name">
+          <el-input v-model="data.dialogForm.receiverInfo.name" placeholder="请输入收货人" />
         </el-form-item>
-        <el-form-item label="手机号码:" prop="mobile">
-          <el-input v-model="data.receiverInfo.mobile" placeholder="请输入手机号码" />
+        <el-form-item label="手机号码:" prop="receiverInfo.mobile">
+          <el-input v-model="data.dialogForm.receiverInfo.mobile" placeholder="请输入手机号码" />
         </el-form-item>
         <el-form-item label="数量:" prop="planQty">
-          <el-input v-model="data.dialogForm.planQty" placeholder="请输入数量" />
+          <el-input-number v-model="data.dialogForm.planQty" :min="1" />
         </el-form-item>
         <el-form-item label="物流公司:" prop="logisticsName">
           <el-input v-model="data.dialogForm.logisticsName" placeholder="请输入物流公司" />
@@ -46,24 +61,24 @@
         <el-form-item label="快递单号:" prop="logisticsCode">
           <el-input v-model="data.dialogForm.logisticsCode" placeholder="请输入快递单号" />
         </el-form-item>
-        <div class="address">
-          <el-form-item label="收货地址:" prop="province">
-            <el-input v-model="data.receiverInfo.province" placeholder="省" />
+        <el-form-item class="address" label="收货地址:" required>
+          <el-form-item prop="receiverInfo.province">
+            <el-input v-model="data.dialogForm.receiverInfo.province" placeholder="省" />
           </el-form-item>
           <span>/</span>
-          <el-form-item>
-            <el-input v-model="data.receiverInfo.city" placeholder="市" />
+          <el-form-item prop="receiverInfo.city">
+            <el-input v-model="data.dialogForm.receiverInfo.city" placeholder="市" />
           </el-form-item>
           <span>/</span>
           <el-form-item>
-            <el-input v-model="data.receiverInfo.area" placeholder="区" />
+            <el-input v-model="data.dialogForm.receiverInfo.area" placeholder="区" />
           </el-form-item>
-        </div>
-        <el-form-item label="详细地址:" prop="detailAddress">
-          <el-input v-model="data.receiverInfo.detailAddress" placeholder="请输入地址" />
+        </el-form-item>
+        <el-form-item label="详细地址:" prop="receiverInfo.detailAddress">
+          <el-input v-model="data.dialogForm.receiverInfo.detailAddress" placeholder="请输入地址" />
         </el-form-item>
         <el-form-item label="备注:" prop="buyerMessage">
-          <el-input v-model="data.receiverInfo.buyerMessage" type="textarea" :autosize="{ minRows: 5 }"
+          <el-input v-model="data.dialogForm.buyerMessage" type="textarea" :autosize="{ minRows: 5 }"
             placeholder="请输入备注" />
         </el-form-item>
       </el-form>
@@ -76,10 +91,12 @@
 </template>
 
 <script setup>
-import { list, submit } from '@/api/service/resend.js'
+import { list, submit, push } from '@/api/service/resend.js'
 
-import { useAddress } from '@/hooks/index'
+import { useAddress, useStore, useCommon } from '@/hooks/index'
 const { addressOptions, getAddress } = useAddress()
+const { storeOptions, getStore } = useStore()
+const { pushStatusOptions } = useCommon()
 
 const { proxy } = getCurrentInstance()
 
@@ -92,32 +109,44 @@ const data = reactive({
   tableData: [],
   // 表单
   dialogForm: {
-    shopCode: "A1000002",
     sourcePlatformCode: "MUZEN",
     sourcePlatformName: "猫王",
-    shopNick: "猫王旗舰店"
+    receiverInfo: {},
+    planQty: 1
   },
-  receiverInfo: {},
   // 校验
   rules: {
-    shopCode: [{ required: true, message: '请选择店铺编码', trigger: 'change' }],
+    shopCode: [{ required: true, message: '请选择购买渠道', trigger: 'change' }],
     buyerNick: [{ required: true, message: '请输入会员昵称', trigger: 'blur' }],
-    name: [{ required: true, message: '请输入收货人名称', trigger: 'blur' }],
-    mobile: [{ required: true, message: '请输入手机号码', trigger: 'blur' }],
     planQty: [{ required: true, message: '请输入数量', trigger: 'blur' }],
     logisticsName: [{ required: true, message: '请输入物流公司', trigger: 'blur' }],
     logisticsCode: [{ required: true, message: '请输入快递单号', trigger: 'blur' }],
-    province: [{ required: true, message: '请输入省', trigger: 'blur' }],
-    detailAddress: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
-    buyerMessage: [{ required: true, message: '请输入备注', trigger: 'blur' }]
-  }
+    receiverInfo: {
+      name: [{ required: true, message: '请输入收货人名称', trigger: 'blur' }],
+      mobile: [{ required: true, pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
+      province: [{ required: true, message: '请输入省', trigger: 'blur' }],
+      city: [{ required: true, message: '请输入区', trigger: 'blur' }],
+      detailAddress: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
+    },
+    buyerMessage: [{ required: true, message: '请输入备注', trigger: 'blur' }],
+  },
+  // 推送
+  idsList: []
 })
 
+// 遮罩层
+const loading = ref(false)
+// 总数据
+const total = ref(0)
+
 // 列表
 const getList = () => {
+  loading.value = true
   list(data.form).then(res => {
     if (res.code === 0) {
       data.tableData = res.data.records
+      total.value = res.data.total
+      loading.value = false
     }
   })
 }
@@ -129,6 +158,11 @@ const getDialog = () => {
   dialogVisible.value = true
 }
 
+// 购买渠道
+const handleChangeShopCode = (e) => {
+  data.dialogForm.shopNick = storeOptions.value.find(i => i.storeCode == e).storeName
+}
+
 // 提交
 const getSubmit = () => {
   proxy.$refs.dialogForm.validate((valid) => {
@@ -137,6 +171,7 @@ const getSubmit = () => {
         if (res.code === 0) {
           proxy.$modal.msgSuccess('新增成功!')
           getClose()
+          getList()
         }
       })
     } else {
@@ -150,12 +185,27 @@ const getClose = () => {
   dialogVisible.value = false
   proxy.$refs.dialogForm.resetFields()
   data.dialogForm = {
-    shopCode: "A1000002",
     sourcePlatformCode: "MUZEN",
     sourcePlatformName: "猫王",
-    shopNick: "猫王旗舰店"
+    receiverInfo: {},
+    planQty: 1
   }
-  data.receiverInfo = {}
+}
+
+// 多选
+const handleSelectionChange = (e) => {
+  data.idsList = []
+  e.map(i => data.idsList.push(i.id))
+}
+
+
+// 推送
+const getPush = (id) => {
+  push({ idList: id }).then(res => {
+    if (res.code === 0) {
+      proxy.$modal.msgSuccess('推送成功!')
+    }
+  })
 }
 
 // 计算属性
@@ -167,12 +217,14 @@ const areaOptions = computed(() => {
   return data.receiverInfo.city ? cityOptions.value.find(i => i.id === data.receiverInfo.city).childList : []
 })
 
-watch(data.receiverInfo, (val) => {
-  data.dialogForm.receiverInfo = val
-})
-
-getList()
 getAddress()
+getStore()
+getList()
+
+// 字典翻译
+const statusFormatter = (row) => {
+  return proxy.selectDictLabel(pushStatusOptions.value, row.pushStatus)
+}
 </script>
 
 <style lang="scss" scoped>
@@ -181,6 +233,11 @@ getAddress()
   display: flex;
   align-items: center;
 
+  .el-form-item {
+    width: 100%;
+    flex: 1;
+  }
+
   span {
     margin: 0 4px
   }

+ 2 - 1
src/whiteList.js

@@ -3,7 +3,8 @@ export default {
     "/login",
     "/register",
     "/mobile/service",
-    "/mobile/apply",
+    "/mobile/replace",
+    "/mobile/repair",
     "/mobile/order"
   ],
 };

+ 1 - 3
vite.config.js

@@ -32,9 +32,7 @@ export default defineConfig(({ mode, command }) => {
         // https://cn.vitejs.dev/config/#server-proxy
         "/dev-api": {
           // target: "http://192.168.0.174:8087", // 本地
-          // target: 'http://192.168.0.75:8080', // 测试
-          // target: "http://43.138.219.11:8087", // 打包地址
-          target: "http://10.0.0.11:8087",
+          target: "http://10.0.0.11:8087", // 打包
           changeOrigin: true,
           rewrite: (p) => p.replace(/^\/dev-api/, ""),
         },