huangxw 10 сар өмнө
parent
commit
de83eeba09

+ 3 - 0
.env.development

@@ -28,6 +28,9 @@ VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3C
 # 客户端id
 VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
 
+# appid
+VITE_APP_APPID = '1890328853823459329'
+
 # websocket 开关 默认使用sse推送
 VITE_APP_WEBSOCKET = false
 

+ 22 - 0
src/api/cdt/menus/index.ts

@@ -61,3 +61,25 @@ export const testPackageSale = (id?: string): any => {
         method: 'post'
     });
 };
+/**
+ * 下架套餐
+ * @param id
+ * @returns {*}
+ */
+export const testPackageUnSale = (id?: string): any => {
+    return request({
+        url: `/dgtmedicine/testPackage/offSale/${id}`,
+        method: 'post'
+    });
+};
+/**
+ * 复制套餐
+ * @param id
+ * @returns {*}
+ */
+export const copyTestPackage = (id?: string): any => {
+    return request({
+        url: `/dgtmedicine/testPackage/copy/${id}`,
+        method: 'post'
+    });
+};

+ 121 - 119
src/utils/request.ts

@@ -17,116 +17,118 @@ let downloadLoadingInstance: LoadingInstance;
 // 是否显示重新登录
 export const isRelogin = { show: false };
 export const globalHeaders = () => {
-  return {
-    Authorization: 'Bearer ' + getToken(),
-    clientid: import.meta.env.VITE_APP_CLIENT_ID
-  };
+    return {
+        Authorization: 'Bearer ' + getToken(),
+        clientid: import.meta.env.VITE_APP_CLIENT_ID,
+        Appid: import.meta.env.VITE_APP_APPID
+    };
 };
 
 axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8';
 axios.defaults.headers['clientid'] = import.meta.env.VITE_APP_CLIENT_ID;
+axios.defaults.headers['Appid'] = import.meta.env.VITE_APP_APPID;
 // 创建 axios 实例
 const service = axios.create({
-  baseURL: import.meta.env.VITE_APP_BASE_API,
-  timeout: 50000
+    baseURL: import.meta.env.VITE_APP_BASE_API,
+    timeout: 50000
 });
 
 // 请求拦截器
 service.interceptors.request.use(
-  (config: InternalAxiosRequestConfig) => {
-    // 对应国际化资源文件后缀
-    config.headers['Content-Language'] = getLanguage();
+    (config: InternalAxiosRequestConfig) => {
+        // 对应国际化资源文件后缀
+        config.headers['Content-Language'] = getLanguage();
 
-    const isToken = config.headers?.isToken === false;
-    // 是否需要防止数据重复提交
-    const isRepeatSubmit = config.headers?.repeatSubmit === false;
-    // 是否需要加密
-    const isEncrypt = config.headers?.isEncrypt === 'true';
+        const isToken = config.headers?.isToken === false;
+        // 是否需要防止数据重复提交
+        const isRepeatSubmit = config.headers?.repeatSubmit === false;
+        // 是否需要加密
+        const isEncrypt = config.headers?.isEncrypt === 'true';
 
-    if (getToken() && !isToken) {
-      config.headers['Authorization'] = 'Bearer ' + getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
-    }
-    // get请求映射params参数
-    if (config.method === 'get' && config.params) {
-      let url = config.url + '?' + tansParams(config.params);
-      url = url.slice(0, -1);
-      config.params = {};
-      config.url = url;
-    }
+        if (getToken() && !isToken) {
+            config.headers['Authorization'] = 'Bearer ' + getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改
+        }
+        // get请求映射params参数
+        if (config.method === 'get' && config.params) {
+            let url = config.url + '?' + tansParams(config.params);
+            url = url.slice(0, -1);
+            config.params = {};
+            config.url = url;
+        }
 
-    if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
-      const requestObj = {
-        url: config.url,
-        data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
-        time: new Date().getTime()
-      };
-      const sessionObj = cache.session.getJSON('sessionObj');
-      if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
-        cache.session.setJSON('sessionObj', requestObj);
-      } else {
-        const s_url = sessionObj.url; // 请求地址
-        const s_data = sessionObj.data; // 请求数据
-        const s_time = sessionObj.time; // 请求时间
-        const interval = 500; // 间隔时间(ms),小于此时间视为重复提交
-        if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
-          const message = '数据正在处理,请勿重复提交';
-          console.warn(`[${s_url}]: ` + message);
-          return Promise.reject(new Error(message));
-        } else {
-          cache.session.setJSON('sessionObj', requestObj);
+        if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
+            const requestObj = {
+                url: config.url,
+                data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
+                time: new Date().getTime()
+            };
+            const sessionObj = cache.session.getJSON('sessionObj');
+            if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
+                cache.session.setJSON('sessionObj', requestObj);
+            } else {
+                const s_url = sessionObj.url; // 请求地址
+                const s_data = sessionObj.data; // 请求数据
+                const s_time = sessionObj.time; // 请求时间
+                const interval = 500; // 间隔时间(ms),小于此时间视为重复提交
+                if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
+                    const message = '数据正在处理,请勿重复提交';
+                    console.warn(`[${s_url}]: ` + message);
+                    return Promise.reject(new Error(message));
+                } else {
+                    cache.session.setJSON('sessionObj', requestObj);
+                }
+            }
         }
