Browse Source

ip营销活动页面&需退回订单待发货状态增加取消订单按钮

Alex 9 tháng trước cách đây
mục cha
commit
d8ccc3d12a

+ 1 - 1
src/views/marketing/ipMrakup/datalist/components/page-search.vue

@@ -1,6 +1,6 @@
 <!-- 搜索表单 -->
 <template>
-  <ele-card :body-style="{ padding: '0', paddingTop: '30px' }">
+  <ele-card :body-style="{ padding: '0', paddingTop: '12px' }">
     <ProSearch
       :items="formItems"
       ref="searchRef"

+ 9 - 38
src/views/marketing/ipMrakup/datalist/index.vue

@@ -12,19 +12,13 @@
         :columns="columns"
         :bodyStyle="{ padding: 0 }"
       >
-        <!-- 状态列 -->
-        <template #status="{ row }">
-          <el-tag type="success" v-if="row.status === 1">已启用</el-tag>
-          <el-tag type="danger" v-else>已禁用</el-tag>
-        </template>
-
         <!-- 操作列 -->
         <template #action="{ row }">
           <div class="action-buttons">
             <el-button
               type="primary"
               link
-              v-permission="'marketing:ipMarkup:datalist:detail'"
+              v-permission="'ipMarkup:datalist:detail'"
               @click="handleViewDetail(row)"
             >
               [查看详情]
@@ -33,10 +27,10 @@
             <el-button
               type="success"
               link
-              v-permission="'marketing:ipMarkup:datalist:share'"
+              v-permission="'ipMarkup:datalist:share'"
               @click="handleShare(row)"
             >
-              [分享订单]
+              [分享信息]
             </el-button>
           </div>
         </template>
@@ -58,8 +52,6 @@
   import PageSearch from './components/page-search.vue';
   import ViewDetail from './components/view-detail.vue';
   import ShareInfo from './components/share-info.vue';
-  import request from '@/utils/request';
-  import { DownloadOutlined } from '@/components/icons';
 
   // 表格实例
   const tableRef = ref(null);
