Bläddra i källkod

add 需退回订单页面&按钮权限

haveyou 1 år sedan
förälder
incheckning
5ea7c8db43

+ 1 - 1
.env.development

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

+ 1 - 1
.env.production

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

+ 0 - 5
src/api/layout/index.js

@@ -48,11 +48,6 @@ export async function getUserMenu() {
         hide: true
       }
     });
-    // 增加EleAdmin链接
-    temp.push({
-      path: 'https://plus.eleadmin.com',
-      meta: { title: 'EleAdmin', icon: 'LinkOutlined' }
-    });
     // 修改图标
     return mapTree(temp, (item) => {
       const meta =

BIN
src/assets/logo.png


+ 3 - 1
src/components/CommonPage/ProSearch.vue

@@ -1,4 +1,5 @@
 <script setup>
+  import DictData from '@/components/DictData/index.vue';
   import { ref, watch } from 'vue';
   //组件的属性
   let props = defineProps({
@@ -56,7 +57,8 @@
 
 <style lang="scss">
   .search-form {
-    ::v-deep .el-date-editor.el-input, .el-date-editor.el-input__wrapper {
+    ::v-deep .el-date-editor.el-input,
+    .el-date-editor.el-input__wrapper {
       width: 100%;
     }
   }

+ 73 - 0
src/components/CommonPage/SimpleForm.vue

@@ -0,0 +1,73 @@
+<!-- 编辑弹窗 -->
+<template>
+  <pro-form
+    v-bind="$attrs"
+    ref="proFormRef"
+    :model="form"
+    :items="items"
+    :grid="{ span: gird }"
+    @updateValue="setFieldValue"
+  >
+    <template v-for="(val, key) in slotArray" v-slot:[key]="{ row }">
+      <slot :name="key" :row="row"></slot>
+    </template>
+  </pro-form>
+</template>
+
+<script setup>
+  import { ref, useSlots } from 'vue';
+  import { useFormData } from '@/utils/use-form-data';
+  import ProForm from '@/components/ProForm/index.vue';
+  const slotArray = useSlots();
+
+  const proFormRef = ref(null);
+  const props = defineProps({
+    items: {
+      type: Array,
+      default() {
+        return [];
+      }
+    },
+    initKeys: {
+      type: Object,
+      default() {
+        return {};
+      }
+    },
+    gird: {
+      type: Number,
+      default: 24
+    }
+  });
+  const [form, resetFields, assignFields, setFieldValue] = useFormData(
+    props.initKeys
+  );
+  console.log(form, 'form');
+  /** 提交表单 */
+  const submitForm = () => {
+    return new Promise((resolve, reject) => {
+      proFormRef.value?.validate?.((valid) => {
+        if (valid) {
+          resolve(form);
+        } else {
+          reject('表单验证失败');
+        }
+      });
+    });
+  };
+
+  /** 重置表单 */
+  const resetForm = () => {
+    resetFields();
+    nextTick(() => {
+      proFormRef.value?.clearValidate?.();
+    });
+  };
+
+  defineExpose({
+    resetFields,
+    assignFields,
+    submitForm,
+    resetForm
+  });
+</script>

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

@@ -8,6 +8,7 @@
     highlight-current-row
     :pagination="false"
     :tools="false"
+    v-bind="$attrs"
   >
     <template v-for="(val, key) in slotArray" v-slot:[key]="{ row }">
       <slot :name="key" :row="row"></slot>

+ 0 - 1
src/components/DictData/index.vue

@@ -10,7 +10,6 @@
       v-for="item in valueData"
       :key="item.dictCode"
       :disable-transitions="true"
-      size="small"
       :type="item.listClass === 'default' ? 'primary' : item.listClass"
     >
       {{ item.dictLabel }}

+ 18 - 0
src/styles/index.scss

@@ -57,6 +57,7 @@ body {
     padding-left: 20px;
   }
 }
+
 //订单详情
 .order-detail {
   .el-step.is-center .el-step__description {
@@ -136,6 +137,10 @@ body {
   .el-button+.el-button {
     margin-left: 0;
   }
+
+  .el-text {
+    align-self: flex-start;
+  }
 }
 
 //搜索况下时间选择框的样式
@@ -179,3 +184,16 @@ html.disabled-transition :not(.view-transition-trigger) * {
     margin-bottom: 6px;
   }
 }
+
+//表单中基础样式
+.el-form {
+  .is-without-controls {
+    .el-input .el-input__wrapper {
+      padding-left: 10px;
+    }
+
+    .el-input-number .el-input__inner {
+      text-align: left !important;
+    }
+  }
+}

+ 81 - 0
src/utils/validators.js

@@ -0,0 +1,81 @@
+const validators = {
+  // 验证手机号码(简单验证,仅针对常见格式)
+  phone: {
+    pattern: /^1[3-9]\d{9}$/,
+    message: '请输入正确的手机号码'
+  },
+
+  // 验证电子邮箱
+  email: {
+    pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
+    message: '请输入正确的电子邮箱地址'
+  },
+
+  // 验证身份证号码(简单验证,不考虑所有特殊情况)
+  idCard: {
+    pattern: /^\d{15}(\d{2}[a-zA-Z0-9])?$/,
+    message: '请输入正确的身份证号码'
+  },
+
+  // 验证纯数字(可用于验证数量、页码等)
+  number: {
+    pattern: /^\d+$/,
+    message: '请输入数字'
+  },
+
+  // 验证是否为正整数
+  positiveInteger: {
+    pattern: /^[1-9]\d*$/,
+    message: '请输入正整数'
+  },
+
+  // 验证是否为非负整数(包含0和正整数)
+  nonNegativeInteger: {
+    pattern: /^\d*$/,
+    message: '请输入非负整数'
+  },
+
+  // 验证是否包含中文
+  chinese: {
+    pattern: /[\u4e00-\u9fa5]+/,
+    message: '请输入包含中文的内容'
+  },
+
+  // 验证是否只包含英文字母(大写或小写)
+  englishLetters: {
+    pattern: /^[a-zA-Z]+$/,
+    message: '请输入只包含英文字母的内容'
+  },
+
+  // 验证是否只包含英文字母和数字
+  englishLettersAndNumbers: {
+    pattern: /^[a-zA-Z0-9]+$/,
+    message: '请输入只包含英文字母和数字的内容'
+  },
+
+  // 验证密码强度(至少包含一个大写字母、一个小写字母、一个未雨绸缪、一个数字和一个特殊字符,长度至少8位)
+  passwordStrength: {
+    pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$/,
+    message:
+      '请输入至少包含一个大写字母、一个小写字母、一个数字和一个特殊字符,且长度至少8位的密码'
+  },
+
+  // 验证URL格式(简单验证)
+  url: {
+    pattern: /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/,
+    message: '请输入正确的URL地址'
+  },
+
+  // 大于0小于1且最多两位小数验证
+  decimalRange: {
+    pattern: /^(0\.\d{1,2}|0[1-9]\d{0,1}\.\d{1,2}|1)$/,
+    message: '请输入大于0小于1且最多两位小数的数值'
+  },
+
+  money:{
+    pattern: /^(([1-9]{1}\d*)|([0]{1}))(\.\d{1,2})?$/,
+    message:'请输入正确的金额'
+  },
+};
+
+export default validators;

+ 10 - 2
src/views/recycleOrder/components/order-customer.vue

@@ -1,9 +1,13 @@
 <template>
   <div class="recycle-order-number">
-    <div class="common-text">
+    <div class="common-text" v-if="!isReturn">
       <el-text>用户名:</el-text>
       <el-text>77184923212132138219312323</el-text>
     </div>
+    <div class="common-text" v-if="isReturn">
+      <el-text>昵称:</el-text>
+      <el-text>微信用户 <el-tag type="success" size="small">微信</el-tag> </el-text>
+    </div>
     <div class="common-text">
       <el-text>发件人:</el-text>
       <el-text v-if="row.deliveryCode">暂无信息</el-text>
@@ -17,7 +21,7 @@
       <el-text>地址:</el-text>
       <el-text>谭中街道文昌路2号科技大学文昌路校区宿舍B区</el-text>
     </div>
-    <div class="common-text">
+    <div class="common-text" v-if="!isReturn">
       <el-text>标签:</el-text>
       <el-text>暂无信息</el-text>
     </div>
@@ -29,6 +33,10 @@
     row: {
       type: Object,
       default: () => {}
+    },
+    isReturn: {
+      type: Boolean,
+      default: false
     }
   });
 </script>

+ 23 - 8
src/views/recycleOrder/components/order-number.vue

@@ -1,9 +1,13 @@
 <template>
   <div class="recycle-order-number">
-    <div class="common-text">
+    <div class="common-text" v-if="!isReturn">
       <el-text>订单号:</el-text>
       <el-text type="danger">7718492</el-text>
     </div>
+    <div class="common-text" v-if="isReturn">
+      <el-text>退回编号:</el-text>
+      <el-text type="danger">31231321321321</el-text>
+    </div>
     <div class="common-text">
       <el-text>快递单号:</el-text>
       <el-text v-if="!row.deliveryCode">暂无信息</el-text>
@@ -13,13 +17,20 @@
       <el-text>快递公司:</el-text>
       <el-text type="success">顺丰快递</el-text>
     </div>
-    <div class="common-text">
-      <el-text>订单来源:</el-text>
-      <el-text>微信小程序</el-text>
-    </div>
-    <div class="common-text">
-      <el-text>订单备注:</el-text>
-      <el-text>京东</el-text>
+    <template v-if="!isReturn">
+      <div class="common-text">
+        <el-text>订单来源:</el-text>
+        <el-text>微信小程序</el-text>
+      </div>
+      <div class="common-text">
+        <el-text>订单备注:</el-text>
+        <el-text>京东</el-text>
+      </div>
+    </template>
+
+    <div class="common-text" v-if="isReturn">
+      <el-text>回收订单:</el-text>
+      <el-text>2732781321</el-text>
     </div>
   </div>
 </template>
@@ -29,6 +40,10 @@
     row: {
       type: Object,
       default: () => {}
+    },
+    isReturn: {
+      type: Boolean,
+      default: false
     }
   });
 </script>

+ 68 - 0
src/views/recycleOrder/detail/order-blacklist.vue

@@ -0,0 +1,68 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal
+    form
+    :width="460"
+    v-model="visible"
+    title="加入黑名单"
+    @open="handleOpen"
+  >
+    <SimpleForm
+      :items="items"
+      labelWidth="90px"
+      ref="formRef"
+      :initKeys="form"
+    ></SimpleForm>
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleSumbit">确定</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+  import SimpleForm from '@/components/CommonPage/SimpleForm.vue';
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+    nextTick(() => {
+      formRef.value?.resetForm();
+    });
+  };
+
+  const form = reactive({
+    reason: ''
+  });
+  /** 弹窗打开事件 */
+  const handleOpen = () => {
+    visible.value = true;
+    nextTick(() => {
+      formRef.value?.assignFields(form);
+    });
+  };
+
+  const items = reactive([
+    {
+      label: '拉黑原因',
+      prop: 'reason',
+      type: 'dictSelect',
+      required: true
+    }
+  ]);
+
+  const formRef = ref();
+  const handleSumbit = () => {
+    formRef.value?.submitForm().then((data) => {
+      visible.value = false;
+    });
+  };
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 100 - 10
src/views/recycleOrder/detail/order-book-list.vue

