Explorar o código

add 回收订单目录查询&组件封装

haveyou hai 1 ano
pai
achega
935cde5462
Modificáronse 39 ficheiros con 1711 adicións e 14 borrados
  1. 2 2
      .env
  2. 1 1
      .env.development
  3. 1 1
      .env.production
  4. 109 0
      src/components/CommonPage/ProSearch.vue
  5. 45 0
      src/components/CommonPage/SimpleTable.vue
  6. 2 2
      src/layout/index.vue
  7. 2 0
      src/main.js
  8. 2 0
      src/router/index.js
  9. 1 0
      src/store/modules/user.js
  10. 57 8
      src/styles/index.scss
  11. 5 0
      src/views/recycleOrder/auditNotSubmit/index.vue
  12. 5 0
      src/views/recycleOrder/awaitAudit/index.vue
  13. 5 0
      src/views/recycleOrder/awaitDelivery/index.vue
  14. 5 0
      src/views/recycleOrder/awaitPay/index.vue
  15. 5 0
      src/views/recycleOrder/awaitPickup/index.vue
  16. 5 0
      src/views/recycleOrder/awaitReview/index.vue
  17. 5 0
      src/views/recycleOrder/awaitSign/index.vue
  18. 5 0
      src/views/recycleOrder/cancelled/index.vue
  19. 5 0
      src/views/recycleOrder/completed/index.vue
  20. 122 0
      src/views/recycleOrder/components/after-sales-payment.vue
  21. 116 0
      src/views/recycleOrder/components/applyfor-order-claim.vue
  22. 65 0
      src/views/recycleOrder/components/audit-screenshot.vue
  23. 30 0
      src/views/recycleOrder/components/order-amount.vue
  24. 34 0
      src/views/recycleOrder/components/order-customer.vue
  25. 61 0
      src/views/recycleOrder/components/order-log.vue
  26. 37 0
      src/views/recycleOrder/components/order-modal.vue
  27. 34 0
      src/views/recycleOrder/components/order-number.vue
  28. 256 0
      src/views/recycleOrder/components/order-page.vue
  29. 123 0
      src/views/recycleOrder/components/order-remarks.vue
  30. 125 0
      src/views/recycleOrder/components/order-search.vue
  31. 25 0
      src/views/recycleOrder/components/order-time.vue
  32. 29 0
      src/views/recycleOrder/components/order-timeline.vue
  33. 92 0
      src/views/recycleOrder/components/send-SMS.vue
  34. 55 0
      src/views/recycleOrder/components/user-bind-tag.vue
  35. 5 0
      src/views/recycleOrder/detail/index.vue
  36. 5 0
      src/views/recycleOrder/failedAudit/index.vue
  37. 5 0
      src/views/recycleOrder/needReturned/index.vue
  38. 220 0
      src/views/recycleOrder/search/index.vue
  39. 5 0
      src/views/recycleOrder/urgentRecycleAudit/index.vue

+ 2 - 2
.env

@@ -1,4 +1,4 @@
 # EleAdminPlus授权码, 自带的只能用于演示, 正式项目请更换为自己的授权码
-VITE_LICENSE=dk9mcwJyetRWQlxWRiojIiwiIzVHbQ5Wa6ICdjVmaiV3culWYt9GZiwSMukWevVnciojIu4WatRWYlxWZiQWaiwiIt92YXZ3UxIVYoJiOpNnclZnIsISYiIjLxIiOi42bQf0NW==
+VITE_LICENSE=dk9mcwJyetRWQlxWRiojIiwiIzVHbQ5Wa6ICdjVmaiV3cklmIsATO3UTMaVTU1cUWiojIzJXZ2JCLi4Gby4SMiojIu9Wa0nI0NW=
 # 项目名
-VITE_APP_NAME=RuoYi EleAdmin
+VITE_APP_NAME=书嗨后台管理

+ 1 - 1
.env.development

@@ -1,3 +1,3 @@
 # 开发环境接口地址
-VITE_API_URL=https://vue.ruoyi.vip/prod-api
+VITE_API_URL=http://bk.shuhi.com/api
 #VITE_API_URL=http://localhost:8080

+ 1 - 1
.env.production

@@ -1,2 +1,2 @@
 # 生产环境接口地址
-VITE_API_URL=https://vue.ruoyi.vip/prod-api
+VITE_API_URL=http://bk.shuhi.com/api

+ 109 - 0
src/components/CommonPage/ProSearch.vue

@@ -0,0 +1,109 @@
+<script setup>
+  import { ref, watch } from 'vue';
+  //组件的属性
+  let props = defineProps({
+    form: {
+      //表单参数详情
+      type: Object,
+      default: () => ({})
+    },
+    columns: {
+      type: Array,
+      default: () => []
+    },
+    marginBottom: {
+      type: String,
+      default: '10px'
+    }
+  });
+  const emit = defineEmits(['update:form']);
+
+  let model = ref({});
+  watch(
+    () => props.form,
+    (val) => {
+      model.value = val;
+    },
+    { deep: true }
+  );
+
+  watch(
+    () => model.value,
+    (val) => {
+      let data = Object.assign(props.form, val);
+      emit('update:form', data);
+    },
+    { deep: true }
+  );
+
+  //tag上 placeholder的显示
+  const getPlaceholder = (row) => {
+    if (row.placeholder) return row.placeholder;
+    if (typeof row.tag == 'object') return;
+    return row.label;
+  };
+  //插槽函数
+  const slotFunction = (val) => {
+    return typeof val == 'function' ? val() : val;
+  };
+
+  let formRef = ref(null);
+
+  defineExpose({
+    form: props.model
+  });
+</script>
+
+<style lang="scss">
+  .search-form {
+    ::v-deep .el-date-editor.el-input, .el-date-editor.el-input__wrapper {
+      width: 100%;
+    }
+  }
+</style>
+
+<template>
+  <el-form
+    ref="formRef"
+    v-bind="$attrs"
+    :labelWidth="0"
+    :model="model"
+    class="search-form"
+  >
+    <el-row :gutter="12" justify="start">
+      <el-col
+        v-for="element in columns"
+        :span="element.span || 6"
+        :key="element.prop"
+      >
+        <el-form-item
+          class="custom-class"
+          :class="element.customClass"
+          :prop="element.prop"
+          v-bind="element.formItemAttrs"
+          :style="{ marginBottom: marginBottom }"
+        >
+          <template v-if="element.type == 'slot'">
+            <slot
+              :name="element.prop"
+              :data="model"
+              :item="element.tagAttrs"
+            ></slot>
+          </template>
+          <component
+            v-else
+            :is="element.tag"
+            v-bind="element.tagAttrs"
+            v-model="model[element.prop]"
+            :placeholder="getPlaceholder(element)"
+          >
+            <template v-for="(val, key, i) in element.tagSlots" :key="i" #[key]>
+              {{ slotFunction(val) }}
+            </template>
+          </component>
+        </el-form-item>
+      </el-col>
+      <slot></slot>
+    </el-row>
+  </el-form>
+</template>