-      }
-    }
-    if (import.meta.env.VITE_APP_ENCRYPT === 'true') {
-      // 当开启参数加密
-      if (isEncrypt && (config.method === 'post' || config.method === 'put')) {
-        // 生成一个 AES 密钥
-        const aesKey = generateAesKey();
-        config.headers[encryptHeader] = encrypt(encryptBase64(aesKey));
-        config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey);
-      }
-    }
-    // FormData数据去请求头Content-Type
-    if (config.data instanceof FormData) {
-      delete config.headers['Content-Type'];
+        if (import.meta.env.VITE_APP_ENCRYPT === 'true') {
+            // 当开启参数加密
+            if (isEncrypt && (config.method === 'post' || config.method === 'put')) {
+                // 生成一个 AES 密钥
+                const aesKey = generateAesKey();
+                config.headers[encryptHeader] = encrypt(encryptBase64(aesKey));
+                config.data = typeof config.data === 'object' ? encryptWithAes(JSON.stringify(config.data), aesKey) : encryptWithAes(config.data, aesKey);
+            }
+        }
+        // FormData数据去请求头Content-Type
+        if (config.data instanceof FormData) {
+            delete config.headers['Content-Type'];
+        }
+        return config;
+    },
+    (error: any) => {
+        return Promise.reject(error);
     }