@@ -12,20 +12,36 @@
             <div><el-text type="primary">作物栽培</el-text></div>
             <div><el-text>ISBN:9787109261839</el-text></div>
             <div class="base-info-btns flex">
-              <el-button size="small" color="#4f4f4f" @click=""
+              <el-button
+                size="small"
+                color="#4f4f4f"
+                @click="handleBlackList(row)"
                 >加入黑名单</el-button
               >
-              <el-button size="small" type="success" @click=""
+              <el-button
+                size="small"
+                type="success"
+                @click="handleAddBookList(row)"
                 >加入回收书单</el-button
               >
-              <el-button size="small" type="warning" @click=""
+              <el-button
+                size="small"
+                type="warning"
+                @click="handleSpecifiedDiscount(row)"
                 >指定回收折扣</el-button
               >
-              <el-button size="small" color="#7728f5" @click=""
+              <el-button
+                size="small"
+                color="#7728f5"
+                @click="handleModifyDiscount(row)"
                 >修改回收折扣</el-button
               >
             </div>
-            <div><el-text type="danger">(已回收数量:200当前库存:75)</el-text></div>
+            <div
+              ><el-text type="danger"
+                >(已回收数量:200当前库存:75)</el-text
+              ></div
+            >
           </div>
         </div>
         <div class="base-info-right w-36 shrink-0">