+ 45 - 0
src/components/CommonPage/SimpleTable.vue

@@ -0,0 +1,45 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-pro-table
+    ref="tableRef"
+    :row-key="rowId"
+    :columns="columns"
+    :datasource="datasource"
+    highlight-current-row
+    :pagination="false"
+    :tools="false"
+  ></ele-pro-table>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+  import { pagePosts } from '@/api/system/post';
+
+  const props = defineProps({
+    columns: {
+      type: Array,
+      default() {
+        return [];
+      }
+    },
+    rowId: {
+      type: String,
+      default: 'id'
+    }
+  });
+
+  const tableRef = ref(null);
+  /** 表格数据源 */
+  const datasource = ({ pages, where, orders }) => {
+    return pagePosts({ ...where, ...orders, ...pages });
+  };
+
+  /** 搜索 */
+  const reload = (where) => {
+    tableRef.value?.reload?.({ page: 1, where });
+  };
+
+  defineExpose({
+    reload
+  });
+</script>

+ 2 - 2
src/layout/index.vue

@@ -130,9 +130,9 @@
       </div>
     </template>
     <!-- 全局页脚 -->
-    <template #footer>
+    <!-- <template #footer>
       <page-footer />
-    </template>
+    </template> -->
     <!-- 菜单图标 -->
     <template #icon="{ icon, item }">
       <el-icon v-if="icon" v-bind="item.meta?.props?.iconProps || {}">

+ 2 - 0
src/main.js

@@ -9,8 +9,10 @@ import 'element-plus/theme-chalk/display.css';
 import 'ele-admin-plus/es/style/nprogress.scss';
 import './styles/themes/dark.scss';
 import './styles/index.scss';
+import request from '@/utils/request';
 
 const app = createApp(App);
+app.config.globalProperties.$http = request;
 
 app.use(store);
 app.use(router);

+ 2 - 0
src/router/index.js