-    return config;
-  },
-  (error: any) => {
-    return Promise.reject(error);
-  }
 );
 
 // 响应拦截器
 service.interceptors.response.use(
-  (res: AxiosResponse) => {
-    if (import.meta.env.VITE_APP_ENCRYPT === 'true') {
-      // 加密后的 AES 秘钥
-      const keyStr = res.headers[encryptHeader];
-      // 加密
-      if (keyStr != null && keyStr != '') {
-        const data = res.data;
-        // 请求体 AES 解密
-        const base64Str = decrypt(keyStr);
-        // base64 解码 得到请求头的 AES 秘钥
-        const aesKey = decryptBase64(base64Str.toString());
-        // aesKey 解码 data
-        const decryptData = decryptWithAes(data, aesKey);
-        // 将结果 (得到的是 JSON 字符串) 转为 JSON
-        res.data = JSON.parse(decryptData);
-      }
-    }
-    // 未设置状态码则默认成功状态
-    const code = res.data.code || HttpStatus.SUCCESS;
-    // 获取错误信息
-    const msg = errorCode[code] || res.data.msg || errorCode['default'];
-    // 二进制数据则直接返回
-    if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
-      return res.data;
-    }
-    if (code === 401) {
-      // prettier-ignore
-      if (!isRelogin.show) {
+    (res: AxiosResponse) => {
+        if (import.meta.env.VITE_APP_ENCRYPT === 'true') {
+            // 加密后的 AES 秘钥
+            const keyStr = res.headers[encryptHeader];
+            // 加密
+            if (keyStr != null && keyStr != '') {
+                const data = res.data;
+                // 请求体 AES 解密
+                const base64Str = decrypt(keyStr);
+                // base64 解码 得到请求头的 AES 秘钥
+                const aesKey = decryptBase64(base64Str.toString());
+                // aesKey 解码 data
+                const decryptData = decryptWithAes(data, aesKey);
+                // 将结果 (得到的是 JSON 字符串) 转为 JSON
+                res.data = JSON.parse(decryptData);
+            }
+        }
+        // 未设置状态码则默认成功状态
+        const code = res.data.code || HttpStatus.SUCCESS;
+        // 获取错误信息
+        const msg = errorCode[code] || res.data.msg || errorCode['default'];
+        // 二进制数据则直接返回
+        if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
+            return res.data;
+        }
+        if (code === 401) {
+            // prettier-ignore
+            if (!isRelogin.show) {
         isRelogin.show = true;
         ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
           confirmButtonText: '重新登录',
@@ -146,38 +148,38 @@ service.interceptors.response.use(
           isRelogin.show = false;
         });
       }
-      return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
-    } else if (code === HttpStatus.SERVER_ERROR) {
-      ElMessage({ message: msg, type: 'error' });
-      return Promise.reject(new Error(msg));
-    } else if (code === HttpStatus.WARN) {
-      ElMessage({ message: msg, type: 'warning' });
-      return Promise.reject(new Error(msg));
-    } else if (code !== HttpStatus.SUCCESS) {
-      ElNotification.error({ title: msg });
-      return Promise.reject('error');
-    } else {
-      return Promise.resolve(res.data);
-    }
-  },
-  (error: any) => {
-    let { message } = error;
-    if (message == 'Network Error') {
-      message = '后端接口连接异常';
-    } else if (message.includes('timeout')) {
-      message = '系统接口请求超时';
-    } else if (message.includes('Request failed with status code')) {
-      message = '系统接口' + message.substr(message.length - 3) + '异常';
+            return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
+        } else if (code === HttpStatus.SERVER_ERROR) {
+            ElMessage({ message: msg, type: 'error' });
+            return Promise.reject(new Error(msg));
+        } else if (code === HttpStatus.WARN) {
+            ElMessage({ message: msg, type: 'warning' });
+            return Promise.reject(new Error(msg));
+        } else if (code !== HttpStatus.SUCCESS) {
+            ElNotification.error({ title: msg });
+            return Promise.reject('error');
+        } else {
+            return Promise.resolve(res.data);
+        }
+    },
+    (error: any) => {
+        let { message } = error;
+        if (message == 'Network Error') {
+            message = '后端接口连接异常';
+        } else if (message.includes('timeout')) {
+            message = '系统接口请求超时';
+        } else if (message.includes('Request failed with status code')) {
+            message = '系统接口' + message.substr(message.length - 3) + '异常';
+        }
+        ElMessage({ message: message, type: 'error', duration: 5 * 1000 });
+        return Promise.reject(error);
     }
-    ElMessage({ message: message, type: 'error', duration: 5 * 1000 });
-    return Promise.reject(error);
-  }
 );
 // 通用下载方法
 export function download(url: string, params: any, fileName: string) {
-  downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
-  // prettier-ignore
-  return service.post(url, params, {
+    downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' });
+    // prettier-ignore
+    return service.post(url, params, {
       transformRequest: [
         (params: any) => {
           return tansParams(params);

+ 63 - 22
src/views/cdt/menus/form/index.vue

@@ -14,12 +14,12 @@
                 <el-form ref="formRef" label-width="auto" label-position="top" :model="form" :rules="rules">
                     <div class="pd-16 border-bottom">
                         <el-form-item prop="items">
-                            <div class="flex1">
+                            <div class="flex1 ov-hd">
                                 <template v-if="!form.items.length">
                                     <add-btn @click="showSelectItems = true" content="选择检测项目"></add-btn>
                                 </template>
                                 <template v-else>
-                                    <div class="d-flex">
+                                    <div class="d-flex mb-10">
                                         <div class="flex1 ov-hd f-s-16 c-333 f-w-5">已选择{{ form.items.length }}项检测项目,合计{{ totalCountPrice }}元</div>
                                         <div>
                                             <el-button @click="addItems" type="primary" text>
@@ -56,8 +56,8 @@
                                 </el-form-item>
                             </el-col>
                             <el-col :span="8">
-                                <el-form-item label="套餐类型" prop="publicFlag">
-                                    <el-select v-model="form.publicFlag" clearable placeholder="请选择套餐类型">
+                                <el-form-item label="套餐类型" prop="type">
+                                    <el-select v-model="form.type" clearable placeholder="请选择套餐类型">
                                         <el-option v-for="item in dm_package_type" :key="item.value" :label="item.label" :value="item.value"></el-option>
                                     </el-select>
                                 </el-form-item>
@@ -80,8 +80,8 @@
                             </template>
                             <template v-if="form.permitType === '2'">
                                 <el-col :span="8">
-                                    <el-form-item label="适用企业" prop="permitCpy">
-                                        <SearchSelect v-model="form.permitCpy" :params="{ reviewStatus: '1' }" @changeItem="changeItemCpy"></SearchSelect>
+                                    <el-form-item label="适用企业" prop="permitCpys">
+                                        <SearchSelect v-model="form.permitCpys" :params="{ reviewStatus: '1' }" @changeItem="changeItemCpy"></SearchSelect>
                                     </el-form-item>
                                 </el-col>
                             </template>
@@ -112,6 +112,11 @@
                                     <el-input type="textarea" v-model="form.purchaseNotes" placeholder="请输入购买须知" :rows="4" show-word-limit maxlength="100"></el-input>
                                 </el-form-item>
                             </el-col>
+                            <el-col :span="8">
+                                <el-form-item label="失效日期" prop="validUntil">
+                                    <el-date-picker v-model="form.validUntil" value-format="YYYY-MM-DD" type="date" clearable placeholder="请选择失效日期"></el-date-picker>
+                                </el-form-item>
+                            </el-col>
                             <el-col :span="8">
                                 <el-form-item label="封面图" prop="coverImg">
                                     <imageUpload v-model="form.coverImg" :limit="1" isString :isShowTip="false"></imageUpload>
@@ -124,16 +129,16 @@
                             </el-col>
                         </el-row>
                     </div>
-                    <div v-if="form.permit" class="pd-16">
+                    <div v-if="form.permit?.length" class="pd-16">
                         <div class="info-title mb-10">套餐价格确认</div>
                         <vxe-table ref="tableRightRef" border :data="form.priceDetail" :column-config="{ resizable: true }">
                             <vxe-column type="seq" width="60" title="序号" align="center" />
                             <vxe-column v-if="form.permitType === '2'" title="企业名称" align="center" min-width="100" :formatter="colNoData">
-                                <template #default>{{ form.permitCpyName }}</template>
+                                <template #default="{ row }">{{ row?.cpyName }}</template>
                             </vxe-column>
                             <vxe-column title="适用类型" align="center" field="name" min-width="100" :formatter="colNoData" />
                             <vxe-column title="折扣标准" align="center" min-width="100">
-                                <template #default="{ row }">{{ NP.times(row?.discount, 10) }}折</template>
+                                <template #default="{ row }">{{ NP.times(row?.memberDiscount, 10) }}折</template>
                             </vxe-column>
                             <vxe-column title="折扣后售价" align="center" field="name" min-width="100">
                                 <template #default="{ row }">{{ row?.discountPrice }}元</template>
@@ -175,16 +180,17 @@ const router = useRouter();
 const showSelectItems = ref(false);
 const form = ref<any>({
    items: [],
-   priceDetail: []
+   priceDetail: [],
+   permitCpys: []
 });
-const rules = reactive({
+const rules = reactive<any>({
     items: [
         { required: true,  type: 'array', message: '请选择检测项目', trigger: 'change' },
     ],
     name: [
         { required: true, message: '请输入套餐名称', trigger: 'blur' }
     ],
-    publicFlag: [
+    type: [
         { required: true, message: '请选择套餐类型', trigger: 'change' }
     ],
     permitType: [
@@ -193,8 +199,8 @@ const rules = reactive({
     permit: [
         { required: true, message: '请选择适用类型', trigger: 'change' }
     ],
-    permitCpy: [
-        { required: true, message: '请选择适用企业', trigger: 'change' }
+    permitCpys: [
+        {type: 'array', required: true, message: '请选择适用企业', trigger: 'change' }
     ],
     period: [
         { required: true, message: '请输入检测周期', trigger: 'blur' }
@@ -211,6 +217,9 @@ const rules = reactive({
     purchaseNotes: [
         { required: true, message: '请输入购买须知', trigger: 'blur' }
     ],
+    validUntil: [
+        { required: true, message: '请选择失效日期', trigger: 'change' }
+    ],
     coverImg: [
         { required: true, message: '请上传封面图', trigger: 'blur' }
     ],
@@ -229,8 +238,18 @@ const submitGround = debounce(async () => {
 const submitSever = async (type) => {
    proxy.$modal.loading('提交中...');
    const params = {
-         ...form.value
+        ...form.value,
+        testItemIds: form.value.items.map((item: any) => item.id),
+        priceDetail: form.value.priceDetail.map((item: any) => {
+            return {
+                memberLevel: item.memberLevel,
+                memberDiscount: item.memberDiscount,
+                originalPrice: item.originalPrice,
+                price: item.price
+            }
+        })
    }
+   delete params.items;
    const res = await addTestPackage(params).finally(() => {
        proxy.$modal.closeLoading();
    });
@@ -249,14 +268,15 @@ const totalCountPrice = computed(() => {
 });
 const changeItems = (val: any) => {
     form.value.items = val;
+    const standards = val.map((item: any) => item.standardForPackage).join(',').split(',');
+    // 去重
+    form.value.standard = Array.from(new Set(standards)).join(',');
     changePermitType();
 };
-const changeItemCpy = (val: any) => {
-    console.log(val);
-    const { vipLevel, cpyName } = val;
-    form.value.permit = [vipLevel || '0']
-    form.value.permitCpyName = cpyName;
-    changePermit([vipLevel || '0']);
+const changeItemCpy = (val: any[]) => {
+   const permits = val.map((item: any) => item.vipLevel || '0');
+    form.value.permit = [...permits];
+    changePermitCpys(val);
 };
 // 继续添加方法
 const addItems = () => {
@@ -286,15 +306,36 @@ const changePermit = (val: string[]) => {
         return {
             ...item,
             memberLevel: item.level,
+            memberDiscount: item.discount,
             originalPrice: totalCountPrice.value,
             discountPrice: NP.times(item.discount, totalCountPrice.value),
             price: NP.times(item.discount, totalCountPrice.value) || undefined
         };
     });
 };
+const changePermitCpys = (vals: any[]) => {
+    console.log(vals);
+    form.value.priceDetail = vals.map(item => {
+        const discountItem = getDiscountItem(item.vipLevel || '0');
+        console.log(discountItem);
+        return {
+            cpyName: item.cpyName,
+            name: discountItem?.name,
+            memberLevel: discountItem?.level,
+            memberDiscount: discountItem?.discount,
+            originalPrice: totalCountPrice.value,
+            discountPrice: NP.times(discountItem?.discount, totalCountPrice.value),
+            price: NP.times(discountItem?.discount, totalCountPrice.value) || undefined
+        };
+    });
+};
+// 获取discountsItem
+const getDiscountItem = (val: string) => {
+    return discounts.value.find(item => +item.level === +val);
+};
 const changePermitType = () => {
     form.value.permit = [];
-    form.value.permitCpy = '';
+    form.value.permitCpys = [];
     form.value.priceDetail = [];
 };
 onMounted(() => {

+ 120 - 12
src/views/cdt/menus/index.vue

@@ -14,16 +14,14 @@
                             </el-form-item>
                             <el-form-item label="套餐状态" prop="status">
                                 <el-select style="width: 160px" v-model="queryParams.status" clearable placeholder="请选择套餐状态" @change="handleQuery">
-                                    <el-option label="全部" value=""></el-option>
-                                    <el-option label="启用" value="1"></el-option>
-                                    <el-option label="停用" value="0"></el-option>
+                                    <el-option label="未上架" value="0"></el-option>
+                                    <el-option label="在售" value="1"></el-option>
+                                    <el-option label="已下架" value="2"></el-option>
                                 </el-select>
                             </el-form-item>
-                            <el-form-item label="适用对象" prop="applyType">
-                                <el-select style="width: 160px" v-model="queryParams.applyType" clearable placeholder="请选择适用对象" @change="handleQuery">
-                                    <el-option label="全部" value=""></el-option>
-                                    <el-option label="个人" value="1"></el-option>
-                                    <el-option label="企业" value="2"></el-option>
+                            <el-form-item label="制定规则" prop="permitType">
+                                <el-select style="width: 160px" v-model="queryParams.permitType" clearable placeholder="请选择制定规则" @change="handleQuery">
+                                    <el-option v-for="item in dm_permit_type" :key="item.value" :label="item.label" :value="item.value"></el-option>
                                 </el-select>
                             </el-form-item>
                             <el-form-item label="创建人" prop="createByName">
@@ -38,11 +36,68 @@
                 </div>
             </div>
             <div class="flex1 ov-hd pd-16">
-                <searchTabs v-model="queryParams.type" :list="tabs" key-label="name" key-value="type" key-count="num"></searchTabs>
+                <searchTabs v-model="queryParams.type" @change="handleQuery" :list="tabs" key-label="name" key-value="type" key-count="num"></searchTabs>
                 <div class="pd-8"></div>
                 <vxe-table :loading="loading" border :data="list" min-height="0" max-height="100%">
                     <!-- 序号 -->
-                    <vxe-column type="seq" width="60" title="序号" align="center" />
+                    <vxe-column type="seq" fixed="left" width="60" title="序号" align="center" />
+                    <vxe-column title="套餐名称" fixed="left" align="center" field="name" min-width="100" :formatter="colNoData" />
+                    <vxe-column title="适用对象" field="applyType" min-width="100">
+                        <template #default="{ row }">
+                            <view class="d-flex flex-cln">
+                                <template v-for="(item, index) in row?.priceDetail" :key="index">
+                                    <view>
+                                        {{ item?.memberLevelName }}-{{ NP.times(item?.memberDiscount, 10) }}折
+                                        <span class="c-333 f-w-5">({{ item?.price }})</span>
+                                    </view>
+                                </template>
+                            </view>
+                        </template>
+                    </vxe-column>
+                    <vxe-column title="检测项目" min-width="140">
+                        <template #default="{ row }">
+                            <view v-if="row?.items">
+                                {{ row?.items }}
+                                <el-button type="primary" text>点击查看详情{{ '>' }}</el-button>
+                            </view>
+                            <view v-else>-</view>
+                        </template>
+                    </vxe-column>
+                    <vxe-column title="检测周期" width="100">
+                        <template #default="{ row }">{{ row?.period }}天</template>
+                    </vxe-column>
+                    <vxe-column title="上架数量" field="totalCount" width="80" :formatter="colNoData"></vxe-column>
+                    <vxe-column title="销量" field="orderedCount" width="80" :formatter="colNoData"></vxe-column>
+                    <vxe-column title="套餐状态" align="center" width="90" fixed="right">
+                        <template #default="{ row }">
+                            <span v-if="+row?.status === 0" class="c-danger">未上架</span>
+                            <span v-else-if="+row?.status === 1" class="c-primary">在售</span>
+                            <span v-else-if="+row?.status === 2" class="c-999">已下架</span>
+                        </template>
+                    </vxe-column>
+                    <vxe-column title="操作" fixed="right" width="260">
+                        <template #default="{ row }">
+                            <template v-if="+row?.status === 0">
+                                <el-button @click="putaway(row)" text type="primary">上架</el-button>
+                                <span></span>
+                                <el-button text type="primary">编辑</el-button>
+                            </template>
+                            <template v-if="+row?.status === 1">
+                                <el-button @click="soldOut(row)" text type="danger">下架</el-button>
+                                <span></span>
+                                <el-button text type="primary">分享</el-button>
+                            </template>
+                            <template v-if="+row?.status === 2">
+                                <el-button @click="putaway(row)" text type="primary">上架</el-button>
+                                <span></span>
+                                <el-button text style="color: #999;" disabled>分享</el-button>
+                            </template>
+                            <span></span>
+                            <el-button @click="copyItem(row)" text type="primary">复制</el-button>
+                            <span></span>
+                            <el-button text type="primary">详情</el-button>
+                        </template>
+                    </vxe-column>
                 </vxe-table>
             </div>
             <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
@@ -50,13 +105,17 @@
     </div>
 </template>
 <script setup name="Menus" lang="ts">
-import { testPackageList, testPackageListCount } from '@/api/cdt/menus';
+import { copyTestPackage, testPackageList, testPackageListCount, testPackageSale, testPackageUnSale } from '@/api/cdt/menus';
 import { colNoData } from '@/utils/noData';
 import { searchTabs } from '@/views/models';
+import NP from 'number-precision';
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { dm_package_type, dm_permit_type, vip_level } = toRefs<any>(proxy?.useDict('dm_package_type', 'dm_permit_type', 'vip_level'));
 const router = useRouter();
 const queryParams = ref<any>({
     pageNum: 1,
-    pageSize: 10
+    pageSize: 10,
+    type: '1'
 });
 const queryFormRef = ref<any>();
 const loading = ref(false);
@@ -86,6 +145,55 @@ const getTabsCount = async () => {
     // this.tabsList = res.rows;
     tabs.value = res.data;
 };
+// 上架套餐
+const putaway = async (row: any) => {
+    console.log(row);
+    ElMessageBox({
+        title: '上架提示',
+        showCancelButton: true,
+        confirmButtonText: '确认上架',
+        cancelButtonText: '取消',
+        message: h('p', null, [h('div', null, `是否确认上架:${ row?.name }`), h('div', { style: 'color: #2A6D52;' }, '上架后,即可分享并在小程序上显示该套餐!')]),
+        callback: async (action: string) => {
+            if (action === 'confirm') {
+                proxy.$modal.loading('上架中...');
+                const res = await testPackageSale(row?.id).finally(() => proxy.$modal.closeLoading());
+                if (!res || res.code !== 200) return;
+                proxy.$modal.msgSuccess('上架成功!');
+                getList();
+            }
+        }
+    });
+};
+// 下架套餐
+const soldOut = async (row: any) => {
+    console.log(row);
+    ElMessageBox({
+        title: '下架提示',
+        showCancelButton: true,
+        confirmButtonText: '确认下架',
+        cancelButtonText: '取消',
+        message: h('p', null, [h('div', null, `是否确认下架:${ row?.name }`), h('div', { style: 'color: #F56C6C;' }, '下架后,该套餐将不再小程序上显示,已购买企业不受影响!')]),
+        callback: async (action: string) => {
+            if (action === 'confirm') {
+                proxy.$modal.loading('下架中...');
+                const res = await testPackageUnSale(row?.id).finally(() => proxy.$modal.closeLoading());
+                if (!res || res.code !== 200) return;
+                proxy.$modal.msgSuccess('下架成功!');
+                getList();
+            }
+        }
+    });
+};
+// 复制套餐
+const copyItem = async (row: any) => {
+    console.log(row);
+    proxy.$modal.loading('复制中...');
+    const res = await copyTestPackage(row?.id).finally(() => proxy.$modal.closeLoading());
+    if (!res || res.code !== 200) return;
+    proxy.$modal.msgSuccess('复制成功!');
+    getList();
+};
 onMounted(() => {
     getTabsCount();
     getList();

+ 3 - 3
src/views/models/SearchSelect.vue

@@ -1,5 +1,5 @@
 <template>
-    <el-select ref="selectDropRef" @change="changeSelect" v-model="value" filterable popper-class="custom-dropdown" remote reserve-keyword :remote-method="remoteMethod" remote-show-suffix clearable placeholder="请选择适用企业">
+    <el-select ref="selectDropRef" @change="changeSelect" multiple v-model="value" filterable popper-class="custom-dropdown" remote reserve-keyword :remote-method="remoteMethod" remote-show-suffix clearable placeholder="请选择适用企业">
         <div class="optionBox" infinite-scroll-delay="500" infinite-scroll-distance="20" v-infinite-scroll="load">
             <el-option v-for="item in options" :key="item.value" filterable :label="item.cpyName" :value="item.id"></el-option>
         </div>
@@ -54,8 +54,8 @@ const load = () => {
         getList(false)
     }
 }
-const changeSelect = (val: string) => {
-    const itemInfo = options.value.find(item => item.id === val)
+const changeSelect = (val: string[]) => {
+    const itemInfo = options.value.filter(item => val.includes(item.id))
     emit('update:modelValue', val)
     emit('change', val)
     emit('changeItem', itemInfo)

+ 2 - 2
vite.config.ts

@@ -26,8 +26,8 @@ export default defineConfig(({ mode, command }: ConfigEnv): UserConfig => {
             proxy: {
                 [env.VITE_APP_BASE_API]: {
                     // target: 'http://dm.yujin.shuziyunyao.com/api',
-                    target: 'http://dm.yujin.shuziyunyao.com/api',
-                    // target: 'http://192.168.1.68:8080',
+                    // target: 'http://dm.yujin.shuziyunyao.com/api',
+                    target: 'http://192.168.1.68:8080',
                     changeOrigin: true,
                     ws: true,
                     rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')