@@ -51,11 +67,25 @@
     <template #action="{ row }">
       <div class="action-btns">
         <el-button class="mb-10" color="#4f4f4f" @click="">审核图片</el-button>
-        <el-button class="mb-10" color="#a4adb3" @click="">查看当当</el-button>
-        <el-button class="mb-10" color="#e99d42" @click="">回收日志</el-button>
-        <el-button class="mb-10" color="#f27606" @click="">查看淘宝</el-button>
-        <el-button color="#0f7dc7" @click="">售价日志</el-button>
-        <el-button color="#399420" @click="">查看豆瓣</el-button>
+        <el-button
+          class="mb-10"
+          color="#a4adb3"
+          @click="handleViewUrl(row, 'dd')"
+          >查看当当</el-button
+        >
+        <el-button class="mb-10" color="#e99d42" @click="handleRecycleLog(row)"
+          >回收日志</el-button
+        >
+        <el-button
+          class="mb-10"
+          color="#f27606"
+          @click="handleViewUrl(row, 'tb')"
+          >查看淘宝</el-button
+        >
+        <el-button color="#0f7dc7" @click="handleSalesLog(row)">售价日志</el-button>
+        <el-button color="#399420" @click="handleViewUrl(row, 'db')"
+          >查看豆瓣</el-button
+        >
       </div>
     </template>
     <template #auditInfo="{ row }">