@@ -47,7 +47,9 @@ router.beforeEach(async (to) => {
     if (menus) {
       getMenuRoutes(menus, homePath).forEach((r) => {
         router.addRoute(r);
+        console.log(r.path, r, 'r');
       });
+
       return { ...to, replace: true };
     }
   }

+ 1 - 0
src/store/modules/user.js

@@ -37,6 +37,7 @@ export const useUserStore = defineStore('user', {
       this.roles = result.roles;
       // 用户菜单
       const userMenu = await getUserMenu().catch((e) => console.error(e));
+      console.log(userMenu,'getUserMenu')
       if (!userMenu) {
         return {};
       }

+ 57 - 8
src/styles/index.scss

@@ -1,6 +1,11 @@
 /** 全局样式 */
-@use 'element-plus/theme-chalk/src/mixins/function.scss' as *;
-@use './transition.scss' as *;
+@use 'element-plus/theme-chalk/src/mixins/function.scss'as *;
+@use './transition.scss'as *;
+
+.ele-page,
+.ele-admin-tabs {
+  --ele-page-padding: 12px;
+}
 
 * {
   outline: none;
@@ -21,6 +26,7 @@ body {
   overflow-x: hidden;
   overflow-y: auto;
   height: 100%;
+  width: 100% !important;
 }
 
 /* 按钮加图标减少间距 */
@@ -29,7 +35,7 @@ body {
   padding-left: 12px;
   padding-right: 12px;
 
-  & > .el-icon {
+  &>.el-icon {
     margin-left: -2px;
     margin-right: -2px;
   }
@@ -45,22 +51,29 @@ body {
   }
 }
 
+.demo-timeline {
+  .el-timeline {
+    padding: 0;
+    padding-left: 20px;
+  }
+}
+
 /* 级联选择器增加高度 */
 .ele-popper-higher .el-cascader-menu__wrap.el-scrollbar__wrap {
   height: 280px;
 }
 
 /* 间距组件样式优化 */
-.el-space--horizontal > .el-space__item:last-child {
+.el-space--horizontal>.el-space__item:last-child {
   margin-right: 0 !important;
 }
 
-.el-space--vertical > .el-space__item:last-child {
+.el-space--vertical>.el-space__item:last-child {
   padding-bottom: 0 !important;
 }
 
 /* echarts */
-.echarts > div > div {
+.echarts>div>div {
   max-width: 100%;
   overflow: hidden;
 }
@@ -68,6 +81,7 @@ body {
 /* 小屏幕时分页去掉一些组件 */
 @media screen and (max-width: 768px) {
   .ele-pro-table .el-pagination {
+
     .el-pagination__sizes,
     .el-pagination__jump {
       display: none;
@@ -76,8 +90,8 @@ body {
 }
 
 /* 表单验证气泡形式 */
-.pro-form-error-popper.el-form-item > .el-form-item__content {
-  & > .el-form-item__error {
+.pro-form-error-popper.el-form-item>.el-form-item__content {
+  &>.el-form-item__error {
     position: absolute;
     left: 0;
     top: auto;
@@ -103,6 +117,30 @@ body {
   }
 }
 
+//table操作按钮
+.ele-pro-table {
+  .el-table .cell.el-tooltip {
+    white-space: wrap;
+  }
+
+  .el-button {
+    margin-right: 8px;
+  }
+
+  .el-button+.el-button {
+    margin-left: 0;
+  }
+}
+
+//搜索况下时间选择框的样式
+.search-form {
+
+  .el-date-editor.el-input,
+  .el-date-editor.el-input__wrapper {
+    width: 100%
+  }
+}
+
 /* 主题切换过渡 */
 ::view-transition-old(root),
 ::view-transition-new(root) {
@@ -124,3 +162,14 @@ html.disabled-transition,
 html.disabled-transition :not(.view-transition-trigger) * {
   transition: none !important;
 }
+
+
+//基础信息展示样式
+.common-row {
+  padding-left: 12px;
+
+  .el-col {
+    line-height: 32px;
+    margin-bottom: 6px;
+  }
+}

+ 5 - 0
src/views/recycleOrder/auditNotSubmit/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 5 - 0
src/views/recycleOrder/awaitAudit/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 5 - 0
src/views/recycleOrder/awaitDelivery/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 5 - 0
src/views/recycleOrder/awaitPay/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 5 - 0
src/views/recycleOrder/awaitPickup/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 5 - 0
src/views/recycleOrder/awaitReview/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 5 - 0
src/views/recycleOrder/awaitSign/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 5 - 0
src/views/recycleOrder/cancelled/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 5 - 0
src/views/recycleOrder/completed/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 122 - 0
src/views/recycleOrder/components/after-sales-payment.vue

@@ -0,0 +1,122 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal
+    form
+    :width="960"
+    v-model="visible"
+    title="售后补款"
+    @open="handleOpen"
+  >
+    <el-row :gutter="12" class="common-row">
+      <el-col :span="12">书籍总数:20本</el-col>
+      <el-col :span="12">不良数量:2本</el-col>
+      <el-col :span="12">预估书款:20.46元</el-col>
+      <el-col :span="12">预估运费:0元</el-col>
+      <el-col :span="12">审核书款:15.66元</el-col>
+      <el-col :span="12">运费补贴:0元</el-col>
+    </el-row>
+
+    <el-form
+      ref="formRef"
+      :model="form"
+      :rules="rules"
+      label-width="80px"
+      @submit.prevent=""
+    >
+      <el-form-item label="补款类型" prop="paymentType">
+        <el-radio-group v-model="form.paymentType">
+          <el-radio :value="1">书籍补款</el-radio>
+          <el-radio :value="2">运费补款</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="书籍补款" prop="amount">
+        <el-input-number v-model="form.amount" :controls="false" :min="0.01" placeholder="补款金额">
+        </el-input-number>
+        <el-text style="margin:0 16px 0 5px">元</el-text>
+        <el-text size="small" type="info">书籍补款金额≤预估金额-审核金额-理赔金额。大于0,可精确到小数点后两位。</el-text>
+      </el-form-item>
+      <el-form-item label="补款备注" prop="remark">
+        <el-input
+          :rows="4"
+          type="textarea"
+          v-model="form.remark"
+          placeholder="请输入补款备注"
+        />
+      </el-form-item>
+      <el-form-item label="补款记录" prop="records"> 
+        <SimpleTable style="width:100%" :columns="columns"></SimpleTable>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleCancel">确定</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+  import { Flag, ChatDotSquare } from '@element-plus/icons-vue';
+  import orderTimeline from '@/views/recycleOrder/components/order-timeline.vue';
+  import SimpleTable from '@/components/CommonPage/SimpleTable.vue'
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+  };
+
+  /** 弹窗打开事件 */
+  const handleOpen = () => {
+    visible.value = true;
+    nextTick(() => console.log('打开'));
+  };
+
+  const form = reactive({
+    paymentType: '',
+    remark: '',
+    amount: ''
+  });
+  /** 表单验证规则 */
+  const rules = reactive({
+    paymentType: [
+      {
+        required: true,
+        message: '请选择补款类型',
+        type: 'string',
+        trigger: 'change'
+      }
+    ],
+    remark: [
+      {
+        required: true,
+        message: '请输入备注信息',
+        type: 'string',
+        trigger: 'blur'
+      }
+    ],
+    amount:[{
+        required: true,
+        message: '请输入补款金额',
+        type: 'number',
+        trigger: 'change'
+    }]
+  });
+
+  // 表格数据
+  const columns = reactive([
+    { label: '操作人', prop: 'createBy', width: 100 },
+    { label: '金额', prop: 'orderNumber', width: 150 },
+    { label: '类型', prop: 'status', width: 100 },
+    { label: '操作时间', prop: 'createTime', width: 180 },
+    { label: '备注', prop: 'logDescription' },
+  ]);
+
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 116 - 0
src/views/recycleOrder/components/applyfor-order-claim.vue

@@ -0,0 +1,116 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal
+    form
+    :width="960"
+    v-model="visible"
+    title="申请订单理赔"
+    @open="handleOpen"
+  >
+    <el-row :gutter="12" class="common-row">
+      <el-col :span="24">订单编号:9835451</el-col>
+      <el-col :span="24">预估金额:20.46元</el-col>
+      <el-col :span="24">审核金额:15.66元</el-col>
+      <el-col :span="24">书籍补款:0.22元</el-col>
+    </el-row>
+
+    <el-form
+      ref="formRef"
+      :model="form"
+      :rules="rules"
+      label-width="80px"
+      @submit.prevent=""
+    >
+      <el-form-item label="理赔金额" prop="amount">
+        <el-input-number
+          v-model="form.amount"
+          :controls="false"
+          :min="0.01"
+          placeholder="理赔金额"
+        >
+        </el-input-number>
+        <el-text style="margin: 0 16px 0 5px">元</el-text>
+        <el-text size="small" type="info"
+          >理赔金额≤预估金额-审核金额-售后补款金额。大于0,可精确到小数点后两位。</el-text
+        >
+      </el-form-item>
+      <el-form-item label="理赔原因" prop="paymentType">
+        <el-radio-group v-model="form.paymentType">
+          <el-radio :value="1">破损</el-radio>
+          <el-radio :value="2">少书</el-radio>
+          <el-radio :value="2">丢失</el-radio>
+          <el-radio :value="2">浸泡</el-radio>
+          <el-radio :value="2">混寄</el-radio>
+          <el-radio :value="2">书单不符</el-radio>
+        </el-radio-group>
+      </el-form-item>
+
+      <el-form-item label="理赔记录" prop="records">
+        <SimpleTable style="width:100%" :columns="columns"></SimpleTable>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleCancel">确定</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+  import { Flag, ChatDotSquare } from '@element-plus/icons-vue';
+  import orderTimeline from '@/views/recycleOrder/components/order-timeline.vue';
+  import SimpleTable from '@/components/CommonPage/SimpleTable.vue';
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+  };
+
+  /** 弹窗打开事件 */
+  const handleOpen = () => {
+    visible.value = true;
+    nextTick(() => console.log('打开'));
+  };
+
+  const form = reactive({
+    paymentType: '',
+    amount: ''
+  });
+  /** 表单验证规则 */
+  const rules = reactive({
+    paymentType: [
+      {
+        required: true,
+        message: '请选择补款类型',
+        type: 'string',
+        trigger: 'change'
+      }
+    ],
+    amount: [
+      {
+        required: true,
+        message: '请输入理赔金额',
+        type: 'number',
+        trigger: 'change'
+      }
+    ]
+  });
+
+  // 表格数据
+  const columns = reactive([
+    { label: '操作人', prop: 'createBy', width: 100 },
+    { label: '金额', prop: 'orderNumber', width: 150 },
+    { label: '类型', prop: 'status', width: 100 },
+    { label: '操作时间', prop: 'createTime', width: 180 },
+    { label: '备注', prop: 'logDescription' },
+  ]);
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 65 - 0
src/views/recycleOrder/components/audit-screenshot.vue

@@ -0,0 +1,65 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal :width="560" v-model="visible" title="审核截图">
+    <div
+      class="demo-image__preview"
+      v-for="(item, index) in imageList"
+      :key="index"
+    >
+      <div class="demo-image__info" style="margin-bottom: 6px">{{
+        item.remark
+      }}</div>
+      <el-image
+        v-for="(url, idx) in item.list"
+        style="width: 100px; height: 100px; margin-right: 10px"
+        :src="url"
+        :preview-src-list="item.list"
+        :initial-index="idx"
+        fit="cover"
+      />
+    </div>
+
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+  };
+
+  /** 弹窗打开事件 */
+  const handleOpen = () => {
+    visible.value = true;
+    nextTick(() => console.log('打开'));
+  };
+
+  const srcList = [
+    'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
+    'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
+    'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg'
+  ];
+
+  const imageList = reactive([
+    {
+      remark: '说明3213213',
+      list: srcList
+    },
+    {
+      remark: '说明说明说明说明说明说明说明',
+      list: srcList
+    }
+  ]);
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 30 - 0
src/views/recycleOrder/components/order-amount.vue

@@ -0,0 +1,30 @@
+<template>
+  <div class="recycle-order-number">
+    <div class="comon-text">
+      <el-text>预估书款:</el-text>
+      <el-text type="danger">¥2.9</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>审核书款:</el-text>
+      <el-text v-if="!row.deliveryCode">待核算</el-text>
+      <el-text v-else>罗**(189****1233)</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>订单类型:</el-text>
+      <el-text>普通订单</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>取件方式:</el-text>
+      <el-text>上门取件</el-text>
+    </div>
+  </div>
+</template>
+
+<script setup>
+  const props = defineProps({
+    row: {
+      type: Object,
+      default: () => {}
+    }
+  });
+</script>

+ 34 - 0
src/views/recycleOrder/components/order-customer.vue

@@ -0,0 +1,34 @@
+<template>
+  <div class="recycle-order-number">
+    <div class="comon-text">
+      <el-text>用户名:</el-text>
+      <el-text>77184923212132138219312323</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>发件人:</el-text>
+      <el-text v-if="row.deliveryCode">暂无信息</el-text>
+      <el-text v-else>罗**(189****1233)</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>省市区:</el-text>
+      <el-text>广东省/广州市/白云区</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>地址:</el-text>
+      <el-text>谭中街道文昌路2号科技大学文昌路校区宿舍B区</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>标签:</el-text>
+      <el-text>暂无信息</el-text>
+    </div>
+  </div>
+</template>
+
+<script setup>
+  const props = defineProps({
+    row: {
+      type: Object,
+      default: () => {}
+    }
+  });
+</script>

+ 61 - 0
src/views/recycleOrder/components/order-log.vue

@@ -0,0 +1,61 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal :width="1080" v-model="visible" title="订单日志">
+    <ele-pro-table
+      ref="tableRef"
+      row-key="id"
+      :columns="columns"
+      :datasource="datasource"
+      highlight-current-row
+      cache-key="orderLogTable"
+      :pagination="false"
+      :tools="false"
+    ></ele-pro-table>
+
+    <template #footer>
+      <el-button type="primary" @click="handleCancel">关闭</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+  import { pagePosts } from '@/api/system/post';
+
+  /** 弹窗是否打开 */
+  const visible = ref(false);
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+  };
+
+  /** 弹窗打开事件 */
+  const handleOpen = () => {
+    visible.value = true;
+    nextTick(() => console.log('打开'));
+  };
+
+  const columns = reactive([
+    { label: '订单编号', prop: 'orderNumber', width: 150 },
+    { label: '状态', prop: 'status', width: 100 },
+    { label: '操作者', prop: 'createBy', width: 100 },
+    { label: '日志描述', prop: 'logDescription' },
+    { label: '操作时间', prop: 'createTime', width: 180 }
+  ]);
+
+  const tableRef = ref(null);
+  /** 表格数据源 */
+  const datasource = ({ pages, where, orders }) => {
+    return pagePosts({ ...where, ...orders, ...pages });
+  };
+
+  /** 搜索 */
+  const reload = (where) => {
+    tableRef.value?.reload?.({ page: 1, where });
+  };
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 37 - 0
src/views/recycleOrder/components/order-modal.vue

@@ -0,0 +1,37 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal
+    form
+    :width="460"
+    v-model="visible"
+    title="用户绑定标签"
+    @open="handleOpen"
+  >
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleCancel">确定</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+  };
+
+  /** 弹窗打开事件 */
+  const handleOpen = () => {
+    visible.value = true;
+    nextTick(() => console.log('打开'));
+  };
+
+  defineExpose({
+    handleOpen
+  })
+</script>

+ 34 - 0
src/views/recycleOrder/components/order-number.vue

@@ -0,0 +1,34 @@
+<template>
+  <div class="recycle-order-number">
+    <div class="comon-text">
+      <el-text>订单号:</el-text>
+      <el-text type="danger">7718492</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>快递单号:</el-text>
+      <el-text v-if="!row.deliveryCode">暂无信息</el-text>
+      <el-text v-else type="success">SF23930090911YHD</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>快递公司:</el-text>
+      <el-text type="success">顺丰快递</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>订单来源:</el-text>
+      <el-text>微信小程序</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>订单备注:</el-text>
+      <el-text>京东</el-text>
+    </div>
+  </div>
+</template>
+
+<script setup>
+  const props = defineProps({
+    row: {
+      type: Object,
+      default: () => {}
+    }
+  });
+</script>

+ 256 - 0
src/views/recycleOrder/components/order-page.vue

@@ -0,0 +1,256 @@
+<template>
+  <ele-page flex-table>
+    <!-- 搜索表单 -->
+    <order-search @search="reload" />
+    <ele-card :body-style="{ paddingTop: '8px' }" flex-table>
+      <!-- 表格 -->
+      <ele-pro-table
+        ref="tableRef"
+        row-key="postId"
+        :columns="columns"
+        :datasource="datasource"
+        :show-overflow-tooltip="true"
+        v-model:selections="selections"
+        highlight-current-row
+        :export-config="{ fileName: pageConfig.fileName }"
+        :cache-key="pageConfig.cacheKey"
+      >
+        <template #toolbar>
+          <slot name="toolbar"></slot>
+        </template>
+
+        <template #status="{ row }">
+          <dict-data
+            code="sys_normal_disable"
+            type="tag"
+            :model-value="row.status"
+          />
+        </template>
+        <template #orderNumber="{ row }">
+          <order-number :row="row"></order-number>
+        </template>
+        <template #customer="{ row }">
+          <order-customer :row="row"></order-customer>
+        </template>
+        <template #amount="{ row }">
+          <order-amount :row="row"></order-amount>
+        </template>
+        <template #time="{ row }">
+          <order-time :row="row"></order-time>
+        </template>
+        <template #remarks="{ row }">
+          <el-popover trigger="hover" width="240px">
+            <template #reference>
+              <el-button
+                :icon="Flag"
+                link
+                style="font-size: 20px"
+                @click="handleRemarks(row)"
+              >
+              </el-button>
+            </template>
+            <orderTimeline
+              :records="activities"
+              title="备注历史记录"
+            ></orderTimeline>
+          </el-popover>
+        </template>
+
+        <template #action="{ row }">
+          <slot name="action" :row="row"></slot>
+        </template>
+      </ele-pro-table>
+    </ele-card>
+
+    <slot></slot>
+    <orderRemarks ref="remarksRef" />
+  </ele-page>
+</template>
+
+<script setup>
+  import { ref, getCurrentInstance } from 'vue';
+  import { ElMessageBox } from 'element-plus/es';
+  import { EleMessage } from 'ele-admin-plus/es';
+  import { DownloadOutlined } from '@/components/icons';
+  import { Flag, ChatDotSquare } from '@element-plus/icons-vue';
+  import OrderSearch from '../components/order-search.vue';
+  import OrderNumber from '@/views/recycleOrder/components/order-number.vue';
+  import OrderCustomer from '@/views/recycleOrder/components/order-customer.vue';
+  import OrderAmount from '@/views/recycleOrder/components/order-amount.vue';
+  import OrderTime from '@/views/recycleOrder/components/order-time.vue';
+  import { useDictData } from '@/utils/use-dict-data';
+  import { download, toFormData, checkDownloadRes } from '@/utils/common';
+  import orderRemarks from '@/views/recycleOrder/components/order-remarks.vue';
+  import orderTimeline from '@/views/recycleOrder/components/order-timeline.vue';
+
+  let props = defineProps({
+    pageConfig: {
+      type: Object,
+      default: () => ({
+        cacheKey: 'recycleOrderTable',
+        fileName: '回收订单查询'
+      })
+    },
+    pageUrl: { type: String, default: '/system/post/list' },
+    exportUrl: { type: String, default: '/system/post/export' }
+  });
+  let { proxy } = getCurrentInstance();
+  /** 字典数据 */
+  const [statusDicts] = useDictData(['sys_normal_disable']);
+
+  /** 表格实例 */
+  const tableRef = ref(null);
+
+  /** 表格列配置 */
+  const columns = ref([
+    {
+      type: 'selection',
+      columnKey: 'selection',
+      width: 50,
+      align: 'center',
+      fixed: 'left'
+    },
+    { label: '单号', prop: 'orderNumber', slot: 'orderNumber', minWidth: 180 },
+    { label: '客户', prop: 'customer', slot: 'customer', minWidth: 360 },
+    { label: '金额', prop: 'amount', slot: 'amount', minWidth: 160 },
+    {
+      label: '状态',
+      prop: 'status',
+      slot: 'status',
+      formatter: (row) =>
+        statusDicts.value.find((d) => d.dictValue == row.status)?.dictLabel
+    },
+    { label: '时间', prop: 'time', slot: 'time', minWidth: 200 },
+    { label: '备注', prop: 'remarks', slot: 'remarks' },
+    {
+      columnKey: 'action',
+      label: '操作',
+      width: 180,
+      align: 'center',
+      slot: 'action',
+      hideInPrint: true,
+      hideInExport: true
+    }
+  ]);
+
+  /** 表格选中数据 */
+  const selections = ref([]);
+
+  /** 当前编辑数据 */
+  const current = ref(null);
+
+  /** 是否显示编辑弹窗 */
+  const showEdit = ref(false);
+
+  async function queryPage(params) {
+    const res = await proxy.$http.get(props.pageUrl, { params });
+    if (res.data.code === 200) {
+      return res.data;
+    }
+    return Promise.reject(new Error(res.data.msg));
+  }
+
+  /** 表格数据源 */
+  const datasource = ({ pages, where, orders }) => {
+    return queryPage({ ...where, ...orders, ...pages });
+  };
+
+  /** 搜索 */
+  const reload = (where) => {
+    tableRef.value?.reload?.({ page: 1, where });
+  };
+
+  /** 批量操作 */
+  const operatBatch = ({ row, url, title }) => {
+    const rows = row == null ? selections.value : [row];
+    if (!rows.length) {
+      EleMessage.error('请至少选择一条数据');
+      return;
+    }
+    title = title || '是否确认当前操作?';
+    ElMessageBox.confirm(title, '提示', {
+      type: 'warning',
+      draggable: true
+    })
+      .then(() => {
+        const loading = EleMessage.loading({
+          message: '请求中..',
+          plain: true
+        });
+
+        proxy.$http
+          .delete(url)
+          .then(() => {
+            loading.close();
+            EleMessage.success('操作成功');
+            reload();
+          })
+          .catch((e) => {
+            loading.close();
+            EleMessage.error(e.message);
+          });
+      })
+      .catch(() => {});
+  };
+
+  /// 导出数据
+  async function exportPage(params, name) {
+    const res = await proxy.$http({
+      url: props.exportUrl,
+      method: 'POST',
+      data: toFormData(params),
+      responseType: 'blob'
+    });
+    await checkDownloadRes(res);
+    download(
+      res.data,
+      name ? `${name}_${Date.now()}.xlsx` : `post_${Date.now()}.xlsx`
+    );
+  }
+
+  /** 导出数据 */
+  const exportData = (name) => {
+    const loading = EleMessage.loading({
+      message: '请求中..',
+      plain: true
+    });
+    tableRef.value?.fetch?.(({ where, orders }) => {
+      exportPage({ ...where, ...orders }, name)
+        .then(() => {
+          loading.close();
+        })
+        .catch((e) => {
+          loading.close();
+          EleMessage.error(e.message);
+        });
+    });
+  };
+
+  //修改备注
+  const remarksRef = ref(null);
+  function handleRemarks(row) {
+    remarksRef.value?.handleOpen(row);
+  }
+  const activities = [
+    {
+      content: 'Event start',
+      timestamp: '2018-04-15',
+      color: '#0bbd87',
+      icon: ChatDotSquare
+    },
+    {
+      content: 'Approved',
+      timestamp: '2018-04-13',
+      color: '#0bbd87',
+      icon: ChatDotSquare
+    },
+    {
+      content: 'Success',
+      timestamp: '2018-04-11',
+      color: '#0bbd87',
+      icon: ChatDotSquare
+    }
+  ];
+
+  defineExpose({ reload, exportData, operatBatch });
+</script>

+ 123 - 0
src/views/recycleOrder/components/order-remarks.vue

@@ -0,0 +1,123 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal
+    form
+    :width="760"
+    v-model="visible"
+    title="回收订单备注"
+    @open="handleOpen"
+  >
+    <el-form
+      ref="formRef"
+      :model="form"
+      :rules="rules"
+      label-width="80px"
+      @submit.prevent=""
+    >
+      <el-form-item label="选择标签" prop="tag">
+        <el-radio-group v-model="form.tag">
+          <el-radio :value="1"
+            ><el-icon color="#67C23A" :size="18"><Flag /></el-icon
+          ></el-radio>
+          <el-radio :value="2"
+            ><el-icon color="#409EFF" :size="18"><Flag /></el-icon
+          ></el-radio>
+          <el-radio :value="3"
+            ><el-icon color="#E6A23C" :size="18"><Flag /></el-icon
+          ></el-radio>
+          <el-radio :value="4"
+            ><el-icon color="#F56C6C" :size="18"><Flag /></el-icon
+          ></el-radio>
+          <el-radio :value="5"
+            ><el-icon color="#7728f5" :size="18"><Flag /></el-icon
+          ></el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="备注信息" prop="remark">
+        <el-input
+          :rows="4"
+          type="textarea"
+          v-model="form.remark"
+          placeholder="请输入备注"
+        />
+      </el-form-item>
+     
+    </el-form>
+
+    <orderTimeline :records="activities" title="备注历史记录"></orderTimeline>
+
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleCancel">确定</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+  import { Flag,ChatDotSquare } from '@element-plus/icons-vue';
+  import orderTimeline from '@/views/recycleOrder/components/order-timeline.vue';
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+  };
+
+  /** 弹窗打开事件 */
+  const handleOpen = () => {
+    visible.value = true;
+    nextTick(() => console.log('打开'));
+  };
+
+  const form = reactive({
+    tag: '',
+    remark: ''
+  });
+  /** 表单验证规则 */
+  const rules = reactive({
+    tag: [
+      {
+        required: true,
+        message: '请选择标签',
+        type: 'string',
+        trigger: 'change'
+      }
+    ],
+    remark: [
+      {
+        required: true,
+        message: '请输入备注信息',
+        type: 'string',
+        trigger: 'blur'
+      }
+    ]
+  });
+
+  const activities = [
+    {
+      content: 'Event start',
+      timestamp: '2018-04-15',
+      color: '#0bbd87',
+      icon:ChatDotSquare
+    },
+    {
+      content: 'Approved',
+      timestamp: '2018-04-13',
+      color: '#0bbd87',
+      icon:ChatDotSquare
+    },
+    {
+      content: 'Success',
+      timestamp: '2018-04-11',
+      color: '#0bbd87',
+      icon:ChatDotSquare
+    }
+  ];
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 125 - 0
src/views/recycleOrder/components/order-search.vue

@@ -0,0 +1,125 @@
+<!-- 搜索表单 -->
+<template>
+  <ele-card :body-style="{ paddingBottom: '8px' }">
+    <ProSearch :columns="columns" v-model:form="form" ref="searchRef">
+      <el-col :span="6" style="min-width: 160px">
+        <el-button style="width: 80px" type="primary" plain @click="search"
+          >查询</el-button
+        >
+        <el-button style="width: 80px" type="info" @click="reset"
+          >重置</el-button
+        >
+      </el-col>
+    </ProSearch>
+  </ele-card>
+</template>
+
+<script setup>
+  import { reactive, ref, defineEmits } from 'vue';
+  import { useFormData } from '@/utils/use-form-data';
+  import ProSearch from '@/components/CommonPage/ProSearch.vue';
+
+  const emit = defineEmits(['search']);
+  const columns = reactive([
+    { tag: 'el-input', label: '发件人名称', prop: 'senderName', span: 4 },
+    { tag: 'el-input', label: '发件人电话', prop: 'senderPhone', span: 4 },
+    {
+      tag: 'el-input',
+      label: '发件人地址(仅查询7天内数据)',
+      prop: 'senderAddress',
+      span: 5
+    },
+    { tag: 'el-input', label: '用户名', prop: 'userName', span: 4 },
+    {
+      tag: 'el-input',
+      label: '搜索备注关键字',
+      prop: 'searchRemarks',
+      span: 4
+    },
+    {
+      tag: 'el-select',
+      label: '收货仓库',
+      prop: 'receivingWarehouse',
+      span: 3
+    },
+    { tag: 'el-select', label: '全部订单', prop: 'allOrders', span: 3 },
+    {
+      tag: 'el-select',
+      label: '物流公司',
+      prop: 'logisticsCompany',
+      span: 3
+    },
+    { tag: 'el-select', label: '全部方式', prop: 'allMethods', span: 3 },
+    {
+      tag: 'el-date-picker',
+      label: '建单时间(开始时间)',
+      prop: 'orderStartTime',
+      span: 3,
+      tagAttrs: {
+        valueFormat: 'YYYY-MM-DD',
+      }
+    },
+    {
+      tag: 'el-date-picker',
+      label: '建单时间(结束时间)',
+      prop: 'orderEndTime',
+      span: 4,
+      tagAttrs: {
+        valueFormat: 'YYYY-MM-DD',
+      }
+    },
+    {
+      tag: 'el-date-picker',
+      label: '建单时间(开始时间)',
+      prop: 'orderStartTime',
+      span: 4,
+      tagAttrs: {
+        valueFormat: 'YYYY-MM-DD',
+      }
+    },
+    {
+      tag: 'el-date-picker',
+      label: '建单时间(结束时间)',
+      prop: 'orderEndTime',
+      span: 4,
+      tagAttrs: {
+        valueFormat: 'YYYY-MM-DD',
+      }
+    },
+    {
+      tag: 'el-input',
+      label: '订单编号(多个以中文逗号、空格或换行分割)',
+      prop: 'orderNumber',
+      span: 6
+    },
+    {
+      tag: 'el-input',
+      label: '物流单号(多个以中文逗号、空格或换行分割)',
+      prop: 'logisticsNumber',
+      span: 6
+    }
+  ]);
+
+  const initKeys = {};
+  for (let i = 0; i < columns.length; i++) {
+    initKeys[columns[i].prop] = '';
+  }
+
+  /** 表单数据 */
+  const [form, resetFields] = useFormData({
+    ...initKeys
+  });
+
+  const searchRef = ref(null);
+  /** 搜索 */
+  const search = () => {
+    console.log(form, '[form]');
+    emit('search', { ...form });
+  };
+
+  /** 重置 */
+  const reset = () => {
+    resetFields();
+    search();
+  };
+</script>

+ 25 - 0
src/views/recycleOrder/components/order-time.vue

@@ -0,0 +1,25 @@
+<template>
+  <div class="recycle-order-number">
+    <div class="comon-text">
+      <el-text>建单:</el-text>
+      <el-text>2024-11-08 21:09:19</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>提交:</el-text>
+      <el-text>2024-11-08 21:09:19</el-text>
+    </div>
+    <div class="comon-text">
+      <el-text>预约:</el-text>
+      <el-text>2024-11-08 21:09:19</el-text>
+    </div>
+  </div>
+</template>
+
+<script setup>
+  const props = defineProps({
+    row: {
+      type: Object,
+      default: () => {}
+    }
+  });
+</script>

+ 29 - 0
src/views/recycleOrder/components/order-timeline.vue

@@ -0,0 +1,29 @@
+<template>
+  <div class="demo-timeline" v-if="records.length">
+    <div style="margin-bottom: 10px">{{ title }}</div>
+    <el-timeline>
+      <el-timeline-item
+        v-for="(item, index) in records"
+        :key="index"
+        :timestamp="item.timestamp"
+        :icon="item.icon"
+        :color="item.color"
+      >
+        {{ item.content }}
+      </el-timeline-item>
+    </el-timeline>
+  </div>
+</template>
+
+<script setup>
+  const props = defineProps({
+    records: {
+      type: Array,
+      default: () => []
+    },
+    title: {
+      type: String,
+      default: ''
+    }
+  });
+</script>

+ 92 - 0
src/views/recycleOrder/components/send-SMS.vue

@@ -0,0 +1,92 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal form :width="800" v-model="visible" title="推送短信">
+    <el-form
+      ref="formRef"
+      :model="form"
+      :rules="rules"
+      label-width="80px"
+      @submit.prevent=""
+    >
+      <el-form-item label="短信类型" prop="paymentType">
+        <el-radio-group v-model="form.paymentType">
+          <el-radio :value="1">部分未收到</el-radio>
+          <el-radio :value="2">有多出书籍</el-radio>
+          <el-radio :value="3">书籍与订单不符</el-radio>
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="短信预览" prop="remark">
+        <el-input
+          :rows="4"
+          type="textarea"
+          v-model="form.remark"
+          placeholder="请输入短信预览"
+        />
+      </el-form-item>
+      <el-form-item label="推送历史" prop="records">
+        <SimpleTable style="width: 100%" :columns="columns"></SimpleTable>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleCancel">确定</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+  import { Flag, ChatDotSquare } from '@element-plus/icons-vue';
+  import orderTimeline from '@/views/recycleOrder/components/order-timeline.vue';
+  import SimpleTable from '@/components/CommonPage/SimpleTable.vue';
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+  };
+
+  /** 弹窗打开事件 */
+  const handleOpen = () => {
+    visible.value = true;
+    nextTick(() => console.log('打开'));
+  };
+
+  const form = reactive({
+    paymentType: '',
+    remark: '',
+  });
+  /** 表单验证规则 */
+  const rules = reactive({
+    paymentType: [
+      {
+        required: true,
+        message: '请选择短信类型',
+        type: 'string',
+        trigger: 'change'
+      }
+    ],
+    remark: [
+      {
+        required: true,
+        message: '请输入短信预览',
+        type: 'string',
+        trigger: 'blur'
+      }
+    ],
+  });
+
+  // 表格数据
+  const columns = reactive([
+    { label: '发送人', prop: 'createBy', width: 100 },
+    { label: '发送内容', prop: 'logDescription' },
+    { label: '发送时间', prop: 'createTime', width: 180 },
+  ]);
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 55 - 0
src/views/recycleOrder/components/user-bind-tag.vue

@@ -0,0 +1,55 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal
+    form
+    :width="460"
+    v-model="visible"
+    title="用户绑定标签"
+    @open="handleOpen"
+  >
+    <el-checkbox-group v-model="userTag">
+      <el-checkbox label="书商" value="Value A" />
+      <el-checkbox label="合伙人" value="Value B" />
+      <el-checkbox label="内部账号" value="Value C" />
+      <el-checkbox label="优质书商" value="Value disabled" />
+      <el-checkbox label="大书商" value="Value selected and disabled" />
+      <el-checkbox label="分销客户" value="Value d" />
+    </el-checkbox-group>
+
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleSubmit" :loading="loading"
+        >确定</el-button
+      >
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+
+  /** 弹窗是否打开 */
+  const visible = ref(false);
+  const loading = ref(false);
+
+  const userTag = ref([]);
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+  };
+
+  /** 弹窗打开事件 */
+  const handleOpen = (row) => {
+    visible.value = true;
+    nextTick(() => console.log('打开'));
+  };
+  /** 提交 */
+  const handleSubmit = () => {
+    loading.value = true;
+  };
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 5 - 0
src/views/recycleOrder/detail/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div class="order-detail">
+        详情
+    </div>
+</template>

+ 5 - 0
src/views/recycleOrder/failedAudit/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 5 - 0
src/views/recycleOrder/needReturned/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>

+ 220 - 0
src/views/recycleOrder/search/index.vue

@@ -0,0 +1,220 @@
+<template>
+  <order-page ref="pageRef" :pageConfig="pageConfig">
+    <template #toolbar>
+      <el-button
+        type="warning"
+        plain
+        class="ele-btn-icon"
+        v-permission="'recycleOrder:search:batchAudit'"
+        @click="removeBatch()"
+      >
+        批量初审
+      </el-button>
+      <el-button
+        type="success"
+        plain
+        class="ele-btn-icon"
+        :icon="DownloadOutlined"
+        v-permission="'recycleOrder:search:export'"
+        @click="exportData"
+      >
+        导出订单明细
+      </el-button>
+    </template>
+
+    <template #action="{ row }">
+      <div>
+        <el-button
+          type="success"
+          link
+          v-permission="'recycleOrder:search:detail'"
+          @click="toOrderDetail(row)"
+        >
+          [订单详情]
+        </el-button>
+        <el-button
+          type="warning"
+          link
+          v-permission="'recycleOrder:search:log'"
+          @click="openOrderLog(row)"
+        >
+          [订单日志]
+        </el-button>
+        <el-button
+          type="danger"
+          link
+          v-permission="'recycleOrder:search:cancel'"
+          @click="cancelOrder(row)"
+        >
+          [取消订单]
+        </el-button>
+        <el-button
+          type="primary"
+          link
+          v-permission="'recycleOrder:search:fallback'"
+          @click="fallbackOrder(row)"
+        >
+          [回退状态]
+        </el-button>
+        <el-button
+          type="success"
+          link
+          v-permission="'recycleOrder:search:materialPickup'"
+          @click="materialPickup(row)"
+        >
+          [物料揽件]
+        </el-button>
+        <el-button
+          type="danger"
+          link
+          v-permission="'recycleOrder:search:auditScreenshot'"
+          @click="handleAuditScreenshot(row)"
+        >
+          [审核截图]
+        </el-button>
+        <el-button
+          type="danger"
+          link
+          v-permission="'recycleOrder:search:afterSalesPayment'"
+          @click="handleAfterSalesPayment(row)"
+        >
+          [售后补款]
+        </el-button>
+        <el-button
+          type="warning"
+          link
+          v-permission="'recycleOrder:search:userTag'"
+          @click="openEditUserTag(row)"
+        >
+          [用户标签]
+        </el-button>
+        <el-button
+          type="success"
+          link
+          v-permission="'recycleOrder:search:sendSMS'"
+          @click="handleSendSMS(row)"
+        >
+          [推送短信]
+        </el-button>
+        <el-button
+          color="#7728f5"
+          link
+          plain
+          v-permission="'recycleOrder:search:applyForOrderClaim'"
+          @click="applyForOrderClaim(row)"
+        >
+          [申请订单理赔]
+        </el-button>
+      </div>
+    </template>
+
+    <order-log ref="orderLogRef" />
+    <userBindTag ref="userTagRef" />
+    <audit-screenshot ref="auditScreenshotRef"></audit-screenshot>
+    <afterSalesPayment ref="paymentRef" />
+    <applyforOrderClaim ref="claimRef"></applyforOrderClaim>
+    <sendSMS ref="smsRef"></sendSMS>
+  </order-page>
+</template>
+
+<script setup>
+  import { ref, reactive } from 'vue';
+  import { ElMessageBox } from 'element-plus/es';
+  import { EleMessage } from 'ele-admin-plus/es';
+  import { DownloadOutlined } from '@/components/icons';
+  import OrderPage from '@/views/recycleOrder/components/order-page.vue';
+  import { useDictData } from '@/utils/use-dict-data';
+  import { useRouter } from 'vue-router';
+
+  //订单日志
+  import orderLog from '@/views/recycleOrder/components/order-log.vue';
+  //用户标签
+  import userBindTag from '@/views/recycleOrder/components/user-bind-tag.vue';
+  //审核截图
+  import auditScreenshot from '@/views/recycleOrder/components/audit-screenshot.vue';
+  //售后补款
+  import afterSalesPayment from '@/views/recycleOrder/components/after-sales-payment.vue';
+  //申请订单理赔
+  import applyforOrderClaim from '@/views/recycleOrder/components/applyfor-order-claim.vue'
+  //推送短信
+  import sendSMS from '@/views/recycleOrder/components/send-SMS.vue'
+
+  defineOptions({ name: 'recycleOrderSearch' });
+
+  let router = useRouter();
+  /** 页面组件实例 */
+  const pageRef = ref(null);
+
+  const pageConfig = reactive({
+    pageUrl: '',
+    exportUrl: '',
+    fileName: '回收订单查询',
+    cacheKey: 'recycleOrderTable'
+  });
+
+  //导出数据
+  function exportData() {
+    pageRef.value?.exportData('回收订单查询');
+  }
+  //订单详情
+  function toOrderDetail(row) {
+    router.push({ path: '/recycleOrder/detail', query: { id: row.postId } });
+  }
+
+  //订单日志
+  const orderLogRef = ref(null);
+  function openOrderLog(row) {
+    console.log(row, orderLogRef.value, 'row');
+
+    orderLogRef.value?.handleOpen(row);
+  }
+
+  //用户绑定标签
+  const userTagRef = ref(null);
+  function openEditUserTag(row) {
+    userTagRef.value?.handleOpen(row);
+  }
+
+  function messageBoxConfirm({ message, url, row }) {
+    ElMessageBox.confirm(message, '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '关闭',
+      type: 'warning'
+    }).then(() => {
+      console.log(row, 'row');
+    });
+  }
+
+  //取消订单
+  function cancelOrder(row) {
+    messageBoxConfirm({ message: '确认取消?', url: '', row });
+  }
+  //回退状态
+  function fallbackOrder(row) {
+    messageBoxConfirm({ message: '确认回退状态?', url: '', row });
+  }
+  //物料揽件
+  function materialPickup(row) {
+    messageBoxConfirm({ message: '确认物料揽件?', url: '', row });
+  }
+  //审核截图
+  const auditScreenshotRef = ref(null);
+  function handleAuditScreenshot(row) {
+    auditScreenshotRef.value?.handleOpen(row);
+  }
+  //售后补款
+  const paymentRef = ref(null);
+  function handleAfterSalesPayment(row) {
+    paymentRef.value?.handleOpen(row);
+  }
+  //推送短信
+  const smsRef = ref(null);
+  function handleSendSMS(row) {
+    smsRef.value?.handleOpen(row);
+  }
+  //申请订单理赔
+  const claimRef = ref(null);
+  function applyForOrderClaim(row) {
+    claimRef.value?.handleOpen(row);
+  }
+</script>

+ 5 - 0
src/views/recycleOrder/urgentRecycleAudit/index.vue

@@ -0,0 +1,5 @@
+<template>
+    <div>
+        
+    </div>
+</template>