@@ -69,27 +61,20 @@
 
   // 页面配置
   const pageConfig = reactive({
-    pageUrl: '/order/list',
-    exportUrl: '/order/export',
-    fileName: '订单管理列表',
-    cacheKey: 'orderManagementTable',
+    pageUrl: '/activity/activityUpsellInfo/pagelist',
+    exportUrl: '/activity/activityUpsellInfo/export',
+    fileName: 'IP营销数据列表',
+    cacheKey: 'ipMarketingDataList',
     rowKey: 'id'
   });
 
   // 表格列配置
   const columns = ref([
-    {
-      type: 'selection',
-      columnKey: 'selection',
-      width: 50,
-      align: 'center',
-      fixed: 'left'
-    },
     { label: '用户UID', prop: 'uid' },
     { label: '订单编号', prop: 'orderNo' },
     { label: '参与时间', prop: 'participateTime' },
-    { label: '名份', prop: 'name' },
-    { label: '地区', prop: 'region' },
+    { label: '省份', prop: 'province' },
+    { label: '地区', prop: 'city' },
     { label: '订单总本数', prop: 'totalBooks' },
     { label: '加价本数', prop: 'markupBooks' },
     { label: '订单总金额', prop: 'totalAmount' },
@@ -124,20 +109,6 @@
   const handleShare = (row) => {
     shareRef.value.openDialog(row);
   };
-
-  // 更改状态
-  const handleChangeStatus = (row, status) => {
-    const statusText = status === 1 ? '启用' : '禁用';
-    tableRef.value?.messageBoxConfirm({
-      message: `确认${statusText}该IP?`,
-      fetch: () =>
-        request.post(`/marketing/ip/changeStatus`, {
-          id: row.id,
-          status: status
-        })
-    });
-  };
-
   // 刷新表格
   const reload = () => {
     tableRef.value?.reload();

+ 5 - 1
src/views/marketing/ipMrakup/index.vue

@@ -7,6 +7,9 @@
         class="ip-markup-tabs"
         @tab-click="handleTabClick"
       >
+        <el-tab-pane label="IP加价营销" name="ipMarkup">
+          <ip-activity v-if="activeTab === 'ipMarkup'" />
+        </el-tab-pane>
         <el-tab-pane label="加价营销数据" name="datalist">
           <data-list ref="dataListRef" v-if="activeTab === 'datalist'" />
         </el-tab-pane>
@@ -30,9 +33,10 @@
   import MarkupRules from './rules/index.vue';
   import BookList from './booklist/index.vue';
   import FissionAnalysis from './fission/index.vue';
+  import IpActivity from './ipActivity/index.vue';
 
   // 当前激活的标签页
-  const activeTab = ref('datalist');
+  const activeTab = ref('ipMarkup');
   const dataListRef = ref(null);
 
   // 标签页切换事件

+ 151 - 0
src/views/marketing/ipMrakup/ipActivity/components/activity-edit.vue

@@ -0,0 +1,151 @@
+<!-- 新增/编辑加价营销活动弹窗 -->
+<template>
+  <ele-modal form :width="560" v-model="visible" :title="title">
+    <SimpleForm
+      :items="formItems"
+      labelWidth="120px"
+      ref="formRef"
+      :initKeys="formData"
+    ></SimpleForm>
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleSubmit">确定</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { reactive, ref, computed, nextTick, getCurrentInstance } from 'vue';
+  import SimpleForm from '@/components/CommonPage/SimpleForm.vue';
+  import request from '@/utils/request';
+  import { EleMessage } from 'ele-admin-plus/es';
+
+  const { proxy } = getCurrentInstance();
+  const emit = defineEmits(['success']);
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 表单标题 */
+  const title = ref('新增活动');
+
+  /** 表单引用 */
+  const formRef = ref();
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+    nextTick(() => {
+      formRef.value?.resetForm();
+    });
+  };
+
+  /** 表单数据 */
+  const formData = reactive({
+    activityName: '',
+    startTime: '',
+    endTime: '',
+    limitFirst: '1',
+    inviteNum: '',
+    timeRange: [],
+    activityId: ''
+  });
+
+  /** 表单项配置 */
+  const formItems = computed(() => {
+    return [
+      {
+        type: 'input',
+        label: '活动名称',
+        prop: 'activityName',
+        required: true
+      },
+      {
+        type: 'datetimerange',
+        label: '活动时间',
+        required: true,
+        prop: 'timeRange',
+        props: {
+          format: 'YYYY-MM-DD HH:mm:ss',
+          valueFormat: 'YYYY-MM-DD HH:mm:ss',
+          rangeSeparator: '至'
+        }
+      },
+      {
+        type: 'dictRadio',
+        label: '是否限制首单',
+        prop: 'limitFirst',
+        props: { code: 'limit_first' },
+        required: true
+      },
+      {
+        type: 'input',
+        label: '加价助力人数',
+        prop: 'inviteNum',
+        required: true
+      }
+    ];
+  });
+
+  /** 弹窗打开事件 */
+  function handleOpen(data = {}) {
+    visible.value = true;
+    title.value = data && data.id ? '编辑活动' : '新增活动';
+
+    // 重置表单数据
+    for (const key in formData) {
+      formData[key] = '';
+    }
+
+    // 设置默认值
+    formData.limitFirst = '1';
+
+    // 如果是编辑模式,合并数据
+    if (data && data.id) {
+      Object.assign(formData, data);
+      formData.activityId = data.id;
+    }
+
+    formData.timeRange = [formData.startTime, formData.endTime];
+    console.log(data, formData, 'xxxx');
+
+    nextTick(() => {
+      formRef.value?.setData(formData);
+    });
+  }
+
+  /** 提交表单 */
+  function handleSubmit() {
+    formRef.value?.submitForm().then((data) => {
+      const url = formData.activityId
+        ? '/activity/activityUpsellInfo/update'
+        : '/activity/activityUpsellInfo/add';
+
+      let params = {
+        ...data,
+        status: 1,
+        activityId: formData.activityId,
+        startTime: data.timeRange[0],
+        endTime: data.timeRange[1]
+      };
+      delete params.timeRange;
+
+      request.post(url, params).then((res) => {
+        if (res.data.code === 200) {
+          EleMessage.success('保存成功');
+          visible.value = false;
+          emit('success');
+        } else {
+          EleMessage.error(res.data.msg || '保存失败');
+        }
+      });
+    });
+  }
+
+  /** 获取省市列表 */
+  function getProvinceList(id = 1) {
+    return proxy.$http.get(`/baseinfo/districtInfo/findInfo/${id}`);
+  }
+
+  defineExpose({ handleOpen });
+</script>

+ 283 - 0
src/views/marketing/ipMrakup/ipActivity/components/area-setting.vue

@@ -0,0 +1,283 @@
+<!-- 编辑弹窗 -->
+<template>
+  <ele-modal
+    form
+    :width="1080"
+    :bodyStyle="{ 'min-height': '400px' }"
+    v-model="visible"
+    :title="title"
+    @open="handleOpen"
+  >
+    <div class="flex flex-col" v-loading="loading">
+      <div class="flex" v-for="dq in areaList" :key="dq.code">
+        <el-checkbox
+          :label="dq.name"
+          :indeterminate="isIndeterminateShow(dq)"
+          style="min-width: 100px"
+          @change="(value) => handleDqChange(value, dq)"
+        ></el-checkbox>
+
+        <div v-for="item in dq.children" class="mr-6 flex items-center">
+          <el-checkbox
+            @change="(value) => handleParentChange(value, item)"
+            :data-id="item.id"
+            v-model="item.otherSelected"
+            style="margin-right: 5px"
+            :true-value="1"
+            :false-value="0"
+            :indeterminate="isIndeterCityShow(item, 'otherSelected')"
+            v-if="item.otherSelected == 1"
+            disabled
+          ></el-checkbox>
+          <el-checkbox
+            @change="(value) => handleParentChange(value, item)"
+            :data-id="item.id"
+            v-model="item.mySelected"
+            style="margin-right: 5px"
+            :true-value="1"
+            :false-value="0"
+            :indeterminate="isIndeterCityShow(item, 'mySelected')"
+            v-else
+          ></el-checkbox>
+          <ele-popover
+            :width="400"
+            trigger="click"
+            :title="item.district"
+            :showArrow="false"
+            :disabled="isPopoverDisabled(item)"
+          >
+            <template #reference>
+              <div
+                class="flex items-center cursor-pointer"
+                :class="{ 'disabled-popover': isPopoverDisabled(item) }"
+              >
+                <el-text :type="item.mySelected == 1 ? 'primary' : ''">{{
+                  item.district
+                }}</el-text>
+                <el-text type="warning" v-if="isShowAll(item)">(全)</el-text>
+                <el-icon><CaretBottom /></el-icon>
+              </div>
+            </template>
+            <template v-for="child in item.childInfo">
+              <el-checkbox
+                @change="(value) => handleChildChange(value, item, child)"
+                :data-id="child.id"
+                :label="child.district"
+                v-model="child.otherSelected"
+                :true-value="1"
+                :false-value="0"
+                v-if="child.otherSelected == 1"
+                disabled
+              ></el-checkbox>
+              <el-checkbox
+                v-else
+                @change="(value) => handleChildChange(value, item, child)"
+                :data-id="child.id"
+                v-model="child.mySelected"
+                :label="child.district"
+                :true-value="1"
+                :false-value="0"
+              ></el-checkbox>
+            </template>
+          </ele-popover>
+        </div>
+      </div>
+    </div>
+
+    <template #footer>
+      <el-button @click="handleCancel">关闭</el-button>
+      <el-button type="primary" @click="handleSubmit">确定</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script setup>
+  import { ref, reactive, nextTick } from 'vue';
+  import request from '@/utils/request';
+  import { ElMessage } from 'element-plus';
+  import { CaretBottom, CaretTop } from '@element-plus/icons-vue';
+
+  /** 弹窗是否打开 */
+  const visible = defineModel({ type: Boolean });
+
+  /** 关闭弹窗 */
+  const handleCancel = () => {
+    visible.value = false;
+  };
+
+  //计算是否禁用
+  const isPopoverDisabled = computed(() => (item) => {
+    let checked = item.childInfo.every((i) => i.otherSelected == 1);
+    return checked;
+  });
+
+  //计算是否显示全
+  const isShowAll = computed(() => (item) => {
+    let checked = item.childInfo.every((i) => i.mySelected == 1);
+    return checked;
+  });
+  //计算大区是否全选
+  const isIndeterminateShow = computed(() => (dq) => {
+    let len = dq.children.length;
+    let length = dq.children.filter((i) => i.mySelected == 1).length;
+
+    return length > 0 && length < len;
+  });
+
+  //计算省市是否全选
+  const isIndeterCityShow = computed(() => (item, type) => {
+    let len = item.childInfo.length;
+    let length = item.childInfo.filter((i) => i[type] == 1).length;
+
+    return length > 0 && length < len;
+  });
+
+  /** 弹窗打开事件 */
+  const title = ref('活动区域设置');
+  const handleOpen = (row) => {
+    visible.value = true;
+    nextTick(() => {
+      if (row && row.id) {
+        title.value = row.activityName
+          ? `${row.activityName}区域设置`
+          : `活动区域设置`;
+
+        row && getAreaInfo(row.id);
+      }
+    });
+  };
+
+  let formdata = reactive({
+    activityId: '',
+    selectendList: [{ provinceId: '', cityId: '' }]
+  });
+
+  //获取区域基础数据信息
+  let dqList = ref([
+    { name: '华东', code: 'hd' },
+    { name: '华北', code: 'hb' },
+    { name: '华中', code: 'hz' },
+    { name: '华南', code: 'hn' },
+    { name: '东北', code: 'db' },
+    { name: '西北', code: 'xb' },
+    { name: '西南', code: 'xn' },
+    { name: '港澳台', code: 'gat' },
+    { name: '海外', code: 'hw' }
+  ]);
+  const areaList = ref([]);
+  const loading = ref(false);
+  const getAreaInfo = (activityId) => {
+    formdata.activityId = activityId;
+    loading.value = true;
+    request
+      .get(`/activity/activityUpsellInfo/areaList/${activityId}`)
+      .then((res) => {
+        if (res.data.code == 200) {
+          areaList.value.length = 0;
+          dqList.value.forEach((item) => {
+            item.checked = false;
+            item.children = res.data.data[item.code];
+            areaList.value.push(item);
+          });
+
+          console.log(areaList.value, 'areaList.value');
+        }
+      })
+      .finally(() => (loading.value = false));
+  };
+
+  //区域checkbox改变事件
+  const handleDqChange = (value, dq) => {
+    if (value == 1) {
+      dq.children.forEach((item) => {
+        if (item.otherSelected != 1) {
+          item.mySelected = 1;
+          item.childInfo.forEach((i) => {
+            if (i.otherSelected != 1) {
+              i.mySelected = 1;
+            }
+          });
+        }
+      });
+    } else if (value == 0) {
+      dq.children.forEach((item) => {
+        if (item.otherSelected != 1) {
+          item.mySelected = 0;
+          item.childInfo.forEach((i) => {
+            if (i.otherSelected != 1) {
+              i.mySelected = 1;
+            }
+          });
+        }
+      });
+    }
+  };
+
+  //父级checkbox改变事件
+  const handleParentChange = (value, item) => {
+    if (value == 1) {
+      item.childInfo.forEach((i) => {
+        i.mySelected = 1;
+      });
+    } else if (value == 0) {
+      item.childInfo.forEach((i) => {
+        i.mySelected = 0;
+      });
+    }
+  };
+  //子级checkbox改变事件
+  const handleChildChange = (value, item, child) => {
+    let checked = item.childInfo.some((i) => i.mySelected == 1);
+    item.mySelected = checked ? 1 : 0;
+  };
+
+  //格式化选中数据
+  const formatterSelected = () => {
+    let arr = [];
+    areaList.value.forEach((item) => {
+      item.children.forEach((i) => {
+        i.childInfo.forEach((j) => {
+          if (j.mySelected == 1 && j.otherSelected != 1) {
+            arr.push({
+              provinceId: i.id,
+              cityId: j.id
+            });
+          }
+        });
+      });
+    });
+    return arr;
+  };
+
+  /** 提交 */
+  const emit = defineEmits(['success']);
+  const handleSubmit = () => {
+    formdata.selectendList = formatterSelected();
+    console.log(formdata);
+    let data = JSON.parse(JSON.stringify(formdata));
+    request.post(`/activity/activityUpsellInfo/setAreaList`, data).then((res) => {
+      if (res.data.code == 200) {
+        visible.value = false;
+        ElMessage.success('设置成功');
+        emit('success');
+      }
+    });
+  };
+
+  defineExpose({
+    handleOpen
+  });
+</script>
+
+<style lang="scss">
+  .disabled-popover {
+    cursor: not-allowed;
+    .el-text {
+      color: #909399;
+    }
+    .el-icon {
+      color: #909399;
+      fill: #909399;
+    }
+  }
+</style>

+ 67 - 0
src/views/marketing/ipMrakup/ipActivity/components/page-search.vue

@@ -0,0 +1,67 @@
+<!-- 搜索表单 -->
+<template>
+  <ele-card :body-style="{ padding: '0', paddingTop: '12px' }">
+    <ProSearch
+      :items="formItems"
+      ref="searchRef"
+      @search="search"
+      :initKeys="initKeys"
+    ></ProSearch>
+  </ele-card>
+</template>
+
+<script setup>
+  import { reactive, ref, defineEmits } from 'vue';
+  import ProSearch from '@/components/CommonPage/ProSearch2.vue';
+
+  const emit = defineEmits(['search']);
+  const formItems = computed(() => {
+    return [
+      { type: 'input', label: '活动名称', prop: 'activityName' },
+      { type: 'input', label: '省份', prop: 'provinceName' },
+      { type: 'input', label: '地区', prop: 'cityName' },
+      {
+        type: 'dictSelect',
+        label: '活动状态',
+        prop: 'status',
+        props: {
+          code: 'activity_status'
+        }
+      },
+      {
+        type: 'daterange',
+        label: '申请时间',
+        prop: 'timeRange',
+        style: {
+          minWidth: '300px'
+        },
+        props: {
+          valueFormat: 'YYYY-MM-DD',
+          format: 'YYYY-MM-DD',
+          startPlaceholder: '开始日期',
+          endPlaceholder: '结束日期',
+          onChange: (value) => {
+            initKeys.startTime = value ? value[0] : '';
+            initKeys.endTime = value ? value[1] : '';
+            searchRef.value?.setData(initKeys);
+          }
+        }
+      }
+    ];
+  });
+
+  const initKeys = reactive({
+    activityName: '',
+    provinceName: '',
+    cityName: '',
+    status: '',
+    startTime: '',
+    endTime: ''
+  });
+
+  const searchRef = ref(null);
+  /** 搜索 */
+  const search = (data) => {
+    emit('search', { ...data });
+  };
+</script>

+ 224 - 0
src/views/marketing/ipMrakup/ipActivity/index.vue

@@ -0,0 +1,224 @@
+<template>
+  <ele-page flex-table :bodyStyle="{ padding: 0 }">
+    <page-search @search="reload" />
+
+    <common-table
+      ref="pageRef"
+      :pageConfig="pageConfig"
+      :columns="columns"
+      :bodyStyle="{ padding: 0 }"
+      :tools="false"
+    >
+      <template #toolbar>
+        <div style="display: flex; align-items: center">
+          <el-button
+            type="primary"
+            plain
+            :icon="PlusOutlined"
+            @click="handleUpdate()"
+          >
+            新建
+          </el-button>
+        </div>
+      </template>
+
+      <template #status="{ row }">
+        <el-tag :type="row.status == 1 ? 'success' : 'danger'">
+          {{ row.status == 1 ? '进行中' : '已关闭' }}
+        </el-tag>
+      </template>
+
+      <template #limitFirst="{ row }">
+        <dict-data
+          code="limit_first"
+          type="text"
+          :model-value="row.limitFirst"
+        />
+      </template>
+
+      <template #startTime="{ row }">
+        {{ row.startTime + ' 至 ' + row.endTime }}
+      </template>
+
+      <template #action="{ row }">
+        <div>
+          <el-button
+            type="primary"
+            link
+            @click="handleUpdate(row)"
+            v-permission="'ipMarkup:ipActivity:edit'"
+          >
+            [编辑]
+          </el-button>
+
+          <el-button
+            type="success"
+            link
+            @click="handleViewData(row)"
+            v-permission="'ipMarkup:ipActivity:viewData'"
+          >
+            [查看数据]
+          </el-button>
+          <el-button
+            :type="row.status == 1 ? 'danger' : 'warning'"
+            link
+            @click="handleChangeStatus(row)"
+            v-permission="'ipMarkup:ipActivity:changeStatus'"
+          >
+            [{{ row.status == 1 ? '关闭活动' : '开启活动' }}]
+          </el-button>
+          <el-button
+            type="primary"
+            link
+            color="#642abc"
+            plain
+            @click="handleAreaSetting(row)"
+            v-permission="'ipMarkup:ipActivity:areaSetting'"
+          >
+            [活动区域设置]
+          </el-button>
+        </div>
+      </template>
+    </common-table>
+
+    <!-- 新增/编辑弹窗 -->
+    <activity-edit ref="activityEditRef" @success="reload" />
+    <area-setting ref="areaSettingRef" @success="reload" />
+  </ele-page>
+</template>
+
+<script setup>
+  import { ref, reactive } from 'vue';
+  import { ElMessageBox } from 'element-plus/es';
+  import { EleMessage } from 'ele-admin-plus/es';
+  import { PlusOutlined } from '@/components/icons';
+  import CommonTable from '@/components/CommonPage/CommonTable.vue';
+  import request from '@/utils/request';
+  import PageSearch from './components/page-search.vue';
+  import ActivityEdit from './components/activity-edit.vue';
+  import AreaSetting from './components/area-setting.vue';
+
+  defineOptions({ name: 'ipActivityTable' });
+
+  /** 表格列配置 */
+  const columns = ref([
+    {
+      label: '活动名称',
+      prop: 'activityName',
+      align: 'center',
+      minWidth: 120,
+    },
+    {
+      label: '活动省份',
+      prop: 'province',
+      align: 'center',
+      minWidth: 120,
+      formatter: (row) => {
+        return row.province || '--';
+      }
+    },
+    {
+      label: '活动地区',
+      prop: 'cityName',
+      align: 'center',
+      minWidth: 200,
+      formatter: (row) => {
+        return row.city || '--';
+      }
+    },
+    {
+      label: '活动时间',
+      prop: 'startTime',
+      align: 'center',
+      slot: 'startTime',
+      width: 310
+    },
+    {
+      label: '加价助力人数',
+      prop: 'inviteNum',
+      align: 'center',
+      width: 120
+    },
+    {
+      label: '是否限制首单',
+      prop: 'limitFirst',
+      align: 'center',
+      slot: 'limitFirst',
+      width: 120
+    },
+    {
+      label: '状态',
+      prop: 'status',
+      align: 'center',
+      width: 100,
+      slot: 'status'
+    },
+    {
+      columnKey: 'action',
+      label: '操作',
+      width: 210,
+      align: 'center',
+      slot: 'action'
+    }
+  ]);
+
+  /** 页面组件实例 */
+  const pageRef = ref(null);
+  const activityEditRef = ref(null);
+
+  const pageConfig = reactive({
+    pageUrl: '/activity/activityUpsellInfo/pagelist',
+    fileName: 'IP加价营销活动',
+    cacheKey: 'ipActivityTable'
+  });
+
+  // 刷新表格
+  function reload(where) {
+    pageRef.value?.reload(where);
+  }
+
+  // 活动区域设置弹窗
+  const areaSettingRef = ref(null);
+  function handleAreaSetting(row) {
+    areaSettingRef.value?.handleOpen(row);
+  }
+
+  // 编辑/新建弹窗
+  function handleUpdate(row) {
+    if (row?.id) {
+      // 编辑模式,获取弹窗详情
+      request
+        .get(`/activity/activityUpsellInfo/getInfo/${row.id}`)
+        .then((res) => {
+          if (res.data.code === 200) {
+            const data = res.data.data;
+            activityEditRef.value.handleOpen(data);
+          } else {
+            EleMessage.error(res.data.msg || '获取活动详情失败');
+          }
+        });
+    } else {
+      // 新建模式
+      activityEditRef.value.handleOpen();
+    }
+  }
+
+  // 改变状态
+  function handleChangeStatus(row) {
+    let message = '';
+    if (row.status == 1) {
+      message = '确认关闭该活动吗?';
+    } else {
+      message = '确认开启该活动吗?';
+    }
+    pageRef.value?.messageBoxConfirm({
+      message,
+      fetch: () => {
+        return request.post('/activity/activityUpsellInfo/changeStatus', {
+          activityId: row.id,
+          status: row.status == 1 ? 0 : 1
+        });
+      }
+    });
+  }
+</script>

+ 120 - 0
src/views/recycle/workbench/book-search.vue

@@ -0,0 +1,120 @@
+<!-- 搜索表单 -->
+<template>
+  <ele-card :body-style="{ paddingBottom: '8px' }">
+    <ProSearch
+      :items="formItems"
+      ref="searchRef"
+      @search="search"
+      :initKeys="initKeys"
+    ></ProSearch>
+  </ele-card>
+</template>
+
+<script setup>
+  import { reactive, ref, defineEmits } from 'vue';
+  import ProSearch from '@/components/CommonPage/ProSearch2.vue';
+
+  let { proxy } = getCurrentInstance();
+  const emit = defineEmits(['search']);
+
+  const formItems = reactive([
+    { type: 'input', label: '书名', prop: 'bookName' },
+    { type: 'input', label: 'ISBN', prop: 'isbn' },
+    { type: 'input', label: '作者', prop: 'author' },
+    { type: 'input', label: '出版社', prop: 'publish' },
+    {
+      type: 'daterange',
+      label: '出版时间',
+      prop: 'pubDate',
+      keys: ['pubDateStart', 'pubDateEnd'],
+      props: {
+        format: 'YYYY-MM-DD',
+        valueFormat: 'YYYY-MM-DD',
+        onChange: (val) => {
+          searchRef.value?.setData({
+            pubDateStart: val && val.length > 0 ? val[0] : '',
+            pubDateEnd: val && val.length > 0 ? val[1] : ''
+          });
+        }
+      }
+    },
+    {
+      type: 'inputNumberRange',
+      label: '定价',
+      prop: 'price',
+      keys: ['minPrice', 'maxPrice'],
+      props: {
+        onChange: (val) => {
+          searchRef.value?.setData({ minPrice: val.min, maxPrice: val.max });
+        }
+      }
+    },
+    {
+      type: 'dictSelect',
+      label: '图书类型',
+      prop: 'bookTag',
+      props: {
+        code: 'book_tag'
+      }
+    },
+    {
+      type: 'daterange',
+      label: '回收时间',
+      prop: 'recycleDate',
+      keys: ['rcNumStartTime', 'rcNumEndTime'],
+      props: {
+        format: 'YYYY-MM-DD',
+        valueFormat: 'YYYY-MM-DD',
+        onChange: (val) => {
+          searchRef.value?.setData({
+            rcNumStartTime: val && val.length > 0 ? val[0] : '',
+            rcNumEndTime: val && val.length > 0 ? val[1] : ''
+          });
+        }
+      }
+    },
+    {
+      type: 'inputNumberRange',
+      label: '回收折扣',
+      prop: 'discount',
+      keys: ['minDiscount', 'maxDiscount'],
+      props: {
+        minAttrs: { min: 0 },
+        maxAttrs: { max: 1 },
+        onChange: (val) => {
+          searchRef.value?.setData({
+            minDiscount: val.min,
+            maxDiscount: val.max
+          });
+        }
+      }
+    }
+  ]);
+
+  const initKeys = reactive({
+    bookName: '',
+    isbn: '',
+    author: '',
+    publish: '',
+    pubDateStart: '',
+    pubDateEnd: '',
+    minPrice: void 0,
+    maxPrice: void 0,
+    minDiscount: void 0,
+    maxDiscount: void 0,
+    globalInDiscount: void 0,
+    globalNotInDiscount: void 0,
+    rcNumStartTime: '',
+    rcNumEndTime: ''
+  });
+
+  const searchRef = ref(null);
+  /** 搜索 */
+  const search = (data) => {
+    let params = JSON.parse(JSON.stringify(data));
+    delete params.price;
+    delete params.discount;
+    delete params.pubDate;
+    emit('search', params);
+  };
+</script>

+ 6 - 5
src/views/recycle/workbench/index.vue

@@ -11,11 +11,12 @@
     >
       <template #toolbar>
         <el-radio-group @change="handleStatusChange" v-model="searchType">
+          <el-radio-button label="全部" value="0" />
           <el-radio-button label="已加入回收书单(正在回收)" value="1" />
           <el-radio-button label="已加入回收书单(暂停回收)" value="2" />
           <el-radio-button label="未加入回收书单" value="3" />
+          <el-radio-button label="未加入回收书单(手动暂停)" value="5" />
           <el-radio-button label="黑名单" value="4" />
-          <el-radio-button label="无数据信息" value="5" />
         </el-radio-group>
 
         <span class="ml-8"></span>
@@ -33,7 +34,7 @@
           plain
           v-permission="'recycle:workbench:batchAddBooklist'"
           @click="handleOptBooklist('add')"
-          v-if="['3', '4'].includes(searchType)"
+          v-if="['3', '4', '5'].includes(searchType)"
         >
           加入回收书单
         </el-button>
@@ -220,7 +221,7 @@
   import { ref, reactive } from 'vue';
   import CommonTable from '@/components/CommonPage/CommonTable.vue';
   import booksEdit from '@/views/data/books/components/books-edit.vue';
-  import bookSearch from '@/views/recycle/components/book-search.vue';
+  import bookSearch from '@/views/recycle/workbench/book-search.vue';
   import bookInfo from '@/views/recycle/components/book-info.vue';
   import bookStock from '@/views/recycle/components/book-stock.vue';
   import setParams from '@/views/recycle/components/set-params.vue';
@@ -232,7 +233,7 @@
 
   defineOptions({ name: 'scanLoglist' });
 
-  const searchType = ref('1');
+  const searchType = ref('0');
   function handleStatusChange(value) {
     pageRef.value.reload({ searchType: value });
   }
@@ -309,7 +310,7 @@
   const pageRef = ref(null);
 
   const pageConfig = reactive({
-    pageUrl: '/user/userScanLog/getBookScanLogList',
+    pageUrl: '/user/userScanLog/getScanWorkLogList',
     fileName: '扫码工作台',
     cacheKey: 'workbenchTable',
     params: {

+ 1 - 1
src/views/recycleOrder/needReturned/index.vue

@@ -104,7 +104,7 @@
             <el-button
               type="danger"
               link
-              v-if="row.status == '0'"
+              v-if="row.status < 3"
               v-permission="'recycleOrder:needReturned:cancel'"
               @click="cancelOrder(row)"
             >