@@ -75,11 +105,21 @@
       </div>
     </template>
   </SimpleTable>
+  <orderSpecifiedDiscount ref="specifiedRef" />
+  <orderModifyDiscount ref="modifyRef" />
+  <orderBlacklist ref="blacklistRef" />
+  <orderRecycleLog ref="recycleLogRef" />
+  <orderSalesLog ref="salesLogRef" />
 </template>
 
 <script setup>
   import { ref, reactive } from 'vue';
   import SimpleTable from '@/components/CommonPage/SimpleTable.vue';
+  import orderSpecifiedDiscount from '@/views/recycleOrder/detail/order-specified-discount.vue';
+  import orderModifyDiscount from '@/views/recycleOrder/detail/order-modify-discount.vue';
+  import orderBlacklist from '@/views/recycleOrder/detail/order-blacklist.vue';
+  import orderRecycleLog from '@/views/recycleOrder/detail/order-recycle-log.vue';
+  import orderSalesLog from '@/views/recycleOrder/detail/order-sales-log.vue';
 
   const columns = ref([
     {
@@ -117,6 +157,56 @@
       minWidth: 120
     }
   ]);
+
+  //查看当当、淘宝、豆瓣链接
+  const handleViewUrl = (row, type) => {
+    let url = '';
+    if (type == 'dd') {
+      url = 'https://search.dangdang.com/?key=9787310027446&act=input';
+    } else if (type == 'tb') {
+      url =
+        'https://s.taobao.com/search?page=1&q=9787310027446&sort=sale-desc&tab=all';
+    } else if (type == 'db') {
+      url =
+        'https://search.douban.com/book/subject_search?search_text=9787310027446';
+    }
+    window.open(url, '_blank');
+  };
+  //加入回收书单
+  const handleAddBookList = (row) => {
+    ElMessageBox.confirm('确认加入回收书单?', '提示', {
+      confirmButtonText: '确定',
+      cancelButtonText: '关闭',
+      type: 'warning'
+    }).then(() => {
+      console.log(row, 'row');
+    });
+  };
+  //修改回收折扣
+  const modifyRef = ref();
+  const handleModifyDiscount = (row) => {
+    modifyRef.value?.handleOpen(row);
+  };
+  //指定回收折扣
+  const specifiedRef = ref();
+  const handleSpecifiedDiscount = (row) => {
+    specifiedRef.value?.handleOpen(row);
+  };
+  //加入黑名单
+  const blacklistRef = ref();
+  const handleBlackList = (row) => {
+    blacklistRef.value?.handleOpen(row);
+  };
+  //查看回收日志
+  const recycleLogRef = ref();
+  const handleRecycleLog = (row) => {
+    recycleLogRef.value?.handleOpen(row);
+  };
+  //查看售价日志
+  const salesLogRef = ref();
+  const handleSalesLog = (row) => {
+    salesLogRef.value?.handleOpen(row);
+  };
 </script>
 
 <style lang="scss">

+ 97 - 0
src/views/recycleOrder/detail/order-modify-discount.vue

@@ -0,0 +1,97 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal
+    form
+    :width="560"
+    v-model="visible"
+    title="修改回收折扣"
+    @open="handleOpen"
+  >
+    <SimpleForm
+      :items="items"
+      labelWidth="140px"
+      ref="formRef"
+      :initKeys="form"
+    ></SimpleForm>
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleSumbit">确定</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 SimpleForm from '@/components/CommonPage/SimpleForm.vue';
+  import validators from '@/utils/validators';
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+    nextTick(() => {
+      formRef.value?.resetForm();
+    });
+  };
+
+  const form = reactive({
+    maxCount: '',
+    discount: '0.01',
+    number: '',
+    status: '1'
+  });
+  /** 弹窗打开事件 */
+  const handleOpen = () => {
+    visible.value = true;
+    nextTick(() => {
+      formRef.value?.assignFields(form);
+    });
+  };
+
+  const items = reactive([
+    {
+      label: '回收折扣',
+      prop: 'discount',
+      type: 'input',
+      required: true,
+      rules: [validators.decimalRange]
+    },
+    {
+      label: '最大回收数量',
+      prop: 'maxCount',
+      type: 'input',
+      required: true,
+      rules: [validators.nonNegativeInteger]
+    },
+    {
+      label: '单个订单回收数量',
+      prop: 'number',
+      type: 'input',
+      required: true,
+      rules: [validators.nonNegativeInteger]
+    },
+    {
+      label: '状态',
+      prop: 'status',
+      type: 'dictRadio',
+      props: { code: 'discount_status' },
+      required: true
+    }
+  ]);
+
+  const formRef = ref();
+  const handleSumbit = () => {
+    formRef.value?.submitForm().then((data) => {
+      visible.value = false;
+      console.log(data);
+    });
+  };
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 78 - 0
src/views/recycleOrder/detail/order-recycle-log.vue

@@ -0,0 +1,78 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal form :width="1080" v-model="visible" title="回收修改日志">
+    <SimpleTable style="width: 100%" :columns="columns" border>
+      <template #discount="{ row }">
+        <div class="flex flex-col align-center">
+          <el-text>折扣:1.5折</el-text>
+          <el-text>价格:¥ 1.61元</el-text>
+        </div>
+      </template>
+      <template #recycleTime="{ row }">
+        <div class="flex flex-col align-center">
+          <el-text>开始回收时间:{{ row.createTime }}</el-text>
+          <el-text>结束回收时间:{{ row.createTime }}</el-text>
+        </div>
+      </template>
+      <template #modifyInfo="{ row }">
+        <div class="flex flex-col align-center">
+          <el-text>修改人:{{ row.createBy }}</el-text>
+          <el-text>修改时间:{{ row.createTime }}</el-text>
+        </div>
+      </template>
+    </SimpleTable>
+
+    <template #footer>
+      <el-button @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 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 columns = reactive([
+    { label: '修改后状态', prop: 'createBy', minWidth: 120 },
+    {
+      label: '修改后折扣',
+      prop: 'discount',
+
+      slot: 'discount',
+      minWidth: 120
+    },
+    {
+      label: '回收时间',
+      prop: 'recycleTime',
+
+      slot: 'recycleTime',
+      minWidth: 200
+    },
+    {
+      label: '修改信息',
+      prop: 'modifyInfo',
+      slot: 'modifyInfo',
+      minWidth: 300
+    }
+  ]);
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 43 - 0
src/views/recycleOrder/detail/order-sales-log.vue

@@ -0,0 +1,43 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal form :width="1080" v-model="visible" title="售价日志">
+    <SimpleTable style="width: 100%" :columns="columns" border> </SimpleTable>
+
+    <template #footer>
+      <el-button @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 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 columns = reactive([
+    { label: '操作人', prop: 'createBy' },
+    { label: '价格', prop: 'createBy' },
+    { label: '规格', prop: 'discount' },
+    { label: '描述', prop: 'recycleTime' },
+    { label: '修改时间', prop: 'createTime' }
+  ]);
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 72 - 0
src/views/recycleOrder/detail/order-specified-discount.vue

@@ -0,0 +1,72 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal
+    form
+    :width="460"
+    v-model="visible"
+    title="指定回收折扣"
+    @open="handleOpen"
+  >
+    <SimpleForm
+      :items="items"
+      labelWidth="90px"
+      ref="formRef"
+      :initKeys="form"
+    ></SimpleForm>
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleSumbit">确定</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 SimpleForm from '@/components/CommonPage/SimpleForm.vue';
+  import validators from '@/utils/validators';
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+    nextTick(() => {
+      formRef.value?.resetForm();
+    });
+  };
+
+  const form = reactive({
+    discount: '0.01'
+  });
+  /** 弹窗打开事件 */
+  const handleOpen = () => {
+    visible.value = true;
+    nextTick(() => {
+      formRef.value?.assignFields(form);
+    });
+  };
+
+  const items = reactive([
+    {
+      label: '回收折扣',
+      prop: 'discount',
+      type: 'input',
+      required: true,
+      rules: [validators.decimalRange]
+    }
+  ]);
+
+  const formRef = ref();
+  const handleSumbit = () => {
+    formRef.value?.submitForm().then((data) => {
+      visible.value = false;
+    });
+  };
+
+  defineExpose({
+    handleOpen
+  });
+</script>

+ 263 - 4
src/views/recycleOrder/needReturned/index.vue

@@ -1,5 +1,264 @@
 <template>
-    <div>
-        
-    </div>
-</template>
+  <ele-page flex-table>
+    <!-- 搜索表单 -->
+    <return-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: '需退回订单' }"
+        cache-key="needReturnedTable"
+        :tools="false"
+      >
+        <template #status="{ row }">
+          <dict-data
+            code="sys_normal_disable"
+            type="tag"
+            :model-value="row.status"
+          />
+        </template>
+        <template #isPush="{ row }">
+          <dict-data code="is_push" type="tag" :model-value="row.status" />
+        </template>
+        <template #isFirstOrder="{ row }">
+          <dict-data
+            code="is_first_order"
+            type="tag"
+            :model-value="row.status"
+          />
+        </template>
+        <template #orderNumber="{ row }">
+          <order-number :row="row" isReturn></order-number>
+        </template>
+        <template #customer="{ row }">
+          <order-customer :row="row" isReturn></order-customer>
+        </template>
+        <template #amount="{ row }">
+          <div class="common-text flex flex-col">
+            <el-text>余额:</el-text>
+            <el-text>邮费:¥ 0 </el-text>
+          </div>
+        </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 }">
+          <div>
+            <el-button
+              type="success"
+              link
+              v-permission="'recycleOrder:needReturned:detail'"
+              @click="toOrderDetail(row)"
+            >
+              [订单详情]
+            </el-button>
+            <el-button
+              color="#7728f5"
+              link
+              plain
+              v-permission="'recycleOrder:needReturned:manualDelivery'"
+              @click="handleManualDelivery(row)"
+            >
+              [手工发货]
+            </el-button>
+            <el-button
+              type="danger"
+              link
+              v-permission="'recycleOrder:needReturned:cancel'"
+              @click="cancelOrder(row)"
+            >
+              [取消订单]
+            </el-button>
+            <el-button
+              type="warning"
+              link
+              v-permission="'recycleOrder:needReturned:log'"
+              @click="openOrderLog(row)"
+            >
+              [订单日志]
+            </el-button>
+          </div>
+        </template>
+      </ele-pro-table>
+    </ele-card>
+
+    <slot></slot>
+    <orderRemarks ref="remarksRef" />
+    <orderLog ref="logRef" />
+  </ele-page>
+</template>
+
+<script setup>
+  import { ref, getCurrentInstance } from 'vue';
+  import { ElMessageBox } from 'element-plus/es';
+  import { Flag, ChatDotSquare } from '@element-plus/icons-vue';
+  import returnSearch from './return-search.vue';
+  import OrderNumber from '@/views/recycleOrder/components/order-number.vue';
+  import OrderCustomer from '@/views/recycleOrder/components/order-customer.vue';
+  import { useDictData } from '@/utils/use-dict-data';
+  import orderRemarks from '@/views/recycleOrder/components/order-remarks.vue';
+  import orderTimeline from '@/views/recycleOrder/components/order-timeline.vue';
+  import orderLog from '@/views/recycleOrder/components/order-log.vue'
+  import { useRouter } from 'vue-router';
+  let router = useRouter();
+
+  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: 380 },
+    { label: '金额', prop: 'amount', slot: 'amount', minWidth: 100 },
+    { label: '是否推送', prop: 'isPush', slot: 'isPush' },
+    {
+      label: '订单状态',
+      prop: 'status',
+      slot: 'status',
+      formatter: (row) =>
+        statusDicts.value.find((d) => d.dictValue == row.status)?.dictLabel
+    },
+    {
+      label: '入库状态',
+      prop: 'status',
+      slot: 'status',
+      formatter: (row) =>
+        statusDicts.value.find((d) => d.dictValue == row.status)?.dictLabel
+    },
+    { label: '是否首单', prop: 'isFirstOrder', slot: 'isFirstOrder' },
+    { label: '备注', prop: 'remarks', slot: 'remarks' },
+    {
+      columnKey: 'action',
+      label: '操作',
+      width: 120,
+      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 });
+  };
+
+  //订单详情
+  function toOrderDetail(row) {
+    router.push({ path: '/recycleOrder/detail', query: { id: row.postId } });
+  }
+  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 handleManualDelivery(row) {
+    messageBoxConfirm({ message: '确认人工发货?', url: '', row });
+  }
+  //订单日志
+  const logRef = ref(null);
+  const openOrderLog = (row) => {
+    logRef.value?.handleOpen(row);
+  };
+
+  //修改备注
+  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
+    }
+  ];
+</script>

+ 66 - 0
src/views/recycleOrder/needReturned/return-search.vue

@@ -0,0 +1,66 @@
+<!-- 搜索表单 -->
+<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: 'returnNumber', span: 4 },
+    { tag: 'el-input', label: '回收订单', prop: 'recycleOrder', span: 4 },
+    { tag: 'el-input', label: '物流单号', prop: 'logisticsNumber', span: 5 },
+    { tag: 'el-input', label: '收件人名称', prop: 'recipientName', span: 4 },
+    { tag: 'el-input', label: '收件人电话', prop: 'recipientPhone', span: 4 },
+    {
+      tag: 'el-select',
+      label: '收货仓库',
+      prop: 'receivingWarehouse',
+      span: 3
+    },
+    { tag: 'el-select', label: '全部订单', prop: 'allOrders', span: 3 },
+    {
+      tag: 'dict-data',
+      label: '是否首单',
+      prop: 'isFirstOrder',
+      span: 3,
+      tagAttrs: { code: 'is_first_order', type: 'select' }
+    }
+  ]);
+
+  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 = () => {
+    emit('search', { ...form });
+  };
+
+  /** 重置 */
+  const reset = () => {
+    resetFields();
+    search();
+  };
+</script>