Bladeren bron

Merge branch 'master' into js

zqwang 1 jaar geleden
bovenliggende
commit
ee62e13c01
53 gewijzigde bestanden met toevoegingen van 3265 en 216 verwijderingen
  1. 6 0
      src/api/backConfig/index.ts
  2. 7 0
      src/api/common/index.ts
  3. 21 0
      src/api/iPayment/index.ts
  4. 26 0
      src/api/pageLayout/channelPage/index.ts
  5. 26 0
      src/api/pageLayout/homePage/index.ts
  6. 35 0
      src/api/pageLayout/viewpagerPage/index.ts
  7. 77 30
      src/components/Upload/myUpload.vue
  8. 13 3
      src/components/admin/dialog/index.vue
  9. 24 24
      src/layout/components/header/index.vue
  10. 1 1
      src/layout/components/header/profile.vue
  11. 18 3
      src/router/modules/charge.ts
  12. 1 1
      src/stores/modules/user/index.ts
  13. 9 0
      src/styles/var.scss
  14. 174 0
      src/views/appletManage/iPayment/form/create.vue
  15. 77 0
      src/views/appletManage/iPayment/form/note.vue
  16. 117 0
      src/views/appletManage/iPayment/index.vue
  17. 23 1
      src/views/appletManage/form/create.vue
  18. 0 0
      src/views/appletManage/miniProgramList/form/depotsTransfer.vue
  19. 32 11
      src/views/appletManage/index.vue
  20. 25 23
      src/views/ordersManage/tabs/rechargeList/index.vue
  21. 98 0
      src/views/pageLayout/channelPageManage/form/config.vue
  22. 72 0
      src/views/pageLayout/channelPageManage/form/create.vue
  23. 276 0
      src/views/pageLayout/channelPageManage/form/videoList.vue
  24. 86 0
      src/views/pageLayout/channelPageManage/index.vue
  25. 98 0
      src/views/pageLayout/homePageManage/form/config.vue
  26. 73 0
      src/views/pageLayout/homePageManage/form/create.vue
  27. 275 0
      src/views/pageLayout/homePageManage/form/videoList.vue
  28. 88 0
      src/views/pageLayout/homePageManage/index.vue
  29. 142 0
      src/views/pageLayout/viewpagerPageManage/form/create.vue
  30. 226 0
      src/views/pageLayout/viewpagerPageManage/form/videoList.vue
  31. 117 0
      src/views/pageLayout/viewpagerPageManage/index.vue
  32. 28 2
      src/views/payBack/juliangAccount/tabs/advertiserList/index.vue
  33. 11 6
      src/views/payBack/juliangAccount/tabs/logList/index.vue
  34. 1 1
      src/views/promotion/promotionList/form/backConfig.vue
  35. 30 4
      src/views/promotion/promotionList/index.vue
  36. 1 1
      src/views/settleManage/settlementCenter/tabs/rechargeRules/index.vue
  37. 1 2
      src/views/settleManage/settlementCenter/tabs/rechargeSettle/form/create.vue
  38. 1 1
      src/views/settleManage/settlementCenter/tabs/rechargeSettle/index.vue
  39. 64 7
      src/views/videoManage/detail.vue
  40. 6 1
      src/views/videoManage/form/create.vue
  41. 0 0
      src/views/videoManage/videoLibraryList/form/subscribeSet.vue
  42. 0 0
      src/views/videoManage/videoLibraryList/form/uploadVideo.vue
  43. 1 1
      src/views/videoManage/form/videoDL.vue
  44. 50 16
      src/views/videoManage/index.vue
  45. 32 0
      src/views/videoManage/wechatAudit/index.vue
  46. 58 1
      src/views/videoManage/detail.vue
  47. 6 1
      src/views/videoManage/form/create.vue
  48. 0 0
      src/views/videoManage/wechatAudit/tabs/wechatAuditList/form/subscribeSet.vue
  49. 0 0
      src/views/videoManage/wechatAudit/tabs/wechatAuditList/form/uploadVideo.vue
  50. 183 0
      src/views/videoManage/wechatAudit/tabs/wechatAuditList/form/videoSync.vue
  51. 58 75
      src/views/videoManage/index.vue
  52. 86 0
      src/views/videoManage/wechatAudit/tabs/wechatAuditStatus/excelTitle.ts
  53. 385 0
      src/views/videoManage/wechatAudit/tabs/wechatAuditStatus/index.vue

+ 6 - 0
src/api/backConfig/index.ts

@@ -36,3 +36,9 @@ export function callbackJuliangAccountLogCallbackAgain(params: object) {
 export function callbackJuliangAccountTurnCallbackState(params: object) {
   return http.post(`/callback/juliangAccount/turnCallbackState`, params);
 }
+/**
+ * 巨量账户级回传-取消推广回传关联
+ */
+export function callbackJuliangAccountUnbindPromotion(params: object) {
+  return http.post(`/callback/juliangAccount/unbindPromotion`, params);
+}

+ 7 - 0
src/api/common/index.ts

@@ -0,0 +1,7 @@
+import http from '@/api/http';
+/**
+ * 公共参数
+ */
+export function optionsCommonParams(params?: object) {
+  return http.get('/options/CommonParams', params);
+}

+ 21 - 0
src/api/iPayment/index.ts

@@ -0,0 +1,21 @@
+import http from '@/api/http';
+/**
+ * 支付配置-列表
+ */
+export function managePayConfigList(params: object) {
+  return http.get('/manage/payConfig/list', params);
+}
+
+/**
+ * 支付配置-修改备注
+ */
+export function managePayConfigRemark(params: object) {
+  return http.post('/manage/payConfig/remark', params);
+}
+/**
+ * 支付配置-添加
+ */
+export function managePayConfigAddConfig(params: object) {
+  return http.post('/manage/payConfig/addConfig', params);
+}
+

+ 26 - 0
src/api/pageLayout/channelPage/index.ts

@@ -0,0 +1,26 @@
+import http from '@/api/http';
+/**
+ * 首页列表-列表
+ */
+export function operationManageFirstPageList(params?: object) {
+  return http.get('/operationManage/firstPage/list', params);
+}
+
+/**
+ * 首页列表-开启状态
+ */
+export function operationManageFirstPageEnableStatus(params: object) {
+  return http.post('/operationManage/firstPage/enableStatus', params);
+}
+/**
+ * 首页列表-添加
+ */
+export function operationManageFirstPageAdd(params: object) {
+  return http.post(`/operationManage/firstPage/add`, params);
+}
+/**
+ * 首页列表-配置
+ */
+export function operationManageFirstPageSetConfig(params: object) {
+  return http.post(`/operationManage/firstPage/setConfig`, params);
+}

+ 26 - 0
src/api/pageLayout/homePage/index.ts

@@ -0,0 +1,26 @@
+import http from '@/api/http';
+/**
+ * 首页列表-列表
+ */
+export function operationManageFirstPageList(params?: object) {
+  return http.get('/operationManage/firstPage/list', params);
+}
+
+/**
+ * 首页列表-开启状态
+ */
+export function operationManageFirstPageEnableStatus(params: object) {
+  return http.post('/operationManage/firstPage/enableStatus', params);
+}
+/**
+ * 首页列表-添加
+ */
+export function operationManageFirstPageAdd(params: object) {
+  return http.post(`/operationManage/firstPage/add`, params);
+}
+/**
+ * 首页列表-配置
+ */
+export function operationManageFirstPageSetConfig(params: object) {
+  return http.post(`/operationManage/firstPage/setConfig`, params);
+}

+ 35 - 0
src/api/pageLayout/viewpagerPage/index.ts

@@ -0,0 +1,35 @@
+import http from '@/api/http';
+/**
+ * 轮播图-列表
+ */
+export function operationBannerList(params?: object) {
+  return http.get('/operation/banner/list', params);
+}
+
+/**
+ * 轮播图-编辑状态
+ */
+export function operationBannerEditStatus(
+  id: number | string,
+  params?: object
+) {
+  return http.post(`/operation/banner/editStatus/${id}`, params);
+}
+/**
+ * 轮播图-添加
+ */
+export function operationBannerAdd(params: object) {
+  return http.post(`/operation/banner/add`, params);
+}
+/**
+ * 轮播图-编辑
+ */
+export function operationBannerEdit(id: number | string, params: object) {
+  return http.post(`/operation/banner/edit/${id}`, params);
+}
+/**
+ * 轮播图-删除
+ */
+export function operationBannerDel(id: number | string, params?: object) {
+  return http.post(`/operation/banner/del/${id}`, params);
+}

+ 77 - 30
src/components/Upload/myUpload.vue

@@ -2,8 +2,10 @@
   <div class="upload_wrap">
     <div v-if="waitFileList.length > 0">
       <div class="el-upload-list el-upload-list--picture-card" v-if="listType == 'picture-card' || listType == 'picture'">
-        <div class="el-upload-list__item is-success" v-for="( item, index ) in  waitFileList " :key="index">
-          <el-image style="width:148px;height:148px;" :src="item.url" fit="fill" :lazy="true"></el-image>
+        <div class="el-upload-list__item is-success" style="width:fit-content;height:fit-content;"
+          v-for="( item, index ) in  waitFileList " :key="index">
+          <el-image style="width:fit-content;height:148px; min-width:148px" :src="item.url" fit="cover"
+            :lazy="true"></el-image>
           <div v-if="!props.isDisableUpload" class="el-upload-list__item-actions el-upload-list__item-delete">
             <el-icon class="cursor-pointer" @click="removeFile(item)">
               <DeleteFilled />
@@ -48,8 +50,13 @@
       </div>
       <template #tip v-if="!props.isDisableUpload && isShowTips">
         <div class="el-upload__tip">
-          <span>支持{{ acceptType.replace(",", "/") }};</span> <span v-if="isLimitSize">文件大小不能超过{{
-            props.maxFileSize }}M</span>
+          <span>支持{{ acceptType.replaceAll(",", "/") }};</span>
+          <span v-if="isLimitSize">
+            文件大小不能超过{{ props.maxFileSize }}M;
+          </span>
+          <span v-if="isCheckMM">
+            尺寸:{{ props.widthLimit }}*{{ props.heightLimit }}px
+          </span>
         </div>
       </template>
     </el-upload>
@@ -68,27 +75,29 @@ import type { UploadProps, UploadUserFile } from 'element-plus'
 const emits = defineEmits(["fileSuccess", "fileRemove"]);
 interface Props {
   acceptType?: string; // 上传文件类型
-  acceptTypeDesc?: string; // 描述 - 上传文件类型
   isMultiple?: boolean; //   是否可批量上传
   isCheckName?: boolean; //   是否检查文件名
   limitNum?: number; // 允许上传文件的最大数量
   isDisableUpload?: boolean; // 是否禁用上传
   maxFileSize?: number; // 文件大小
+  widthLimit?: number; // 图片宽度
+  heightLimit?: number; // 图片高度
   isLimitSize?: boolean;//是否限制大小
   isShowTips?: boolean;
   action?: string;
   formType?: string;//上传的文件字段名称
   fileList?: any; // 回显的文件
   isDownLoad?: boolean; // 是否可以下载
+  isCheckMM?: boolean; // 是否检查图片尺寸
   listType?: string;//文件上传样式类型
 }
 // 接收父组件传递过来的参数
 const props = withDefaults(defineProps<Props>(), {
   acceptType: ".jpeg,.png",
-  acceptTypeDesc: ".png/.jpeg",
   formType: "photo",
   isMultiple: false,
   isCheckName: false,
+  isCheckMM: false,
   limitNum: 10,
   isDisableUpload: false,
   maxFileSize: 0.5,
@@ -96,15 +105,14 @@ const props = withDefaults(defineProps<Props>(), {
   isLimitSize: true,
   action: "/qiniu/upload/image",
   fileList: [],
+  widthLimit: 690,
+  heightLimit: 280,
   isDownLoad: false,
   listType: 'picture-card'
 });
 let waitFileList = ref<any[]>([]);
 
 waitFileList.value = props.fileList;
-// waitFileList.value?.forEach((item: any) => {
-//   item.name = item.original;
-// });
 const dialogImageUrl = ref('')
 const dialogVisible = ref(false)
 const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
@@ -119,16 +127,15 @@ watch(
   () => {
     console.log("props.fileList====>", props.fileList);
     waitFileList.value = props.fileList;
-    // waitFileList.value?.forEach((item: any) => {
-    //   item.name = item.original;
-    // });
   }
 );
 
 // 文件变化Handle 这里监听上传文件的变化是一个一个接收到变化的,所以文件也是一个一个上传到服务器上面的
 const handleChange = async (file: any, fileList: any[]) => {
-  console.log(fileList, 'fileListfileList');
-  console.log(file, 'filefilefile', /^[0-9_][0-9_]*$/.test(file.name));
+  if (props.isCheckMM) {
+    const test = await limitFileWH(file)
+    if (!test) return
+  }
   if (!/^[0-9]+_/.test(file.name) && props.isCheckName) {
     ElMessage.error(`文件上传格式错误`);
     return false
@@ -139,13 +146,13 @@ const handleChange = async (file: any, fileList: any[]) => {
   let acceptTypeList = list.map((its: string) => {
     return getType(its)
   })
+  console.log(list, acceptTypeList, rawFile.type, 'acceptTypeListacceptTypeList');
   // 如果要检索的字符串值没有出现,则该方法返回 -1
   const ars = acceptTypeList.filter((q: string) => {
     return rawFile.type.indexOf(q) > -1
   })
   // 用于校验是否符合上传条件
-  const type = props.acceptTypeDesc.replace("/", ", ");
-  console.log(props.acceptTypeDesc, 66666666, props.acceptType, '55555555555', type);
+  const type = props.acceptType
   if (ars.length < 1) {
     ElMessage.error(`仅支持格式为${type}的图片`);
     return false;
@@ -156,7 +163,8 @@ const handleChange = async (file: any, fileList: any[]) => {
       return item.uid != rawFile.uid;
     });
     return false;
-  } else {
+  }
+  else {
     let formData = new FormData();
     formData.append(props.formType, rawFile);
     const loadingInstance = ElLoading.service({
@@ -183,48 +191,87 @@ const handleChange = async (file: any, fileList: any[]) => {
   }
   return true;
 };
+//限制图片尺寸
+const limitFileWH = (file) => {
+  const isSize = new Promise(function (resolve, reject) {
+    const reader = new FileReader();
+    reader.onload = (event) => {
+      const image = new Image();
+      image.onload = () => {
+        const { width, height, size } = image;
+        if (width !== props.widthLimit || height !== props.heightLimit) {
+          reject(image);
+        } else {
+          resolve(image);
+        }
+      };
+
+      image.onerror = (error) => {
+        reject(`图片加载错误:${error}`);
+      };
+      image.src = event.target.result;
+    };
+
+    reader.onerror = (error) => {
+      reject(`文件读取错误:${error}`);
+    };
+
+    reader.readAsDataURL(file.raw);
+  }).then((e) => {
+    return true;
+  }, (e) => {
+    console.log(props.widthLimit);
+    ElMessage.error({
+      message: '上传文件的图片大小不合符标准,宽需要为' + props.widthLimit + 'px,高需要为' + props.heightLimit + 'px。当前上传图片的宽高分别为:' + e.width + 'px和' +
+        e.height + 'px',
+    })
+    return false;
+  });
+  return isSize
+}
+
 
 // 校验上传文件格式
 const getType = (acceptType: string) => {
   let val = "";
   switch (acceptType) {
-    case "xls":
+    case ".xls":
       val = "excel";
       break;
-    case "doc":
+    case ".doc":
       val = "word";
       break;
-    case "pdf":
+    case ".pdf":
       val = "pdf";
       break;
-    case "zip":
+    case ".zip":
       val = "zip";
       break;
-    case "xlsx":
+    case ".xlsx":
       val = "sheet";
       break;
-    case "pptx":
+    case ".pptx":
       val = "presentation";
       break;
-    case "docx":
+    case ".docx":
       val = "document";
       break;
-    case "text":
+    case ".text":
       val = "text";
       break;
-    case "jpeg":
+    case ".jpeg":
       val = "jpeg";
       break;
-    case "png":
+    case ".png":
       val = "png";
       break;
-    case "gif":
+    case ".gif":
       val = "gif";
       break;
-    case "mp4":
+    case ".mp4":
       val = "mp4";
       break;
-    case "mp3":
+    case ".mp3":
       val = "mp3";
       break;
   }

+ 13 - 3
src/components/admin/dialog/index.vue

@@ -1,12 +1,13 @@
 <template>
   <div>
-    <el-dialog :model-value="modelValue" :show-close="false" :fullscreen="isFullscreen" v-bind="$attrs" :width="width" :close="close" :before-close="beforeClose" draggable>
+    <el-dialog :model-value="modelValue" :align-center="alignCenter" :show-close="false" :style="{ height }"
+      :fullscreen="isFullscreen" v-bind="$attrs" :width="width" :close="close" :before-close="beforeClose" draggable>
       <template #header="{ titleId, titleClass }">
         <div class="flex justify-between w-full">
           <div>
             <h4 :id="titleId" :class="titleClass">{{ title }}</h4>
           </div>
-          <div class="flex w-12 justify-end">
+          <div class="flex justify-end w-12">
             <!--<Icon :name="fullscreenIcon" @click="fullscreen" className="hover:cursor-pointer w-4 h-4" />-->
             <Icon name="x-mark" className="hover:cursor-pointer w-5 h-5" @click="close" />
           </div>
@@ -36,7 +37,15 @@ const props = defineProps({
     type: Boolean,
     default: false,
   },
-
+  alignCenter: {
+    type: Boolean,
+    default: false,
+  },
+  height: {
+    type: String,
+    required: false,
+    default: '',
+  },
   width: {
     type: String,
     required: false,
@@ -92,6 +101,7 @@ const getWidth = () => {
 <style scoped lang="scss">
 :deep(.el-dialog) {
   border-radius: 0.5rem;
+
   .el-dialog__header {
     margin-right: 0 !important;
     border-bottom: 1px solid #e2e8f0;

+ 24 - 24
src/layout/components/header/index.vue

@@ -12,9 +12,9 @@
             value-key="id" remote @change="adverChange" reserve-keyword placeholder="请选择投手" :remote-method="remoteMethod">
             <el-option v-for="item in navDataArr" :key="item.id" :label="item.username" :value="item" />
           </el-select>
-          <el-select v-model="navData.app" style="width:260px;" class="m-2" @change="appChange" clearable filterable
-            placeholder="请选择" size="default">
-            <el-option v-for="item in miniPrograms" :key="item.id" :label="item.name" :value="item.app_name">
+          <el-select v-model="navData.app" style="width:260px;" class="m-2" @change="appChange" value-key="id" clearable
+            filterable placeholder="请选择" size="default">
+            <el-option v-for="item in miniPrograms" :key="item.id" :label="item.name" :value="item">
               <div class="flex items-center">
                 <el-image :src="item.type_logo" style="width: 20px; height: 20px" class="mr-5" fit="contain"></el-image>
                 <span class="mr-5">{{ item.name }}</span>
@@ -25,7 +25,7 @@
       </div>
 
       <div class="flex w-52 sm:min-w-[18rem] flex-row item-center pl-1 sm:pl-0 justify-end sm:justify-between mr-4">
-        <div class="hidden w-3/5 sm:flex">
+        <div class="justify-end hidden w-3/5 sm:flex">
 
           <!-- 菜单切换 -->
           <!-- <MenuSelect /> -->
@@ -72,18 +72,15 @@ const remoteMethod = (query: string) => {
 }
 const isShowNavData = computed(() => {
   console.log(userStore.getRoles, 'getRoles');
-  if (userStore.getRoles?.some(el => (el?.identify == 'optimizer'))) {
-    navData.value.advertiser = navDataArr.value[0]
-    isAdverDisabled.value = true;
-    miniPrograms.value = navDataArr.value[0]?.miniPrograms
-  }
   return userStore.getRoles?.some(el => (el?.identify == 'optimizer'))
 })
+console.log(isShowNavData.value, 'isShowNavDataisShowNavData');
+
 const appChange = (e) => {
   initPer()
   console.log(e, 'appChange', userStore.roles, navData.value, 'appChange.valappChangeappChangeue');
   Cache.set('nav_data', JSON.stringify(navData.value));
-
+  location.reload()
   // router.push('/')
   // let timer = setTimeout(() => {
   //   location.reload()
@@ -118,24 +115,27 @@ const initPer = () => {
 
 const init = (params?: object) => {
   advertiserListAdvertiser({ ...params, limit: 50 }).then(res => {
-    console.log(res, 'advertiserListAdvertiseradvertiserListAdvertiser');
     navDataArr.value = res.data
+    if (isShowNavData.value) {
+      if (userStore.getRoles?.some(el => (el?.identify == 'optimizer'))) {
+        navData.value.advertiser = navDataArr.value[0]
+        isAdverDisabled.value = true;
+        miniPrograms.value = navDataArr.value[0]?.miniPrograms
+      }
+      if (JSON.parse(Cache.get('nav_data'))) {
+        navData.value = JSON.parse(Cache.get('nav_data')) || {}
+        miniPrograms.value = JSON.parse(Cache.get('nav_data'))?.advertiser?.miniPrograms || []
+      } else {
+        if (miniPrograms.value.length > 0) {
+          navData.value.app = miniPrograms.value[0]
+          Cache.set('nav_data', JSON.stringify(navData.value));
+          initPer()
+        }
+      }
+    }
   })
 }
 onMounted(() => {
   init()
-  let timer = setTimeout(() => {
-    if (JSON.parse(Cache.get('nav_data'))) {
-      navData.value = JSON.parse(Cache.get('nav_data')) || {}
-      miniPrograms.value = JSON.parse(Cache.get('nav_data'))?.advertiser?.miniPrograms || []
-    } else {
-      if (miniPrograms.value.length > 0) {
-        navData.value.app = miniPrograms.value[0].app_name
-        Cache.set('nav_data', JSON.stringify(navData.value));
-        initPer()
-      }
-    }
-    clearTimeout(timer)
-  }, 300);
 })
 </script>

+ 1 - 1
src/layout/components/header/profile.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="flex w-2/5 pl-1 pr-1 hover:cursor-pointer">
     <el-dropdown size="large" placement="bottom-end" class="flex items-center justify-center w-full hover:cursor-pointer">
-      <div class="flex lg:items-center">
+      <div class="flex w-fit lg:items-center">
         <div class="rounded-full w-7 h-7"></div>
         <!-- <img :src="userStore.getAvatar" class="rounded-full w-7 h-7" /> -->
         <div class="hidden ml-2 lg:block">{{ userStore.getNickname }}</div>

+ 18 - 3
src/router/modules/charge.ts

@@ -5,13 +5,28 @@
 //   {
 //     path: '/charge',
 //     component: () => import('@/layout/index.vue'),
-//     meta: { title: '充值管理', icon: 'user' },
+//     meta: { title: '管理', icon: 'user' },
 //     children: [
 //       {
 //         path: 'index',
 //         name: 'user-account',
-//         meta: { title: '充值模板管理', icon: 'home' },
-//         component: () => import('@/views/chargeManage/chargeTemplate/index.vue')
+//         meta: { title: '频道管理', icon: 'home' },
+//         component: () =>
+//           import('@/views/pageLayout/channelPageManage/index.vue')
+//       },
+//       {
+//         path: 'index2',
+//         name: 'user-account55',
+//         meta: { title: '轮播图管理', icon: 'home' },
+//         component: () =>
+//           import('@/views/pageLayout/viewpagerPageManage/index.vue')
+//       },
+//       {
+//         path: 'index3',
+//         name: 'user-account55',
+//         meta: { title: '微信提审', icon: 'home' },
+//         component: () =>
+//           import('@/views/videoManage/wechatAudit/index.vue')
 //       }
 //     ]
 //   }

+ 1 - 1
src/stores/modules/user/index.ts

@@ -132,7 +132,7 @@ export const useUserStore = defineStore('UserStore', {
     getUserInfo() {
       return new Promise((resolve, reject) => {
         console.log(Cache.get('nav_data'), 'localStorage.getItem(nav_data)');
-        const params = { app: JSON.parse(Cache.get('nav_data'))?.app };
+        const params = { app: JSON.parse(Cache.get('nav_data'))?.app.app_name };
         console.log(params);
         http
           .get('/user/online', params)

+ 9 - 0
src/styles/var.scss

@@ -10,3 +10,12 @@
     // -el-page
     --el-page-border-radius: 8px;
 }
+
+@mixin text-ellipsis($max-lines: 1) {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: $max-lines;
+  -webkit-box-orient: vertical;
+}
+

+ 174 - 0
src/views/appletManage/iPayment/form/create.vue

@@ -0,0 +1,174 @@
+<template>
+  <el-form :model="formData" label-width="120px" ref="ruleForm" :rules="rules" v-loading="loading" class="pr-4">
+    <div class="flex flex-row justify-between">
+      <div class="w-full">
+        <el-form-item label="支付名称" prop="name">
+          <el-input v-model="formData.name" placeholder="请输入支付名称" />
+        </el-form-item>
+        <el-form-item label="收款主体" prop="payee_name">
+          <el-input v-model="formData.payee_name" placeholder="请输入收款主体" />
+        </el-form-item>
+        <el-form-item label="支付商户号" prop="pay_appid">
+          <el-input v-model.number="formData.pay_appid" clearable placeholder="请输入支付商户号" />
+        </el-form-item>
+        <el-form-item label="支付方式" prop="pay_type">
+          <el-select class="w-full" v-model="formData.pay_type" clearable filterable placeholder="请选择支付方式">
+            <el-option v-for="(item, index) in paymentList" :key="index" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="小程序类型" prop="miniprogram_type">
+          <el-select class="w-full" v-model="formData.miniprogram_type" clearable filterable placeholder="请选择小程序类型">
+            <el-option v-for="(item, index) in appletType" :key="index" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="公用支付参数" prop="pay_common_params">
+          <template #label>
+            <div class="flex items-center">
+              <span class="mr-1 text-red-600">*</span>公用支付参数
+            </div>
+          </template>
+          <div class="w-full mb-3" v-for="(item, index) in payCommonParamsList" :key="index">
+            <el-input style="width:40%;margin-right:6px;" v-model="item.params" clearable placeholder="请输入参数名称" />
+            <el-input style="width:40%;margin-right:6px;" v-model="item.value" clearable placeholder="请输入参数值" />
+            <el-button type="primary" @click="addParams" :icon="Plus" circle />
+            <el-button type="primary" @click="removeParams(index)" :disabled="payCommonParamsList.length == 1"
+              :icon="Minus" circle />
+          </div>
+        </el-form-item>
+      </div>
+    </div>
+    <div class="flex justify-end">
+      <el-button type="primary" @click="submitForm(ruleForm)">{{ $t('system.confirm') }}</el-button>
+    </div>
+  </el-form>
+</template>
+
+<script lang="ts" setup>
+import {
+  Plus,
+  Minus
+} from '@element-plus/icons-vue';
+import type { FormInstance, FormRules } from 'element-plus'
+import { managePayConfigAddConfig } from '@/api/iPayment/index'
+import { optionsCommonParams } from '@/api/common/index'
+const ruleForm = ref<FormInstance>()
+import { onMounted, ref } from 'vue';
+const props = defineProps({
+  primary: Object | null,
+});
+const formData = ref({})
+const rules = reactive({
+  pay_type: [{ required: true, message: '请选择支付方式' }],
+  miniprogram_type: [{ required: true, message: '请选择小程序类型' }],
+  pay_common_params: [
+    {
+      required: false,
+      message: '请输入公用支付参数',
+      trigger: 'blur'
+    }
+  ],
+  remark: [
+    {
+      required: false,
+      message: '请输入备注',
+      trigger: 'blur'
+    }
+  ],
+  name: [
+    {
+      required: true,
+      message: '请输入支付名称',
+      trigger: 'blur'
+    }
+  ],
+  payee_name: [
+    {
+      required: true,
+      message: '请输入收款主体',
+      trigger: 'blur'
+    }
+  ],
+  pay_appid: [
+    {
+      required: true,
+      message: '请输入支付商户号',
+      trigger: 'blur'
+    },
+    { pattern: /^[1-9]\d*$/, message: '只能输正整数', trigger: 'blur' }
+  ]
+});
+const loading = ref(false)
+const appletType = ref([])
+const paymentList = ref([])
+const payCommonParamsList = ref([{ params: '', value: '' }])
+const addParams = () => {
+  if (validateInput()) {
+    payCommonParamsList.value.push({ params: '', value: '' })
+  }
+}
+const removeParams = (idx: number) => {
+  payCommonParamsList.value.splice(idx, 1);
+}
+
+const validateInput = () => {
+  for (const item of payCommonParamsList.value) {
+    if (!item.params || !item.value) {
+      ElMessage.warning('请输入完整公用支付参数的键值对')
+      return false;
+    }
+    if (checkDuplicate(item)) {
+      ElMessage.warning(`键 ${item.params} 已存在,请输入一个唯一的键`)
+      return false;
+    }
+  }
+  return true;
+};
+
+const checkDuplicate = (item) => {
+  const count = payCommonParamsList.value.filter(
+    (i) => i.params === item.params
+  ).length;
+  return count > 1;
+};
+
+const initType = () => {
+  optionsCommonParams().then(res => {
+    appletType.value = res.data.miniprogramType
+    paymentList.value = res.data.payType
+  })
+}
+const submitForm = (formEl: FormInstance | undefined) => {
+  console.log(payCommonParamsList.value, 'test.value,test.value,');
+  let pay_common_params = {}
+  for (let item of payCommonParamsList.value) {
+    pay_common_params[item.params] = item.value
+    console.log(item);
+  }
+  if (!validateInput()) return
+  formData.value.pay_common_params = pay_common_params
+  console.log(pay_common_params, 'objobj');
+  if (!formEl) return;
+  formEl
+    .validate(valid => {
+      if (valid) {
+        managePayConfigAddConfig(formData.value).then(res => {
+          ElMessage.success(res.message)
+          loading.value = false;
+          emit('close')
+        })
+      } else {
+        loading.value = false;
+      }
+    })
+    .then(() => { });
+}
+
+if (props.primary) {
+
+}
+
+const emit = defineEmits(['close']);
+onMounted(() => {
+  initType()
+});
+</script>

+ 77 - 0
src/views/appletManage/iPayment/form/note.vue

@@ -0,0 +1,77 @@
+<template>
+  <el-form :model="form" label-width="130px" ref="ruleForm" :rules="rules" v-loading="loading" class="pr-4">
+    <div class="flex flex-row justify-between">
+      <div class="w-full">
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请填写备注" :rows="5" type="textarea" />
+        </el-form-item>
+      </div>
+    </div>
+    <div class="flex justify-end">
+      <el-button type="primary" size="default" @click="doSave(ruleForm)">确定</el-button>
+    </div>
+  </el-form>
+</template>
+
+<script lang="ts" setup>
+import type { FormInstance, FormRules } from 'element-plus'
+import { managePayConfigRemark } from '@/api/iPayment/index'
+const props = defineProps({
+  primary: Object | null,
+});
+const ruleForm = ref<FormInstance>()
+const loading = ref(false)
+const rules = reactive({
+  remark: [
+    {
+      required: false,
+      message: '请输入备注',
+      trigger: 'blur'
+    }
+  ],
+});
+const form = ref({})
+const emit = defineEmits(['close']);
+const doSave = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl
+    .validate(valid => {
+      if (valid) {
+        managePayConfigRemark(form.value).then(res => {
+          ElMessage.success(res.message)
+          loading.value = false;
+          emit('close')
+        })
+      } else {
+        loading.value = false;
+      }
+    })
+    .then(() => { });
+}
+
+if (props.primary) {
+  form.value.remark = props.primary.remark
+  form.value.id = props.primary.id
+}
+
+
+onMounted(() => {
+
+})
+
+</script>
+
+<style lang="scss" scoped>
+::v-deep(.el-input__wrapper) {
+  display: flex;
+  width: 180px;
+  flex: none;
+}
+
+.wrapper {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+}
+</style>

+ 117 - 0
src/views/appletManage/iPayment/index.vue

@@ -0,0 +1,117 @@
+<template>
+  <div class="flex flex-col justify-between w-full sm:flex-row">
+    <div class="w-full">
+      <Search :search="search" :reset="reset">
+        <template v-slot:body>
+          <el-form-item label="支付名称">
+            <el-input v-model="query.name" placeholder="请输入支付名称" clearable />
+          </el-form-item>
+          <el-form-item label="支付商户号">
+            <el-input v-model="query.pay_appid" placeholder="请输入支付商户号" clearable />
+          </el-form-item>
+          <el-form-item label="备注">
+            <el-input v-model="query.remark" placeholder="请输入备注" clearable />
+          </el-form-item>
+          <el-form-item label="支付方式">
+            <el-select v-model="query.pay_type" clearable filterable placeholder="请选择支付方式">
+              <el-option v-for="(item, index) in paymentList" :key="index" :label="item.label" :value="item.value" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="小程序类型">
+            <el-select v-model="query.miniprogram_type" clearable filterable placeholder="请选择小程序类型">
+              <el-option v-for="(item, index) in miniprogramTypelist" :key="index" :label="item.label" :value="item.value" />
+            </el-select>
+          </el-form-item>
+        </template>
+      </Search>
+      <div class="table-default">
+        <Add v-action="'manage.PayConfig.addConfig'" class="mt-5 ml-2" @click="openType('createVisible', null)" />
+        <el-table :data="tableData" class="mt-3" v-loading="loading">
+          <el-table-column prop="id" label="ID" />
+          <el-table-column prop="name" label="支付名称" />
+          <el-table-column prop="pay_type_str" label="支付方式" />
+          <el-table-column prop="payee_name" label="收款主体" />
+          <el-table-column prop="pay_appid" label="支付商户号" />
+          <el-table-column prop="miniprogram_type_str" label="小程序类型" />
+          <el-table-column prop="pay_common_params" label="公用支付参数">
+            <!-- <template #default="scope">
+              <el-input type="textarea" v-model="scope.row.pay_common_params" :rows="6" autosize disabled></el-input>
+            </template> -->
+          </el-table-column>
+          <el-table-column prop="remark" label="备注" />
+          <el-table-column label="操作" width="200">
+            <template #default="scope">
+              <el-button link type="primary" size="small" @click="openType('noteVisible', scope.row)"
+                v-action="'manage.PayConfig.remark'">备注</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+        <Paginate />
+      </div>
+      <Dialog width="800px" v-model="noteVisible" title="备注" destroy-on-close>
+        <note @close="closeType('noteVisible')" :primary="noteData"></note>
+      </Dialog>
+
+      <Dialog v-model="createVisible" title="新增" destroy-on-close>
+        <Create @close="closeType('createVisible')" :primary="createData" />
+      </Dialog>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { computed, onMounted, ref } from 'vue';
+import Create from './form/create.vue';
+import note from './form/note.vue';
+import { useGetList } from '@/hook/curd/useGetList';
+import { optionsCommonParams } from '@/api/common/index'
+
+const api = 'manage/payConfig/list';
+const noteVisible = ref(false)
+const noteData = ref<object | null>({})
+const createVisible = ref(false)
+const createData = ref<object | null>({})
+const paymentList = ref([])
+const miniprogramTypelist = ref([])
+
+const { data, query, search, reset, loading } = useGetList(api);
+
+const tableData = computed(() => data.value?.data);
+
+const openType = (type: string, data: object | null) => {
+  switch (type) {
+    case 'noteVisible':
+      noteVisible.value = true
+      noteData.value = data
+      break;
+    case 'createVisible':
+      createVisible.value = true
+      createData.value = data
+      break;
+  }
+
+}
+const closeType = (type: string) => {
+  switch (type) {
+    case 'noteVisible':
+      noteVisible.value = false
+      break;
+    case 'createVisible':
+      createVisible.value = false
+      break;
+  }
+  search()
+}
+const init = () => {
+  optionsCommonParams().then(res => {
+    console.log(res, 'optionsCommonParams');
+    paymentList.value = res.data.payType
+    miniprogramTypelist.value = res.data.miniprogramType
+  })
+}
+
+onMounted(() => {
+  init()
+  search();
+});
+</script>

+ 23 - 1
src/views/appletManage/form/create.vue

@@ -12,10 +12,16 @@
           <el-input v-model="formData.play_name" clearable size="large" placeholder="请输入对应剧场名称" />
         </el-form-item>
         <el-form-item label="类型" prop="type">
-          <el-select class="w-full" v-model="formData.type" filterable clearable placeholder="选择类型">
+          <el-select class="w-full" v-model="formData.type" @change="appletTypeChange" filterable clearable
+            placeholder="选择类型">
             <el-option v-for="item in appletType" :key="item.value" :label="item.name" :value="item.value" />
           </el-select>
         </el-form-item>
+        <el-form-item label="绑定支付信息" prop="pay_merchant_id" v-if="formData.type">
+          <el-select class="w-full" v-model="formData.pay_merchant_id" filterable clearable placeholder="选择绑定支付信息">
+            <el-option v-for="item in paymentInfo" :key="item.id" :label="item.name" :value="item.id" />
+          </el-select>
+        </el-form-item>
         <el-form-item label="APP ID" prop="appid">
           <el-input v-model="formData.appid" clearable size="large" placeholder="请输入APP ID" />
         </el-form-item>
@@ -44,6 +50,7 @@ import { useCreate } from '@/hook/curd/useCreate';
 import { useShow } from '@/hook/curd/useShow';
 import type { FormInstance, FormRules } from 'element-plus'
 import { manageMiniprogramStore, manageMiniprogramTypelist, manageMiniprogramShow, manageMiniprogramUpdate } from '@/api/applet/index'
+import { managePayConfigList } from '@/api/iPayment/index'
 const ruleForm = ref<FormInstance>()
 import { onMounted, ref } from 'vue';
 const props = defineProps({
@@ -52,6 +59,7 @@ const props = defineProps({
 const formData = ref({ status: 2, miniProgramIds: [] })
 const rules = reactive({
   type: [{ required: true, message: '请选择类型' }],
+  pay_merchant_id: [{ required: true, message: '请选择绑定支付信息' }],
   appid: [
     {
       required: true,
@@ -102,13 +110,26 @@ const rules = reactive({
 });
 const loading = ref(false)
 const appletType = ref([])
+const paymentInfo = ref([])
+
+
+const appletTypeChange = (e) => {
+  initPaymentInfo({ limit: 100000 })
+}
 
+const initPaymentInfo = (params?: object) => {
+  managePayConfigList({ miniprogram_type: formData.value.type, ...params }).then(res => {
+    console.log(res, 'channelMiniprogramListchannelMiniprogramList');
+    paymentInfo.value = res.data
+  })
+}
 const initAppletType = () => {
   manageMiniprogramTypelist().then(res => {
     console.log(res, 'channelMiniprogramListchannelMiniprogramList');
     appletType.value = res.data
   })
 }
+
 const submitForm = (formEl: FormInstance | undefined) => {
   console.log(formData.value, 'formData.valueformData.value');
   if (!formEl) return;
@@ -139,6 +160,7 @@ if (props.primary) {
   manageMiniprogramShow(props.primary).then(res => {
     console.log(res, 'props.primary');
     formData.value = res.data
+    initPaymentInfo({ limit: 100000 })
   })
 }
 

src/views/appletManage/form/depotsTransfer.vue → src/views/appletManage/miniProgramList/form/depotsTransfer.vue


+ 32 - 11
src/views/appletManage/index.vue

@@ -9,11 +9,11 @@
           <el-form-item label="对应剧场名称">
             <el-input v-model="query.play_name" clearable />
           </el-form-item>
-          <!-- <el-form-item label="所属公司">
+          <el-form-item label="所属公司">
             <el-select v-model="query.company" clearable filterable placeholder="请选择">
               <el-option v-for="(item, index) in companylist" :key="index" :label="item" :value="item" />
             </el-select>
-          </el-form-item> -->
+          </el-form-item>
           <el-form-item label="类型">
             <el-select v-model="query.type" clearable filterable placeholder="请选择">
               <el-option v-for="(item, index) in miniprogramTypelist" :key="index" :label="item.name"
@@ -26,20 +26,41 @@
         <Operate :show="open" v-action="'manage.miniprogram.store'" />
         <el-table :data="tableData" class="mt-3" v-loading="loading">
           <el-table-column prop="id" label="ID" />
-          <el-table-column prop="name" label="小程序名称">
+          <el-table-column prop="name" label="小程序名称" min-width="200">
             <template #default="scope">
               <el-tooltip placement="top" v-if="scope.row.remark">
                 <template #content> {{ scope.row.remark }}<br /> </template>
-                <span>{{ scope.row.name }}</span>
+                <div class="flex flex-col">
+                  <div class="text-lg font-bold text-blue-400">{{ scope.row.name }}</div>
+                  <div>
+                    <span class="text-base">app id:</span>
+                    <span class="text-base font-bold">{{ scope.row.appid }}</span>
+                  </div>
+                  <div>
+                    <span class="text-base">app 密匙:</span>
+                    <span class="text-base font-bold">{{ scope.row.appsecret }}</span>
+                  </div>
+                </div>
               </el-tooltip>
-              <span v-else>{{ scope.row.name }}</span>
+              <div v-else class="flex flex-col">
+                <div class="text-lg font-bold text-blue-400 ">{{ scope.row.name }}</div>
+                <div>
+                  <span class="text-base">app id:</span>
+                  <span class="text-base font-bold">{{ scope.row.appid }}</span>
+                </div>
+                <div>
+                  <span class="text-base">app 密匙:</span>
+                  <span class="text-base font-bold">{{ scope.row.appsecret }}</span>
+                </div>
+              </div>
             </template>
           </el-table-column>
-          <!-- <el-table-column prop="company" label="所属公司" /> -->
+          <el-table-column prop="company" label="所属公司" />
           <el-table-column prop="play_name" label="对应剧场名称" />
+          <el-table-column prop="pay_merchant_name" label="已绑定支付信息" />
           <el-table-column prop="status_name" label="状态" />
           <el-table-column prop="type_name" label="类型" />
-          <el-table-column label="操作" width="200">
+          <el-table-column label="操作" width="200" fixed="right">
             <template #default="scope">
               <el-button link type="primary" size="small" @click="opendepots(scope.row)"
                 v-action="'manage.miniprogram.allocationStore'">分配</el-button>
@@ -69,7 +90,7 @@ import { useGetList } from '@/hook/curd/useGetList';
 import { useOpen } from '@/hook/curd/useOpen';
 import { manageMiniprogramCompanylist, manageMiniprogramTypelist } from '@/api/applet/index'
 
-const api = '/manage/miniprogram/index';
+const api = 'manage/miniprogram/index';
 const depotsVisible = ref(false)
 const depotsData = ref({})
 const companylist = ref([])
@@ -90,9 +111,9 @@ const closeDeptos = () => {
   search()
 }
 const init = () => {
-  // manageMiniprogramCompanylist().then(res => {
-  //   companylist.value = res.data
-  // })
+  manageMiniprogramCompanylist().then(res => {
+    companylist.value = res.data
+  })
   manageMiniprogramTypelist().then(res => {
     miniprogramTypelist.value = res.data
   })

+ 25 - 23
src/views/ordersManage/tabs/rechargeList/index.vue

@@ -49,23 +49,23 @@
             v-model="query.orderTime" type="daterange" :shortcuts="shortcuts" range-separator="To"
             start-placeholder="开始时间" end-placeholder="结束时间" />
         </el-form-item>
-		<el-form-item label="支付名称" prop="pay_merchant_name"  v-if="rolesIdentify.includes('administrator')">
-		  <el-input v-model="query.pay_merchant_name" placeholder="请输入支付名称" clearable />
-		</el-form-item>
-		<el-form-item label="收款主体" prop="payee_name" v-if="rolesIdentify.includes('administrator')">
-		  <el-input v-model="query.payee_name" placeholder="请输入收款主体" clearable />
-		</el-form-item>
-		<el-form-item label="支付商户号" prop="pay_appid"  v-if="rolesIdentify.includes('administrator')">
-		  <el-input v-model="query.pay_appid" placeholder="请输入支付商户号" clearable />
-		</el-form-item>
+        <el-form-item label="支付名称" prop="pay_merchant_name" v-if="rolesIdentify.includes('administrator')">
+          <el-input v-model="query.pay_merchant_name" placeholder="请输入支付名称" clearable />
+        </el-form-item>
+        <el-form-item label="收款主体" prop="payee_name" v-if="rolesIdentify.includes('administrator')">
+          <el-input v-model="query.payee_name" placeholder="请输入收款主体" clearable />
+        </el-form-item>
+        <el-form-item label="支付商户号" prop="pay_appid" v-if="rolesIdentify.includes('administrator')">
+          <el-input v-model="query.pay_appid" placeholder="请输入支付商户号" clearable />
+        </el-form-item>
       </template>
       <template v-slot:extra_button>
-        <exportExcel  v-if="rolesIdentify.includes('administrator')"  api="channel/order_list" sheet_name="订单列表" :title_obj="titlePtObj"
+        <exportExcel v-if="rolesIdentify.includes('administrator')" api="channel/order_list" sheet_name="订单列表"
+          :title_obj="titlePtObj" :extro_params="{ is_export: true, ...query }">
+        </exportExcel>
+        <exportExcel v-else api="channel/order_list" sheet_name="订单列表" :title_obj="titleObj"
           :extro_params="{ is_export: true, ...query }">
         </exportExcel>
-		<exportExcel v-else api="channel/order_list" sheet_name="订单列表" :title_obj="titleObj"
-		  :extro_params="{ is_export: true, ...query }">
-		</exportExcel>
       </template>
     </Search>
     <div class="table-default">
@@ -98,12 +98,15 @@
         </el-table-column>
         <el-table-column prop="pay_name" label="支付方式" show-overflow-tooltip min-width="150px">
         </el-table-column>
-		<el-table-column prop="pay_merchant_name" label="支付名称" show-overflow-tooltip min-width="150px"  v-if="rolesIdentify.includes('administrator')">
-		</el-table-column>
-		<el-table-column prop="payee_name" label="收款主体" show-overflow-tooltip min-width="150px"  v-if="rolesIdentify.includes('administrator')">
-		</el-table-column>
-		<el-table-column prop="pay_appid" label="支付商户号" show-overflow-tooltip min-width="150px"  v-if="rolesIdentify.includes('administrator')">
-		</el-table-column>
+        <el-table-column prop="pay_merchant_name" label="支付名称" show-overflow-tooltip min-width="150px"
+          v-if="rolesIdentify.includes('administrator')">
+        </el-table-column>
+        <el-table-column prop="payee_name" label="收款主体" show-overflow-tooltip min-width="150px"
+          v-if="rolesIdentify.includes('administrator')">
+        </el-table-column>
+        <el-table-column prop="pay_appid" label="支付商户号" show-overflow-tooltip min-width="150px"
+          v-if="rolesIdentify.includes('administrator')">
+        </el-table-column>
         <el-table-column prop="status_txt" label="订单状态" show-overflow-tooltip min-width="150px">
           <template #default="scope">
             <div class="wrapper">
@@ -127,7 +130,7 @@
       </el-table>
       <Paginate />
     </div>
-    <Dialog v-model="userDetailVisible" width="50%" title="用户详情" destroy-on-close>
+    <Dialog v-model="userDetailVisible" width="50%" title="用户详情" :alignCenter="true" destroy-on-close>
       <userDetail @close="closeType('applyVisible')" :primary="userDetailData"></userDetail>
     </Dialog>
     <Dialog v-model="applyVisible" width="50%" title="申请退款" destroy-on-close>
@@ -141,7 +144,7 @@ import { shortcuts } from '@/utils/shortcuts'
 import { useRouter, useRoute } from 'vue-router'
 import { InfoFilled } from '@element-plus/icons-vue';
 import { useGetList } from '@/hook/curd/useGetList';
-import { titleObj,titlePtObj } from "./excelTitle"
+import { titleObj, titlePtObj } from "./excelTitle"
 import userDetail from './userDetail/index.vue'
 import create from './form/create.vue'
 import {
@@ -319,5 +322,4 @@ onMounted(() => {
       font-size: 15px;
     }
   }
-}
-</style>
+}</style>

+ 98 - 0
src/views/pageLayout/channelPageManage/form/config.vue

@@ -0,0 +1,98 @@
+<template>
+  <el-form :model="formCallback" label-width="120px" ref="form" v-loading="loading" class="pr-4">
+    <el-form-item label="列表名称" prop="ids" :rules="[{ required: false, message: '巨量账户ID必须填写' }]" label-width="120px">
+      <el-input v-model="props.primary.type_str" disabled size="default" clearable></el-input>
+    </el-form-item>
+    <el-form-item label="短剧" prop="duanjus" :rules="[{ required: true, message: '选择短剧' }]">
+      <div>
+        <div class="flex flex-wrap mb-5" v-if="formCallback.duanjus.length > 0">
+          <div v-for="item in formCallback.duanjus" :key="item.id" class="mt-3 mr-3">
+            <el-input v-model="item.name" disabled placeholder="短剧名称" style="width:300px;" class="input-with-select">
+              <template #prepend>
+                <el-input type="number" min="1" disabled v-model.number="item.sort" placeholder="排序" size="default"
+                  clearable style="width: 115px"></el-input>
+              </template>
+            </el-input>
+          </div>
+        </div>
+        <div>
+          <el-button type="primary" size="default" @click="chooseShort">选择短剧</el-button>
+        </div>
+      </div>
+    </el-form-item>
+    <div class="flex justify-end">
+      <el-button type="primary" @click="submitForm(form)">{{
+        $t('system.confirm')
+      }}</el-button>
+    </div>
+  </el-form>
+  <Dialog v-model="videoVisible" title="选择短剧" width="90%" :alignCenter="true" destroy-on-close>
+    <videoList @confirm="confirm" :primary="formCallback.duanjus"></videoList>
+  </Dialog>
+</template>
+
+<script lang="ts" setup>
+import videoList from './videoList.vue';
+import { Close } from '@element-plus/icons-vue';
+import { FormInstance } from 'element-plus';
+import { operationManageFirstPageSetConfig } from '@/api/pageLayout/homePage/index';
+import { useRouter, useRoute } from 'vue-router'
+const props = defineProps({
+  primary: Object,
+});
+const router = useRouter()
+const route = useRoute()
+const emit = defineEmits(['close']);
+const loading = ref(false)
+const videoVisible = ref(false)
+const promotion = ref('')
+const form = ref()
+const formCallback = ref({
+  duanjus: []
+})
+
+
+const chooseShort = () => {
+  videoVisible.value = true
+}
+
+const confirm = (e) => {
+  formCallback.value.duanjus = e
+  videoVisible.value = false
+}
+// 提交回传配置
+const submitForm = (formEl: FormInstance | undefined) => {
+  console.log(formCallback.value, 'formCallbackformCallback');
+  if (!formEl) return;
+  loading.value = true;
+  formEl
+    .validate(valid => {
+      if (valid) {
+        operationManageFirstPageSetConfig(formCallback.value).then(res => {
+          ElMessage.success(res.message)
+          emit('close')
+        })
+        loading.value = false;
+      } else {
+        loading.value = false;
+      }
+    })
+    .then(() => { });
+}
+
+if (props.primary) {
+  console.log(props.primary, 'props.primaryprops.primary');
+  formCallback.value.id = props.primary.id
+  formCallback.value.duanjus = props.primary.duanjus
+}
+onMounted(() => {
+});
+</script>
+
+<style lang="scss" scoped>
+:deep(.input-with-select .el-input-group__prepend) {
+  background-color: #FFFFFF;
+  padding: 0;
+  border: 1px solid #dcdfe6;
+}
+</style>

+ 72 - 0
src/views/pageLayout/channelPageManage/form/create.vue

@@ -0,0 +1,72 @@
+<template>
+  <el-form :model="formCallback" label-width="120px" ref="form" v-loading="loading" class="pr-4">
+    <el-form-item label="小程序类型" prop="miniprogram_type" :rules="[{ required: true, message: '选择小程序类型' }]"
+      label-width="120px">
+      <el-select v-model="formCallback.miniprogram_type" clearable filterable placeholder="请选择小程序类型">
+        <el-option v-for="(item, index) in miniprogramTypelist" :key="index" :label="item.label" :value="item.value" />
+      </el-select>
+    </el-form-item>
+    <el-form-item label="列表名称" prop="type" :rules="[{ required: true, message: '选择列表名称' }]" label-width="120px">
+      <el-select v-model="formCallback.type" clearable filterable placeholder="请选择支付方式">
+        <el-option v-for="(item, index) in typeList" :key="index" :label="item.name" :value="item.value" />
+      </el-select>
+    </el-form-item>
+    <el-form-item label="状态" prop="status" label-width="120px" :rules="[{ required: true, message: '选择状态' }]">
+      <el-switch v-model="formCallback.status" :active-value="1" :inactive-value="0"></el-switch>
+    </el-form-item>
+    <div class="flex justify-end">
+      <el-button type="primary" @click="submitForm(form)">{{
+        $t('system.confirm')
+      }}</el-button>
+    </div>
+  </el-form>
+</template>
+
+<script lang="ts" setup>
+import { Close } from '@element-plus/icons-vue';
+import { FormInstance } from 'element-plus';
+import { operationManageFirstPageAdd } from '@/api/pageLayout/homePage/index'
+const emit = defineEmits(['close']);
+const loading = ref(false)
+const form = ref()
+import { optionsCommonParams } from '@/api/common/index'
+const promotion = ref('')
+const formCallback = ref({
+  status: 0,
+})
+
+const typeList = ref([{ name: '本周精选', value: 1 }, { name: '优选好剧', value: 2 }])
+const miniprogramTypelist = ref([])
+const init = () => {
+  optionsCommonParams().then(res => {
+    console.log(res, 'optionsCommonParams');
+    miniprogramTypelist.value = res.data.miniprogramType
+  })
+}
+// 提交回传配置
+const submitForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  loading.value = true;
+  if (!formEl) return;
+  formEl
+    .validate(valid => {
+      if (valid) {
+        operationManageFirstPageAdd(formCallback.value).then(res => {
+          ElMessage.success(res.message)
+          emit('close')
+        })
+        loading.value = false;
+      } else {
+        loading.value = false;
+      }
+    })
+    .then(() => { });
+}
+
+
+onMounted(() => {
+  init()
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 276 - 0
src/views/pageLayout/channelPageManage/form/videoList.vue

@@ -0,0 +1,276 @@
+<template>
+  <div>
+    <el-card shadow="always" :body-style="{ padding: '20px' }" v-if="multipleSelection.length > 0">
+      <template #header>
+        <div class="text-base font-bold card-header">
+          <span>所选短剧:</span>
+        </div>
+      </template>
+      <div class="flex flex-wrap items-start ml-6 choose-wrapper">
+        <el-form-item label="" class="font-bold">
+          <div v-for="(item, index) in multipleSelection" :key="item.id" class="mb-3 mr-3">
+            <el-input type="number" :disabled="false" min="1" v-model.number="sortValues[index]" placeholder="排序"
+              size="default" clearable style="width: 115px;"></el-input>
+            <el-input v-model="item.name" :disabled="true" placeholder="短剧名称" style="width:300px;"
+              class="input-with-select">
+            </el-input>
+          </div>
+        </el-form-item>
+      </div>
+    </el-card>
+    <Search :search="search" :reset="resetQuery">
+      <template v-slot:body>
+        <el-form-item label="短剧" prop="name">
+          <el-input v-model="query.videoName" placeholder="请输入短剧名称" clearable />
+        </el-form-item>
+        <el-form-item label="状态" prop="updateType">
+          <el-select v-model="query.updateType" filterable clearable placeholder="请选择状态">
+            <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="频道" prop="categoryId">
+          <el-cascader v-model="selectType" :options="cooperations" filterable clearable :change-on-select="true"
+            @change="handleCascaderChange" />
+        </el-form-item>
+        <el-form-item label="微信审核状态" prop="wechatPass">
+          <el-select v-model="query.wechatPass" disabled filterable clearable placeholder="请选择微信审核状态">
+            <el-option v-for="item in wxstatusOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+      </template>
+    </Search>
+    <div class="table-default">
+      <el-table :data="tableData" ref="multipleTableRef" height="380px" class="mt-3" v-loading="loading" row-key="id"
+        @selection-change="handleSelectionChange">
+        <el-table-column type="selection" reserve-selection />
+        <el-table-column prop="id" label="剧号" />
+        <el-table-column label="封面" show-overflow-tooltip>
+          <template #default="scope">
+            <div class="flex flex-col items-start justify-center wrapper">
+              <el-popover placement="top" :width="200" trigger="click">
+                <template #reference>
+                  <el-image :src="scope.row.cover_image" class="cursor-pointer" style="width:48px;height:48px;"
+                    fit="contain" :lazy="true"></el-image>
+                </template>
+                <el-image :src="scope.row.cover_image" style="width:100%;" fit="contain"></el-image>
+              </el-popover>
+              <el-button type="primary" link size="default" @click="dowload(scope.row)">下载</el-button>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="短剧名称" show-overflow-tooltip min-width="250">
+          <template #default="scope">
+            <div class="wrapper">
+              <span class="text-lg font-bold text-blue-400 cursor-pointer content">
+                {{ scope.row.name }}
+              </span>
+              <span>
+                【 {{ scope.row.update_type_str }} 】
+              </span>
+            </div>
+            <div class="wrapper">
+              <span class="label">上架时间:</span>
+              <span class="content">{{ scope.row.shelf_at }}</span>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="total_episode_num" label="集数">
+          <template #default="scope">
+            <div class="flex wrapper">
+              <div v-if="scope.row.update_type == 1">
+                <span class="content">
+                  {{ scope.row.updated_episode_num }}
+                </span>
+                <span>/</span>
+              </div>
+              <div>
+                <span class="content">
+                  {{ scope.row.total_episode_num }}
+                </span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="category_str" label="频道" />
+        <el-table-column prop="shelf_type_str" label="上架状态" />
+        <el-table-column prop="charge_sequence" label="起始集" />
+        <el-table-column prop="charge_coin" label="定价">
+          <template #header>
+            <div class="flex items-center">
+              <span>定价</span>
+              <el-tooltip placement="top">
+                <template #content> 定价为所需看剧币<br />1元等于100币 </template>
+                <el-icon>
+                  <InfoFilled />
+                </el-icon>
+              </el-tooltip>
+            </div>
+          </template>
+          <template #default="scope">
+            <span>{{ scope.row.charge_coin }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <Paginate />
+    </div>
+    <div class="flex justify-end">
+      <el-button type="primary" @click="confirm">{{
+        $t('system.confirm')
+      }}</el-button>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { downloadImage } from '@/utils/index'
+import { InfoFilled } from '@element-plus/icons-vue';
+import { provide } from 'vue'
+import { useGetList } from '@/hook/curd/useGetList';
+import { useDestroy } from '@/hook/curd/useDestroy';
+import { useOpen } from '@/hook/curd/useOpen';
+import { videoStockVideoCategoryList, videoStockVideoList } from '@/api/video/index'
+const api = 'videoStock/video/list';
+const multipleTableRef = ref()
+const multipleSelection = ref([]);
+const { data, query, search, reset, loading } = useGetList(api);
+const selectType = ref([])
+const statusOptions = ref([{ label: '连载中', value: '1' }, { label: '完结', value: '2' }]);
+const wxstatusOptions = ref([{ label: '未通过', value: 0 }, { label: '已通过', value: 1 }]);
+const cooperations = ref([]);
+const emit = defineEmits(['confirm']);
+const props = defineProps({
+  primary: Object,
+});
+const sortValues = ref([])
+const rowSelectFlag = ref(false)// 禁止toggleRowSelection默认触发handleSelectionChange
+const handleCascaderChange = (val: any) => {
+  console.log(val, 'valval');
+  if (val) {
+    // 获取最后一级选项的值
+    const lastOptionValue = val[val.length - 1];
+    // 更新 selectedOptions 的值
+    query.value.categoryId = lastOptionValue;
+  } else {
+    delete query.value.categoryId
+  }
+}
+
+const resetQuery = () => {
+  query.value = Object.assign({ page: query.value.page, limit: query.value.limit, shelfType: 2, wechatPass: 1 });
+  search()
+  selectType.value = []
+}
+const initType = () => {
+  videoStockVideoCategoryList().then(res => {
+    console.log(res);
+    cooperations.value = res.data
+  })
+}
+// 下载封面
+const dowload = (e: object) => {
+  downloadImage(e.cover_image, e.name)
+}
+
+const validateData = () => {
+  const sortSet = new Set();
+  const nameSet = new Set();
+
+  for (const item of multipleSelection.value) {
+    if (item.sort === null || item.sort === undefined) {
+      ElMessage.error(`${item.name}的排序不能为空`)
+      return false;
+    }
+    if (sortSet.has(item.sort)) {
+      ElMessage.error(`${item.name}的排序重复`)
+      return false;
+    }
+    sortSet.add(item.sort);
+    if (nameSet.has(item.name)) {
+      ElMessage.error(`${item.name}的排序重复`)
+      return false;
+    }
+
+    nameSet.add(item.name);
+  }
+
+  return true;
+};
+
+const tableData = computed(() => data.value?.data);
+
+const handleSelectionChange = (val: []) => {
+  if (rowSelectFlag.value) return
+  multipleSelection.value = val;
+};
+const confirm = () => {
+  const params = multipleSelection.value.map((el, index) => {
+    multipleSelection.value[index].sort = sortValues.value[index]
+    return {
+      id: el.id,
+      sort: sortValues.value[index],
+      name: el.name
+    }
+  })
+  console.log(sortValues.value, params, 'sortValues[index]');
+  if (validateData()) {
+    // 执行提交逻辑
+    console.log('数据验证通过');
+    emit('confirm', params)
+  }
+}
+
+if (props.primary) {
+  // console.log(props.primary, 'props.primaryprops.primary');
+  multipleSelection.value = props.primary || []
+  if (multipleSelection.value.length > 0) {
+    sortValues.value = multipleSelection.value.map(el => el.sort)
+    console.log(sortValues.value, 'sortValues.valuesortValues.value');
+  }
+}
+
+const setRowSelected = () => {
+  rowSelectFlag.value = true
+  Object.keys(multipleSelection.value).forEach(key => {
+    multipleSelection.value[key] && multipleTableRef.value.toggleRowSelection(multipleSelection.value[key], true)
+  })
+  rowSelectFlag.value = false
+}
+onMounted(() => {
+  // 初始化 sortValues 数组长度,保持与 multipleSelection 数组一致
+  // sortValues.value = new Array(multipleSelection.value.length);
+  query.value = Object.assign({ page: query.value.page, limit: query.value.limit, shelfType: 2, wechatPass: 1 });
+  setRowSelected()
+  initType()
+  search();
+});
+</script>
+
+<style scoped lang="scss">
+.choose-wrapper {
+  height: fit-content;
+  max-height: 150px;
+  overflow: auto;
+}
+
+
+.table-default {
+  .set-warpper {
+    height: 60px;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+  }
+
+  .wrapper {
+    margin: 8px;
+
+    .label {
+      margin-right: 6px;
+    }
+
+    .content {
+      font-size: 15px;
+    }
+  }
+}
+</style>

+ 86 - 0
src/views/pageLayout/channelPageManage/index.vue

@@ -0,0 +1,86 @@
+<template>
+  <div class="table-default">
+    <div class="pt-5 pl-2" v-action="'operation.FirstPage.add'">
+      <el-button type="primary" size="default" @click="openForm(null)">新增</el-button>
+    </div>
+    <el-table :data="tableData" class="mt-3" v-loading="loading">
+      <el-table-column label="频道ID" prop="id"></el-table-column>
+      <el-table-column label="频道名称" prop="type_str">
+      </el-table-column>
+      <el-table-column label="添加时间" prop="created_at">
+      </el-table-column>
+      <el-table-column label="状态" v-action="'operation.FirstPage.enableStatus'">
+        <template #default="scope">
+          <div>
+            <el-switch v-model="scope.row.status" :disabled="Boolean(scope.row.status)" @change="switchStatus(scope.row)"
+              :active-value="1" :inactive-value="0">
+            </el-switch>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作">
+        <template #default="scope">
+          <el-button link type="primary" size="small" @click="handleConfigure(scope.row)"
+            v-action="'operation.FirstPage.setConfig'">配置</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <Paginate />
+  </div>
+  <Dialog v-model="configVisible" title="配置" width="50%" destroy-on-close>
+    <config @close="closeType('configVisible')" :primary="currentConfig"></config>
+  </Dialog>
+
+  <Dialog v-model="addVisible" title="新增" width="30%" destroy-on-close>
+    <create @close="closeType('addVisible')"></create>
+  </Dialog>
+</template>
+
+<script lang="ts"  setup>
+import { InfoFilled } from '@element-plus/icons-vue';
+import { computed, onMounted, ref } from 'vue';
+import create from './form/create.vue';
+import config from './form/config.vue';
+import { useGetList } from '@/hook/curd/useGetList';
+import { operationManageFirstPageEnableStatus } from '@/api/pageLayout/homePage/index'
+
+const api = 'operationManage/firstPage/list';
+
+const { data, query, search, reset, loading } = useGetList(api, true);
+const tableData = computed(() => data.value?.data);
+const addVisible = ref(false)
+const currentConfig = ref({})
+const configVisible = ref(false) //设置回传弹窗
+
+const closeType = (type: string) => {
+  switch (type) {
+    case 'configVisible':
+      configVisible.value = false
+      break;
+    case 'addVisible':
+      addVisible.value = false
+      break;
+  }
+  search()
+}
+
+const switchStatus = (data: object) => {
+  operationManageFirstPageEnableStatus({ id: data.id }).then(res => {
+    ElMessage.success(res.message)
+    search()
+  })
+}
+
+
+const openForm = (data: any) => {
+  addVisible.value = true
+};
+const handleConfigure = (data: object) => {
+  currentConfig.value = data
+  configVisible.value = true
+};
+onMounted(() => {
+  search();
+});
+</script>
+<style  lang='scss' scoped></style>

+ 98 - 0
src/views/pageLayout/homePageManage/form/config.vue

@@ -0,0 +1,98 @@
+<template>
+  <el-form :model="formCallback" label-width="120px" ref="form" v-loading="loading" class="pr-4">
+    <el-form-item label="列表名称" prop="ids" :rules="[{ required: false, message: '巨量账户ID必须填写' }]" label-width="120px">
+      <el-input v-model="props.primary.type_str" disabled size="default" clearable></el-input>
+    </el-form-item>
+    <el-form-item label="短剧" prop="duanjus" :rules="[{ required: true, message: '选择短剧' }]">
+      <div>
+        <div class="flex flex-wrap mb-5" v-if="formCallback.duanjus.length > 0">
+          <div v-for="item in formCallback.duanjus" :key="item.id" class="mt-3 mr-3">
+            <el-input v-model="item.name" disabled placeholder="短剧名称" style="width:300px;" class="input-with-select">
+              <template #prepend>
+                <el-input type="number" min="1" disabled v-model.number="item.sort" placeholder="排序" size="default"
+                  clearable style="width: 115px"></el-input>
+              </template>
+            </el-input>
+          </div>
+        </div>
+        <div>
+          <el-button type="primary" size="default" @click="chooseShort">选择短剧</el-button>
+        </div>
+      </div>
+    </el-form-item>
+    <div class="flex justify-end">
+      <el-button type="primary" @click="submitForm(form)">{{
+        $t('system.confirm')
+      }}</el-button>
+    </div>
+  </el-form>
+  <Dialog v-model="videoVisible" title="选择短剧" width="90%" :alignCenter="true" destroy-on-close>
+    <videoList @confirm="confirm" :primary="formCallback.duanjus"></videoList>
+  </Dialog>
+</template>
+
+<script lang="ts" setup>
+import videoList from './videoList.vue';
+import { Close } from '@element-plus/icons-vue';
+import { FormInstance } from 'element-plus';
+import { operationManageFirstPageSetConfig } from '@/api/pageLayout/homePage/index';
+import { useRouter, useRoute } from 'vue-router'
+const props = defineProps({
+  primary: Object,
+});
+const router = useRouter()
+const route = useRoute()
+const emit = defineEmits(['close']);
+const loading = ref(false)
+const videoVisible = ref(false)
+const promotion = ref('')
+const form = ref()
+const formCallback = ref({
+  duanjus: []
+})
+
+
+const chooseShort = () => {
+  videoVisible.value = true
+}
+
+const confirm = (e) => {
+  formCallback.value.duanjus = e
+  videoVisible.value = false
+}
+// 提交回传配置
+const submitForm = (formEl: FormInstance | undefined) => {
+  console.log(formCallback.value, 'formCallbackformCallback');
+  if (!formEl) return;
+  loading.value = true;
+  formEl
+    .validate(valid => {
+      if (valid) {
+        operationManageFirstPageSetConfig(formCallback.value).then(res => {
+          ElMessage.success(res.message)
+          emit('close')
+        })
+        loading.value = false;
+      } else {
+        loading.value = false;
+      }
+    })
+    .then(() => { });
+}
+
+if (props.primary) {
+  console.log(props.primary, 'props.primaryprops.primary');
+  formCallback.value.id = props.primary.id
+  formCallback.value.duanjus = props.primary.duanjus
+}
+onMounted(() => {
+});
+</script>
+
+<style lang="scss" scoped>
+:deep(.input-with-select .el-input-group__prepend) {
+  background-color: #FFFFFF;
+  padding: 0;
+  border: 1px solid #dcdfe6;
+}
+</style>

+ 73 - 0
src/views/pageLayout/homePageManage/form/create.vue

@@ -0,0 +1,73 @@
+<template>
+  <el-form :model="formCallback" label-width="120px" ref="form" v-loading="loading" class="pr-4">
+    <el-form-item label="小程序类型" prop="miniprogram_type" :rules="[{ required: true, message: '选择小程序类型' }]"
+      label-width="120px">
+      <el-select v-model="formCallback.miniprogram_type" clearable filterable placeholder="请选择小程序类型">
+        <el-option v-for="(item, index) in miniprogramTypelist" :key="index" :label="item.label" :value="item.value" />
+      </el-select>
+    </el-form-item>
+    <el-form-item label="列表名称" prop="type" :rules="[{ required: true, message: '选择列表名称' }]" label-width="120px">
+      <el-select v-model="formCallback.type" clearable filterable placeholder="请选择支付方式">
+        <el-option v-for="(item, index) in typeList" :key="index" :label="item.name" :value="item.value" />
+      </el-select>
+    </el-form-item>
+    <el-form-item label="状态" prop="status" label-width="120px" :rules="[{ required: true, message: '选择状态' }]">
+      <el-switch v-model="formCallback.status" :active-value="1" :inactive-value="0"></el-switch>
+    </el-form-item>
+    <div class="flex justify-end">
+      <el-button type="primary" @click="submitForm(form)">{{
+        $t('system.confirm')
+      }}</el-button>
+    </div>
+  </el-form>
+</template>
+
+<script lang="ts" setup>
+import { Close } from '@element-plus/icons-vue';
+import { FormInstance } from 'element-plus';
+import { optionsCommonParams } from '@/api/common/index'
+import { operationManageFirstPageAdd } from '@/api/pageLayout/homePage/index'
+const emit = defineEmits(['close']);
+const loading = ref(false)
+const form = ref()
+const promotion = ref('')
+const formCallback = ref({
+  status: 0,
+})
+const miniprogramTypelist = ref([])
+
+const typeList = ref([{ name: '本周精选', value: 1 }, { name: '优选好剧', value: 2 }])
+const init = () => {
+  optionsCommonParams().then(res => {
+    console.log(res, 'optionsCommonParams');
+    miniprogramTypelist.value = res.data.miniprogramType
+  })
+}
+
+// 提交回传配置
+const submitForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  loading.value = true;
+  if (!formEl) return;
+  formEl
+    .validate(valid => {
+      if (valid) {
+        operationManageFirstPageAdd(formCallback.value).then(res => {
+          ElMessage.success(res.message)
+          emit('close')
+        })
+        loading.value = false;
+      } else {
+        loading.value = false;
+      }
+    })
+    .then(() => { });
+}
+
+
+onMounted(() => {
+  init()
+});
+</script>
+
+<style lang="scss" scoped></style>

+ 275 - 0
src/views/pageLayout/homePageManage/form/videoList.vue

@@ -0,0 +1,275 @@
+<template>
+  <div>
+    <el-card shadow="always" :body-style="{ padding: '20px' }" v-if="multipleSelection.length > 0">
+      <template #header>
+        <div class="text-base font-bold card-header">
+          <span>所选短剧:</span>
+        </div>
+      </template>
+      <div class="flex flex-wrap items-start ml-6 choose-wrapper">
+        <el-form-item label="" class="font-bold">
+          <div v-for="(item, index) in multipleSelection" :key="item.id" class="mb-3 mr-3">
+            <el-input type="number" :disabled="false" min="1" v-model.number="sortValues[index]" placeholder="排序"
+              size="default" clearable style="width: 115px;"></el-input>
+            <el-input v-model="item.name" :disabled="true" placeholder="短剧名称" style="width:300px;"
+              class="input-with-select">
+            </el-input>
+          </div>
+        </el-form-item>
+      </div>
+    </el-card>
+    <Search :search="search" :reset="resetQuery">
+      <template v-slot:body>
+        <el-form-item label="短剧" prop="name">
+          <el-input v-model="query.videoName" placeholder="请输入短剧名称" clearable />
+        </el-form-item>
+        <el-form-item label="状态" prop="updateType">
+          <el-select v-model="query.updateType" filterable clearable placeholder="请选择状态">
+            <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="频道" prop="categoryId">
+          <el-cascader v-model="selectType" :options="cooperations" filterable clearable :change-on-select="true"
+            @change="handleCascaderChange" />
+        </el-form-item>
+        <el-form-item label="微信审核状态" prop="wechatPass">
+          <el-select v-model="query.wechatPass" filterable clearable placeholder="请选择微信审核状态">
+            <el-option v-for="item in wxstatusOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+      </template>
+    </Search>
+    <div class="table-default">
+      <el-table :data="tableData" ref="multipleTableRef" height="380px" class="mt-3" v-loading="loading" row-key="id"
+        @selection-change="handleSelectionChange">
+        <el-table-column type="selection" reserve-selection />
+        <el-table-column prop="id" label="剧号" />
+        <el-table-column label="封面" show-overflow-tooltip>
+          <template #default="scope">
+            <div class="flex flex-col items-start justify-center wrapper">
+              <el-popover placement="top" :width="200" trigger="click">
+                <template #reference>
+                  <el-image :src="scope.row.cover_image" class="cursor-pointer" style="width:48px;height:48px;"
+                    fit="contain" :lazy="true"></el-image>
+                </template>
+                <el-image :src="scope.row.cover_image" style="width:100%;" fit="contain"></el-image>
+              </el-popover>
+              <el-button type="primary" link size="default" @click="dowload(scope.row)">下载</el-button>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="短剧名称" show-overflow-tooltip min-width="250">
+          <template #default="scope">
+            <div class="wrapper">
+              <span class="text-lg font-bold text-blue-400 cursor-pointer content">
+                {{ scope.row.name }}
+              </span>
+              <span>
+                【 {{ scope.row.update_type_str }} 】
+              </span>
+            </div>
+            <div class="wrapper">
+              <span class="label">上架时间:</span>
+              <span class="content">{{ scope.row.shelf_at }}</span>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="total_episode_num" label="集数">
+          <template #default="scope">
+            <div class="flex wrapper">
+              <div v-if="scope.row.update_type == 1">
+                <span class="content">
+                  {{ scope.row.updated_episode_num }}
+                </span>
+                <span>/</span>
+              </div>
+              <div>
+                <span class="content">
+                  {{ scope.row.total_episode_num }}
+                </span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="category_str" label="频道" />
+        <el-table-column prop="shelf_type_str" label="上架状态" />
+        <el-table-column prop="charge_sequence" label="起始集" />
+        <el-table-column prop="charge_coin" label="定价">
+          <template #header>
+            <div class="flex items-center">
+              <span>定价</span>
+              <el-tooltip placement="top">
+                <template #content> 定价为所需看剧币<br />1元等于100币 </template>
+                <el-icon>
+                  <InfoFilled />
+                </el-icon>
+              </el-tooltip>
+            </div>
+          </template>
+          <template #default="scope">
+            <span>{{ scope.row.charge_coin }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <Paginate />
+    </div>
+    <div class="flex justify-end">
+      <el-button type="primary" @click="confirm">{{
+        $t('system.confirm')
+      }}</el-button>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { downloadImage } from '@/utils/index'
+import { InfoFilled } from '@element-plus/icons-vue';
+import { provide } from 'vue'
+import { useGetList } from '@/hook/curd/useGetList';
+import { useDestroy } from '@/hook/curd/useDestroy';
+import { useOpen } from '@/hook/curd/useOpen';
+import { videoStockVideoCategoryList, videoStockVideoList } from '@/api/video/index'
+const api = 'videoStock/video/list';
+const multipleTableRef = ref()
+const multipleSelection = ref([]);
+const { data, query, search, reset, loading } = useGetList(api);
+const selectType = ref([])
+const statusOptions = ref([{ label: '连载中', value: '1' }, { label: '完结', value: '2' }]);
+const wxstatusOptions = ref([{ label: '未通过', value: 0 }, { label: '已通过', value: 1 }]);
+const cooperations = ref([]);
+const emit = defineEmits(['confirm']);
+const props = defineProps({
+  primary: Object,
+});
+const sortValues = ref([])
+const rowSelectFlag = ref(false)// 禁止toggleRowSelection默认触发handleSelectionChange
+const handleCascaderChange = (val: any) => {
+  console.log(val, 'valval');
+  if (val) {
+    // 获取最后一级选项的值
+    const lastOptionValue = val[val.length - 1];
+    // 更新 selectedOptions 的值
+    query.value.categoryId = lastOptionValue;
+  } else {
+    delete query.value.categoryId
+  }
+}
+
+const resetQuery = () => {
+  query.value = Object.assign({ page: query.value.page, limit: query.value.limit, shelfType: 2, wechatPass: 1 });
+  search()
+  selectType.value = []
+}
+const initType = () => {
+  videoStockVideoCategoryList().then(res => {
+    console.log(res);
+    cooperations.value = res.data
+  })
+}
+// 下载封面
+const dowload = (e: object) => {
+  downloadImage(e.cover_image, e.name)
+}
+
+const validateData = () => {
+  const sortSet = new Set();
+  const nameSet = new Set();
+
+  for (const item of multipleSelection.value) {
+    if (item.sort === null || item.sort === undefined) {
+      ElMessage.error(`${item.name}的排序不能为空`)
+      return false;
+    }
+    if (sortSet.has(item.sort)) {
+      ElMessage.error(`${item.name}的排序重复`)
+      return false;
+    }
+    sortSet.add(item.sort);
+    if (nameSet.has(item.name)) {
+      ElMessage.error(`${item.name}的排序重复`)
+      return false;
+    }
+
+    nameSet.add(item.name);
+  }
+
+  return true;
+};
+
+const tableData = computed(() => data.value?.data);
+
+const handleSelectionChange = (val: []) => {
+  if (rowSelectFlag.value) return
+  multipleSelection.value = val;
+};
+const confirm = () => {
+  const params = multipleSelection.value.map((el, index) => {
+    multipleSelection.value[index].sort = sortValues.value[index]
+    return {
+      id: el.id,
+      sort: sortValues.value[index],
+      name: el.name
+    }
+  })
+  console.log(sortValues.value, params, 'sortValues[index]');
+  if (validateData()) {
+    // 执行提交逻辑
+    console.log('数据验证通过');
+    emit('confirm', params)
+  }
+}
+
+if (props.primary) {
+  // console.log(props.primary, 'props.primaryprops.primary');
+  multipleSelection.value = props.primary || []
+  if (multipleSelection.value.length > 0) {
+    sortValues.value = multipleSelection.value.map(el => el.sort)
+    console.log(sortValues.value, 'sortValues.valuesortValues.value');
+  }
+}
+
+const setRowSelected = () => {
+  rowSelectFlag.value = true
+  Object.keys(multipleSelection.value).forEach(key => {
+    multipleSelection.value[key] && multipleTableRef.value.toggleRowSelection(multipleSelection.value[key], true)
+  })
+  rowSelectFlag.value = false
+}
+onMounted(() => {
+  // 初始化 sortValues 数组长度,保持与 multipleSelection 数组一致
+  // sortValues.value = new Array(multipleSelection.value.length);
+  query.value = Object.assign({ page: query.value.page, limit: query.value.limit, shelfType: 2, wechatPass: 1 });
+  setRowSelected()
+  initType()
+  search();
+});
+</script>
+
+<style scoped lang="scss">
+.choose-wrapper {
+  height: fit-content;
+  max-height: 150px;
+  overflow: auto;
+}
+
+.table-default {
+  .set-warpper {
+    height: 60px;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+  }
+
+  .wrapper {
+    margin: 8px;
+
+    .label {
+      margin-right: 6px;
+    }
+
+    .content {
+      font-size: 15px;
+    }
+  }
+}
+</style>

+ 88 - 0
src/views/pageLayout/homePageManage/index.vue

@@ -0,0 +1,88 @@
+<template>
+  <div class="table-default">
+    <div class="pt-5 pl-2" v-action="'operation.FirstPage.add'">
+      <el-button type="primary" size="default" @click="openForm(null)">新增</el-button>
+    </div>
+    <el-table :data="tableData" class="mt-3" v-loading="loading">
+      <el-table-column label="ID" prop="id"></el-table-column>
+      <el-table-column label="列表名称" prop="type_str">
+      </el-table-column>
+      <el-table-column label="添加时间" prop="created_at">
+      </el-table-column>
+      <el-table-column label="小程序类型" prop="miniprogram_type_str">
+      </el-table-column>
+      <el-table-column label="状态" v-action="'operation.FirstPage.enableStatus'">
+        <template #default="scope">
+          <div>
+            <el-switch v-model="scope.row.status" :disabled="Boolean(scope.row.status)" @change="switchStatus(scope.row)"
+              :active-value="1" :inactive-value="0">
+            </el-switch>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作">
+        <template #default="scope">
+          <el-button link type="primary" size="default" @click="handleConfigure(scope.row)"
+            v-action="'operation.FirstPage.setConfig'">配置</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <Paginate />
+  </div>
+  <Dialog v-model="configVisible" title="配置" width="50%" destroy-on-close>
+    <config @close="closeType('configVisible')" :primary="currentConfig"></config>
+  </Dialog>
+
+  <Dialog v-model="addVisible" title="新增" width="30%" destroy-on-close>
+    <create @close="closeType('addVisible')"></create>
+  </Dialog>
+</template>
+
+<script lang="ts"  setup>
+import { InfoFilled } from '@element-plus/icons-vue';
+import { computed, onMounted, ref } from 'vue';
+import create from './form/create.vue';
+import config from './form/config.vue';
+import { useGetList } from '@/hook/curd/useGetList';
+import { operationManageFirstPageEnableStatus } from '@/api/pageLayout/homePage/index'
+
+const api = 'operationManage/firstPage/list';
+
+const { data, query, search, reset, loading } = useGetList(api, true);
+const tableData = computed(() => data.value?.data);
+const addVisible = ref(false)
+const currentConfig = ref({})
+const configVisible = ref(false) //设置回传弹窗
+
+const closeType = (type: string) => {
+  switch (type) {
+    case 'configVisible':
+      configVisible.value = false
+      break;
+    case 'addVisible':
+      addVisible.value = false
+      break;
+  }
+  search()
+}
+
+const switchStatus = (data: object) => {
+  operationManageFirstPageEnableStatus({ id: data.id }).then(res => {
+    ElMessage.success(res.message)
+    search()
+  })
+}
+
+
+const openForm = (data: any) => {
+  addVisible.value = true
+};
+const handleConfigure = (data: object) => {
+  currentConfig.value = data
+  configVisible.value = true
+};
+onMounted(() => {
+  search();
+});
+</script>
+<style  lang='scss' scoped></style>

+ 142 - 0
src/views/pageLayout/viewpagerPageManage/form/create.vue

@@ -0,0 +1,142 @@
+<template>
+  <el-form :model="formCallback" label-width="120px" ref="form" v-loading="loading" class="pr-4">
+    <el-form-item label="小程序类型" prop="miniprogram_type" :rules="[{ required: true, message: '选择小程序类型' }]"
+      label-width="120px">
+      <el-select v-model="formCallback.miniprogram_type" clearable filterable placeholder="请选择小程序类型">
+        <el-option v-for="(item, index) in miniprogramTypelist" :key="index" :label="item.label" :value="item.value" />
+      </el-select>
+    </el-form-item>
+    <el-form-item label="轮播图名称" prop="title" :rules="[{ required: true, message: '轮播图名称必须填写' }]" label-width="120px">
+      <el-input v-model="formCallback.title" size="default" clearable></el-input>
+    </el-form-item>
+    <el-form-item label="排序" prop="sort" :rules="[{ required: true, message: '排序必须填写' }]" label-width="120px">
+      <el-input v-model.number="formCallback.sort" min="1" type="number" size="default" clearable></el-input>
+    </el-form-item>
+    <el-form-item label="封面图" prop="img_url" :rules="[{ required: true, message: '请上传封面图' }]">
+      <my-upload acceptType=".png,.jpg,.jpeg" :isCheckMM="true" :isMultiple="true" @fileRemove="fileRemove"
+        @fileSuccess="fileSuccess" :fileList="formCallback.fileList" action="/qiniu/upload/image"></my-upload>
+    </el-form-item>
+    <el-form-item label="链接短剧信息" prop="duanjus" :rules="[{ required: true, message: '选择链接短剧信息' }]">
+      <div>
+        <div class="flex flex-wrap mb-5" v-if="formCallback?.duanjus?.name">
+          <el-input v-model="formCallback.duanjus.name" disabled placeholder="短剧名称" style="width:200px;"
+            class="input-with-select">
+          </el-input>
+        </div>
+        <div>
+          <el-button type="primary" size="default" @click="chooseShort">选择短剧</el-button>
+        </div>
+      </div>
+    </el-form-item>
+    <el-form-item label="状态" prop="status" label-width="120px" :rules="[{ required: true, message: '选择状态' }]">
+      <el-switch v-model="formCallback.status" :active-value="1" :inactive-value="0"></el-switch>
+    </el-form-item>
+    <div class="flex justify-end">
+      <el-button type="primary" @click="submitForm(form)">{{
+        $t('system.confirm')
+      }}</el-button>
+    </div>
+  </el-form>
+  <Dialog v-model="videoVisible" title="选择短剧" width="90%" :alignCenter="true" destroy-on-close>
+    <videoList @confirm="confirm" :primary="formCallback.duanjus"></videoList>
+  </Dialog>
+</template>
+
+<script lang="ts" setup>
+import videoList from './videoList.vue';
+import { Close } from '@element-plus/icons-vue';
+import { FormInstance } from 'element-plus';
+import {
+  operationBannerEdit,
+  operationBannerAdd
+} from '@/api/pageLayout/viewpagerPage/index';
+import { useRouter, useRoute } from 'vue-router'
+import { optionsCommonParams } from '@/api/common/index'
+const props = defineProps({
+  primary: Object,
+});
+const router = useRouter()
+const route = useRoute()
+const emit = defineEmits(['close']);
+const loading = ref(false)
+const videoVisible = ref(false)
+const promotion = ref('')
+const form = ref()
+const formCallback = ref({})
+const miniprogramTypelist = ref([])
+const init = () => {
+  optionsCommonParams().then(res => {
+    console.log(res, 'optionsCommonParams');
+    miniprogramTypelist.value = res.data.miniprogramType
+  })
+}
+
+const fileSuccess = (e) => {
+  console.log(e);
+  formCallback.value.img_url = e;
+}
+const fileRemove = (e) => {
+  console.log(e);
+  formCallback.value.img_url = '';
+}
+const chooseShort = () => {
+  videoVisible.value = true
+}
+
+const confirm = (e) => {
+  formCallback.value.duanjus = e
+  videoVisible.value = false
+}
+// 提交回传配置
+const submitForm = (formEl: FormInstance | undefined) => {
+  console.log(formCallback.value, 'formCallbackformCallback');
+  if (!formEl) return;
+  loading.value = true;
+  formEl
+    .validate(valid => {
+      if (valid) {
+        const params = {
+          title: formCallback.value.title,
+          video_id: formCallback.value.duanjus.id,
+          miniprogram_type: formCallback.value.miniprogram_type,
+          sort: formCallback.value.sort,
+          img_url: formCallback.value.img_url,
+          status: formCallback.value.status,
+        }
+        if (props.primary.id) {
+          operationBannerEdit(formCallback.value.id, params).then(res => {
+            ElMessage.success(res.message)
+            emit('close')
+          })
+        } else {
+          operationBannerAdd(params).then(res => {
+            ElMessage.success(res.message)
+            emit('close')
+          })
+          loading.value = false;
+        }
+      } else {
+        loading.value = false;
+      }
+    })
+    .then(() => { });
+}
+
+if (props.primary.id) {
+  console.log(props.primary, 'props.primaryprops.primary');
+  formCallback.value = JSON.parse(JSON.stringify(props.primary))
+  formCallback.value.duanjus = props.primary.videoInfo
+  formCallback.value.fileList = [{ uid: props.primary.id, url: props.primary.img_url }]
+}
+onMounted(() => {
+  init()
+});
+</script>
+
+<style lang="scss" scoped>
+:deep(.input-with-select .el-input-group__prepend) {
+  background-color: #FFFFFF;
+  padding: 0;
+  border: 1px solid #dcdfe6;
+}
+</style>

+ 226 - 0
src/views/pageLayout/viewpagerPageManage/form/videoList.vue

@@ -0,0 +1,226 @@
+<template>
+  <div>
+    <el-card shadow="always" :body-style="{ padding: '20px' }" v-if="multipleSelection.name">
+      <template #header>
+        <div class="text-base font-bold card-header">
+          <span>所选短剧:</span>
+        </div>
+      </template>
+      <div class="flex flex-wrap items-start ml-6 choose-wrapper">
+        <el-form-item label="" class="font-bold">
+          <el-input v-model="multipleSelection.name" :disabled="true" placeholder="短剧名称" style="width:300px;"
+            class="input-with-select">
+          </el-input>
+        </el-form-item>
+      </div>
+    </el-card>
+    <Search :search="search" :reset="resetQuery">
+      <template v-slot:body>
+        <el-form-item label="短剧" prop="name">
+          <el-input v-model="query.videoName" placeholder="请输入短剧名称" clearable />
+        </el-form-item>
+        <el-form-item label="状态" prop="updateType">
+          <el-select v-model="query.updateType" filterable clearable placeholder="请选择状态">
+            <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="频道" prop="categoryId">
+          <el-cascader v-model="selectType" :options="cooperations" filterable clearable :change-on-select="true"
+            @change="handleCascaderChange" />
+        </el-form-item>
+        <el-form-item label="微信审核状态" prop="wechatPass">
+          <el-select v-model="query.wechatPass" disabled filterable clearable placeholder="请选择微信审核状态">
+            <el-option v-for="item in wxstatusOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+      </template>
+    </Search>
+    <div class="table-default">
+      <el-table :data="tableData" ref="multipleTableRef" height="380px" highlight-current-row class="mt-3"
+        v-loading="loading" row-key="id" @current-change="handleCurrentChange">
+        <el-table-column>
+          <template #default="scope">
+            <el-radio class="radio" v-model="selVal" :label="scope.row.id"><span></span></el-radio>
+          </template>
+        </el-table-column>
+        <el-table-column prop="id" label="剧号" />
+        <el-table-column label="封面" show-overflow-tooltip>
+          <template #default="scope">
+            <div class="flex flex-col items-start justify-center wrapper">
+              <el-popover placement="top" :width="200" trigger="click">
+                <template #reference>
+                  <el-image :src="scope.row.cover_image" class="cursor-pointer" style="width:48px;height:48px;"
+                    fit="contain" :lazy="true"></el-image>
+                </template>
+                <el-image :src="scope.row.cover_image" style="width:100%;" fit="contain"></el-image>
+              </el-popover>
+              <el-button type="primary" link size="default" @click="dowload(scope.row)">下载</el-button>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="短剧名称" show-overflow-tooltip min-width="250">
+          <template #default="scope">
+            <div class="wrapper">
+              <span class="text-lg font-bold text-blue-400 cursor-pointer content">
+                {{ scope.row.name }}
+              </span>
+              <span>
+                【 {{ scope.row.update_type_str }} 】
+              </span>
+            </div>
+            <div class="wrapper">
+              <span class="label">上架时间:</span>
+              <span class="content">{{ scope.row.shelf_at }}</span>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="total_episode_num" label="集数">
+          <template #default="scope">
+            <div class="flex wrapper">
+              <div v-if="scope.row.update_type == 1">
+                <span class="content">
+                  {{ scope.row.updated_episode_num }}
+                </span>
+                <span>/</span>
+              </div>
+              <div>
+                <span class="content">
+                  {{ scope.row.total_episode_num }}
+                </span>
+              </div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="category_str" label="频道" />
+        <el-table-column prop="shelf_type_str" label="上架状态" />
+        <el-table-column prop="charge_sequence" label="起始集" />
+        <el-table-column prop="charge_coin" label="定价">
+          <template #header>
+            <div class="flex items-center">
+              <span>定价</span>
+              <el-tooltip placement="top">
+                <template #content> 定价为所需看剧币<br />1元等于100币 </template>
+                <el-icon>
+                  <InfoFilled />
+                </el-icon>
+              </el-tooltip>
+            </div>
+          </template>
+          <template #default="scope">
+            <span>{{ scope.row.charge_coin }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <Paginate />
+    </div>
+    <div class="flex justify-end">
+      <el-button type="primary" @click="confirm">{{
+        $t('system.confirm')
+      }}</el-button>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { downloadImage } from '@/utils/index'
+import { InfoFilled } from '@element-plus/icons-vue';
+import { provide } from 'vue'
+import { useGetList } from '@/hook/curd/useGetList';
+import { useDestroy } from '@/hook/curd/useDestroy';
+import { useOpen } from '@/hook/curd/useOpen';
+import { videoStockVideoCategoryList, videoStockVideoList } from '@/api/video/index'
+const api = 'videoStock/video/list';
+const multipleTableRef = ref()
+const multipleSelection = ref({});
+const { data, query, search, reset, loading } = useGetList(api);
+const selectType = ref([])
+const statusOptions = ref([{ label: '连载中', value: '1' }, { label: '完结', value: '2' }]);
+const cooperations = ref([]);
+const emit = defineEmits(['confirm']);
+const wxstatusOptions = ref([{ label: '未通过', value: 0 }, { label: '已通过', value: 1 }]);
+const props = defineProps({
+  primary: Object,
+});
+const selVal = ref("")
+const rowSelectFlag = ref(false)// 禁止toggleRowSelection默认触发handleSelectionChange
+const handleCascaderChange = (val: any) => {
+  console.log(val, 'valval');
+  if (val) {
+    // 获取最后一级选项的值
+    const lastOptionValue = val[val.length - 1];
+    // 更新 selectedOptions 的值
+    query.value.categoryId = lastOptionValue;
+  } else {
+    delete query.value.categoryId
+  }
+}
+
+const resetQuery = () => {
+  query.value = Object.assign({ page: query.value.page, limit: query.value.limit, shelfType: 2 });
+  search()
+  selectType.value = []
+}
+const initType = () => {
+  videoStockVideoCategoryList().then(res => {
+    console.log(res);
+    cooperations.value = res.data
+  })
+}
+// 下载封面
+const dowload = (e: object) => {
+  downloadImage(e.cover_image, e.name)
+}
+
+const tableData = computed(() => data.value?.data);
+
+const handleCurrentChange = (val: any) => {
+  if (rowSelectFlag.value) return
+  multipleSelection.value = val;
+  selVal.value = val.id
+};
+const confirm = () => {
+  // 执行提交逻辑
+  emit('confirm', multipleSelection.value)
+}
+
+if (props.primary) {
+  // console.log(props.primary, 'props.primaryprops.primary');
+  multipleSelection.value = props.primary || {}
+  selVal.value = props.primary.id
+}
+
+onMounted(() => {
+  query.value = Object.assign({ page: query.value.page, limit: query.value.limit, shelfType: 2 });
+  initType()
+  search();
+});
+</script>
+
+<style scoped lang="scss">
+.choose-wrapper {
+  height: fit-content;
+  max-height: 150px;
+  overflow: auto;
+}
+
+.table-default {
+  .set-warpper {
+    height: 60px;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+  }
+
+  .wrapper {
+    margin: 8px;
+
+    .label {
+      margin-right: 6px;
+    }
+
+    .content {
+      font-size: 15px;
+    }
+  }
+}
+</style>

+ 117 - 0
src/views/pageLayout/viewpagerPageManage/index.vue

@@ -0,0 +1,117 @@
+<template>
+  <div class="table-default">
+    <div class="pt-5 pl-2" v-action="'operation.FirstPage.add'">
+      <el-button type="primary" size="default" @click="openForm(null)">新增</el-button>
+    </div>
+    <el-table :data="tableData" class="mt-3" v-loading="loading">
+      <el-table-column label="轮播图ID" prop="id"></el-table-column>
+      <el-table-column label="轮播图名称" prop="title">
+      </el-table-column>
+      <el-table-column label="封面" prop="img_url">
+        <template #default="scope">
+          <el-image :src="scope.row.img_url" fit="fill" :lazy="true"></el-image>
+        </template>
+      </el-table-column>
+      <el-table-column label="排序" prop="sort">
+      </el-table-column>
+      <el-table-column label="添加时间" prop="created_at">
+      </el-table-column>
+      <el-table-column label="小程序类型" prop="miniprogram_type_text">
+      </el-table-column>
+      <el-table-column label="状态" v-action="'operation.FirstPage.enableStatus'">
+        <template #default="scope">
+          <div>
+            <el-switch v-model="scope.row.status" @change="switchStatus(scope.row)" :active-value="1" :inactive-value="0">
+            </el-switch>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作">
+        <template #default="scope">
+          <el-button link type="primary" size="small" @click="handleEdit(scope.row)"
+            v-action="'operation.FirstPage.setConfig'">编辑</el-button>
+          <br />
+          <el-button link type="primary" size="small" @click="handleDel(scope.row)"
+            v-action="'operation.FirstPage.setConfig'">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <Paginate />
+  </div>
+  <Dialog v-model="addVisible" title="新增" width="30%" destroy-on-close>
+    <create @close="closeType('addVisible')" :primary="currentConfig"></create>
+  </Dialog>
+</template>
+
+<script lang="ts"  setup>
+import { InfoFilled } from '@element-plus/icons-vue';
+import { computed, onMounted, ref } from 'vue';
+import create from './form/create.vue';
+import config from './form/config.vue';
+import { useGetList } from '@/hook/curd/useGetList';
+import {
+  operationBannerEditStatus,
+  operationBannerDel
+} from '@/api/pageLayout/viewpagerPage/index';
+
+const api = 'operation/banner/list';
+
+const { data, query, search, reset, loading } = useGetList(api, true);
+const tableData = computed(() => data.value?.data);
+const addVisible = ref(false)
+const currentConfig = ref({})
+const configVisible = ref(false) //设置回传弹窗
+
+const closeType = (type: string) => {
+  switch (type) {
+    case 'configVisible':
+      configVisible.value = false
+      break;
+    case 'addVisible':
+      addVisible.value = false
+      break;
+  }
+  search()
+}
+
+const switchStatus = (data: object) => {
+  operationBannerEditStatus(data.id, { status: data.status }).then(res => {
+    ElMessage.success(res.message)
+  })
+  search()
+}
+
+const handleDel = (row: object) => {
+  ElMessageBox.confirm(
+    `确认删除 ${row.title} 吗?`,
+    '提示',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(() => {
+      operationBannerDel(row.id).then(res => {
+        ElMessage.success(res.message)
+        search()
+      })
+    })
+    .catch(() => {
+      search()
+    })
+}
+
+const openForm = (data: any) => {
+  currentConfig.value = {}
+  addVisible.value = true
+};
+const handleEdit = (data: object) => {
+  currentConfig.value = data
+  addVisible.value = true
+};
+onMounted(() => {
+  search();
+});
+</script>
+<style  lang='scss' scoped></style>

+ 28 - 2
src/views/payBack/juliangAccount/tabs/advertiserList/index.vue

@@ -28,10 +28,17 @@
           </div>
         </template>
       </el-table-column>
+      <el-table-column label="关联推广名称" width="260" prop="promotion_name">
+      </el-table-column>
+      <el-table-column label="关联推广ID" width="260" prop="promotion_id">
+      </el-table-column>
       <el-table-column label="操作">
         <template #default="scope">
-          <el-button link type="primary" size="default" @click="handleEdit(scope.$index, scope.row)"
+          <el-button link type="primary" size="small" @click="handleEdit(scope.$index, scope.row)"
             v-action="'callback.JuliangAccount.updateCallbackConfig'">回传配置</el-button>
+          <br />
+          <el-button link type="primary" size="small" @click="handleCancel(scope.row)"
+            v-action="'callback.JuliangAccount.unbindPromotion'">取消推广回传关联</el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -53,7 +60,7 @@ import { computed, onMounted, ref } from 'vue';
 import create from './form/create.vue';
 import paybackConfig from './form/paybackConfig.vue';
 import { useGetList } from '@/hook/curd/useGetList';
-import { callbackJuliangAccountTurnCallbackState } from '@/api/backConfig/index'
+import { callbackJuliangAccountTurnCallbackState, callbackJuliangAccountUnbindPromotion } from '@/api/backConfig/index'
 
 const api = 'callback/juliangAccount/list';
 
@@ -84,7 +91,26 @@ const switchStatus = (data: object) => {
     search()
   })
 }
+const handleCancel = (row: object) => {
+  ElMessageBox.confirm(
+    `解绑后此回传账户所有数据重新计算(包括比例/保护数),确定要取消 ${row.adv_account_name} 推广回传关联吗?`,
+    '提示',
+    {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: 'warning',
+    }
+  )
+    .then(() => {
+      callbackJuliangAccountUnbindPromotion({ id: row.id }).then(res => {
+        ElMessage.success(res.message)
+        search()
+      })
+    })
+    .catch(() => {
 
+    })
+}
 // 批量设置
 const mulSet = () => {
   if (multipleSelection.value.length <= 0) {

+ 11 - 6
src/views/payBack/juliangAccount/tabs/logList/index.vue

@@ -18,7 +18,7 @@
         <el-form-item label="广告计划ID" prop="adv_promotion_id">
           <el-input v-model="query.adv_promotion_id" placeholder="请输入广告计划ID" clearable />
         </el-form-item>
-        <el-form-item label="注册时间">
+        <el-form-item label="染色注册时间">
           <el-date-picker unlink-panels clearable @change="userTimeChange" format="YYYY/MM/DD" value-format="YYYY-MM-DD"
             v-model="query.userTime" type="daterange" :shortcuts="shortcuts" range-separator="To" start-placeholder="开始时间"
             end-placeholder="结束时间" />
@@ -46,7 +46,7 @@
         </el-table-column>
         <el-table-column prop="user_ranse_ip" label="注册IP" show-overflow-tooltip min-width="200px">
         </el-table-column>
-        <el-table-column prop="user_ranse_start_at" label="注册时间" show-overflow-tooltip min-width="200px" />
+        <el-table-column prop="user_ranse_start_at" label="染色注册时间" show-overflow-tooltip min-width="200px" />
         <el-table-column prop="order_created_at" label="充值时间" show-overflow-tooltip min-width="200px" />
         <el-table-column prop="order_price" label="充值金额" show-overflow-tooltip min-width="150px">
         </el-table-column>
@@ -126,6 +126,7 @@ import { useRouter, useRoute } from 'vue-router'
 import { InfoFilled } from '@element-plus/icons-vue';
 import { useGetList } from '@/hook/curd/useGetList';
 import { titleObj } from "./excelTitle"
+import Cache from '@/support/cache';
 import { callbackJuliangAccountList, callbackJuliangAccountLogCallbackAgain } from '@/api/backConfig/index'
 import moment from 'moment';
 const start_date = moment().format('YYYY-MM-DD')
@@ -191,7 +192,8 @@ const initAdNameOtion = (params?: object) => {
 }
 
 const resetQuery = () => {
-  reset()
+  query.value = Object.assign({ page: query.value.page, limit: query.value.limit, miniprogram_id: query.value.miniprogram_id });
+  search()
 }
 const openType = (type: string, data: object) => {
   current.value = data;
@@ -209,12 +211,15 @@ const openType = (type: string, data: object) => {
 const tableData = computed(() => data.value?.data);
 
 onMounted(() => {
-  query.value.userTime = [start_date, end_date];
+  // query.value.userTime = [start_date, end_date];
+  // query.value.user_ranse_start_at_begin_time = start_date
+  // query.value.user_ranse_start_at_end_time = end_date
   query.value.orderTime = [start_date, end_date];
-  query.value.user_ranse_start_at_begin_time = start_date
-  query.value.user_ranse_start_at_end_time = end_date
   query.value.order_created_at_begin_time = start_date
   query.value.order_created_at_end_time = end_date
+  if (JSON.parse(Cache.get('nav_data'))?.app.id) {
+    query.value.miniprogram_id = JSON.parse(Cache.get('nav_data'))?.app.id
+  }
   initAdNameOtion()
   search();
 });

+ 1 - 1
src/views/promotion/promotionList/form/backConfig.vue

@@ -49,7 +49,7 @@ const formDataForm = ref({ videos: [] })
 const callbackTypeList = ref([{ id: 1, value: 1, name: '巨量账户级回传' }])
 const emit = defineEmits(['close']);
 const init = (params?: object) => {
-  callbackJuliangAccountList({ limit: 30, ...params }).then(res => {
+  callbackJuliangAccountList({ limit: 666, unbind: 1, ...params }).then(res => {
     callbackConfigList.value = res.data
   })
 }

+ 30 - 4
src/views/promotion/promotionList/index.vue

@@ -101,6 +101,15 @@
               </el-table-column>
               <el-table-column prop="callback_type_str" label="回传类型" />
               <el-table-column prop="callback_config_id" label="回传配置ID" />
+              <el-table-column prop="status_str" label="状态">
+                <template #default="scope">
+                  <div class="wrapper">
+                    <span class="text-lg font-bold content">
+                      <el-text class="mx-1" :type="colorType(scope.row)">{{ scope.row.status_str }}</el-text>
+                    </span>
+                  </div>
+                </template>
+              </el-table-column>
               <el-table-column prop="callback_config_id" label="备注">
                 <template #default="scope">
                   <div class="wrapper">
@@ -186,6 +195,7 @@ import { InfoFilled } from '@element-plus/icons-vue';
 import Create from './form/create.vue';
 import backConfig from './form/backConfig.vue';
 import { useGetList } from '@/hook/curd/useGetList';
+import Cache from '@/support/cache';
 const activeName = ref(1)
 import { tuiguangPromotionDel } from '@/api/promotion/index'
 const api = 'tuiguang/promotion/list';
@@ -198,7 +208,15 @@ const backConfigVisible = ref(false)
 const backConfigData = ref({})
 const current = ref({})
 const titleBack = computed(() => activeName.value ? '更新回传配置' : '回传配置')
-
+const colorType = (data: object) => {
+  const type = data.status
+  switch (type) {
+    case 1:
+      return 'success'
+    case 0:
+      return 'danger'
+  }
+}
 const timeChange = (e) => {
   if (query.value.time) {
     const timeArr = toRaw(e);
@@ -241,7 +259,8 @@ const deletePromotion = (row: object) => {
 }
 
 const resetQuery = () => {
-  reset()
+  query.value = Object.assign({ page: query.value.page, limit: query.value.limit, miniprogram_id: query.value.miniprogram_id, is_config: query.value.is_config });
+  search()
 }
 const openType = (type: string, data: object) => {
   current.value = data;
@@ -269,9 +288,13 @@ const closeType = (type: string) => {
       ElMessageBox.alert('去复制推广链接', '配置完成', {
         draggable: true,
         confirmButtonText: '确认',
+        closeOnClickModal: true,
         callback: (action: any) => {
-          router.push({ path: '/promotion/promotionList', query: { tab: 1 } })
-          activeName.value = 1
+          console.log(action);
+          if (action == 'confirm') {
+            router.push({ path: '/promotion/promotionList', query: { tab: 1 } })
+            activeName.value = 1
+          }
         },
       })
       break;
@@ -282,6 +305,9 @@ const closeType = (type: string) => {
 onMounted(() => {
   activeName.value = Number(route.query.tab || 1)
   query.value.is_config = activeName.value
+  if (JSON.parse(Cache.get('nav_data'))?.app.id) {
+    query.value.miniprogram_id = JSON.parse(Cache.get('nav_data'))?.app.id
+  }
   search();
 });
 </script>

+ 1 - 1
src/views/settleManage/settlementCenter/tabs/rechargeRules/index.vue

@@ -2,7 +2,7 @@
   <div class="withdraw-popup-warn">
     (1):结算功能针对同一账号下的所有小程序<br />
     (2):分成金额=(充值总额-退款)*分成比例<br />
-    (3):申请提现后自动进入审核流程,审核需要1-5个工作日,节假日顺延,审核成功后自动打款<br />
+    (3):申请提现后自动进入审核流程,审核需要t+7个工作日,节假日顺延,审核成功后自动打款<br />
     (4):每日提现一次<br />
     (5):单笔提现金额不少于500<br />
   </div>

+ 1 - 2
src/views/settleManage/settlementCenter/tabs/rechargeSettle/form/create.vue

@@ -1,7 +1,6 @@
 <template>
   <div class="withdraw-popup-warn">
-    提现提示1:工作日14:30点前提现,审核通过之后下一工作日可到账;14:30之后提现将会在下一工作日审核<br />
-    提现提示2:充值收入提现后,请自行到当地税务部门纳税,本平台仅收取10%平台服务费,不承担代扣代缴义务。
+    提现提示:申请提现后自动进入审核流程,审核需要t+7个工作日,节假日顺延,审核成功后自动打款
   </div>
   <el-form :model="formData" label-width="120px" ref="ruleForm" :rules="rules" v-loading="loading" class="pr-4">
     <div class="flex flex-row justify-between">

+ 1 - 1
src/views/settleManage/settlementCenter/tabs/rechargeSettle/index.vue

@@ -23,7 +23,7 @@
             ¥{{ applyData.total_dakuan }}
           </div>
           <div class="text-base">
-            打款
+            累计打款
           </div>
         </el-col>
         <el-col :span="6" class="col">

+ 64 - 7
src/views/videoManage/detail.vue

@@ -1,7 +1,57 @@
 <template>
+  <el-card class="box-card">
+    <template #header>
+      <div class="card-header">
+        <span>简介</span>
+      </div>
+    </template>
+    <div class="flex">
+      <div>
+        <el-image class="mr-2 rounded-sm" :src="props.primary.cover_image" style="width:128px;height:160px;" fit="cover"
+          :lazy="true"></el-image>
+      </div>
+      <div>
+        <div class="flex items-center">
+          <span class="text-lg font-bold text-blue-400">
+            {{ props.primary.name }}
+          </span>
+          <div class="ml-3">
+            剧号:
+            <span class="font-bold">{{ props.primary.id }}</span>
+          </div>
+        </div>
+        <div class="flex items-center mt-2">
+          <span>
+            集数:
+          </span>
+          <div class="flex items-center font-bold">
+            <div v-if="props.primary.update_type == 1">
+              <span class="">
+                {{ props.primary.updated_episode_num }}
+              </span>
+              <span>/</span>
+            </div>
+            <div>
+              <span class="">
+                {{ props.primary.total_episode_num }}
+              </span>
+            </div>
+            <span>
+              【 {{ props.primary.update_type_str }} 】
+            </span>
+          </div>
+        </div>
+        <div class="mt-2">
+          简介:
+          <span class="font-bold note">{{ props.primary.note }}</span>
+        </div>
+      </div>
+    </div>
+  </el-card>
+
   <div class="flex flex-col justify-between w-full sm:flex-row" style="width:100%;">
     <div class="table-default" style="width:100%;">
-      <el-table :data="tableData" class="w-full mt-3" style="width:100%;">
+      <el-table :data="tableData" class="w-full mt-3" v-loading="loading" style="width:100%;">
         <el-table-column prop="series_name" label="章节名称" />
         <el-table-column prop="is_charge" label="是否付费">
           <template #default="scope">
@@ -21,12 +71,12 @@
       <Paginate />
     </div>
   </div>
-  <Dialog v-model="playVisible" title="视频" destroy-on-close height="100%">
+  <el-dialog draggable v-model="playVisible" align-center append-to-body width="500px" center :show-close="false"
+    style="background: none;box-shadow: none;" destroy-on-close>
     <video id="my-player" class="video-js" controls autoplay preload="auto" ref="myVideo">
       <source :src="current.public_video_url" type="video/mp4">
     </video>
-  </Dialog>
-
+  </el-dialog>
   <Dialog v-model="linkVisible" title="创建推广链接" destroy-on-close>
     <el-form :model="formDataForm" label-width="120px" ref="form" v-loading="loading" class="pr-4">
       <el-form-item label="推广名称" prop="name" :rules="[{ required: true, message: '推广名称必须填写' }]">
@@ -71,7 +121,7 @@ const { open, close, title, visible, id } = useOpen();
 if (props.primary) {
   query.value.video_id = props.primary.id
   formDataForm.value.video_id = props.primary.id
-  formDataForm.value.miniprogram_id = JSON.parse(Cache.get('nav_data'))?.advertiser?.miniProgramIds
+  formDataForm.value.miniprogram_id = JSON.parse(Cache.get('nav_data'))?.app?.id
 }
 const tableData = computed(() => data.value?.data);
 const play = (e: object) => {
@@ -112,8 +162,15 @@ onMounted(() => {
 <style lang="scss" scoped>
 //播放器样式
 video#my-player.video-js {
-  width: 80%;
-  height: 500px;
+  width: 500px;
+  height: auto;
   background-color: #000;
 }
+
+.note {
+  font-size: 16px;
+  width: fit-content;
+  word-wrap: break-word;
+  word-break: break-all;
+}
 </style>

+ 6 - 1
src/views/videoManage/form/create.vue

@@ -56,9 +56,12 @@
           </el-radio-group>
         </el-form-item>
         <el-form-item label="封面" prop="cover_image">
-          <my-upload acceptType=".png,.jpeg" :isMultiple="true" @fileRemove="fileRemove" @fileSuccess="fileSuccess"
+          <my-upload acceptType=".png,.jpg,.jpeg" :isMultiple="true" @fileRemove="fileRemove" @fileSuccess="fileSuccess"
             :fileList="formData.fileList" action="/qiniu/upload/image"></my-upload>
         </el-form-item>
+        <el-form-item label="简介" prop="note">
+          <el-input v-model="formData.note" placeholder="请输入简介" :rows="3" autosize type="textarea" />
+        </el-form-item>
       </div>
     </div>
     <div class="flex justify-end">
@@ -82,6 +85,7 @@ const categoryList = ref([])
 const formData = ref({ status: 2, miniProgramIds: [] })
 const rules = reactive({
   name: [{ required: true, message: '请输入短剧名称', trigger: 'blur' }],
+  note: [{ required: true, message: '请输入简介', trigger: 'blur' }],
   total_episode_num: [
     {
       required: true,
@@ -198,6 +202,7 @@ const submitForm = (formEl: FormInstance | undefined) => {
           "cp_name": formData.value.cp_name,
           "cp_share_type": formData.value.cp_share_type,
           "cover_image": formData.value.cover_image,
+          "note": formData.value.note
         };
         if (props.primary) {
           api = videoStockVideoUpdate

src/views/videoManage/form/subscribeSet.vue → src/views/videoManage/videoLibraryList/form/subscribeSet.vue


src/views/videoManage/form/uploadVideo.vue → src/views/videoManage/videoLibraryList/form/uploadVideo.vue


+ 1 - 1
src/views/videoManage/form/videoDL.vue

@@ -31,7 +31,7 @@ import { ref } from 'vue'
 import { videoStockEpisodeList } from '@/api/video/index'
 const myVideo = ref()
 const videoChoose = ref([])
-const changeForm = ref({ page: 1, limit: 5 })
+const changeForm = ref({ page: 1, limit: 100 })
 const props = defineProps({
   primary: String | Number,
 });

+ 50 - 16
src/views/videoManage/index.vue

@@ -6,7 +6,7 @@
           <el-input v-model="query.videoName" placeholder="请输入短剧名称" clearable />
         </el-form-item>
         <el-form-item label="状态" prop="updateType">
-          <el-select v-model="query.updateType" filterable clearable remote placeholder="请选择状态">
+          <el-select v-model="query.updateType" filterable clearable placeholder="请选择状态">
             <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
           </el-select>
         </el-form-item>
@@ -14,6 +14,11 @@
           <el-cascader v-model="selectType" :options="cooperations" filterable clearable :change-on-select="true"
             @change="handleCascaderChange" />
         </el-form-item>
+        <el-form-item label="微信审核状态" prop="wechatPass">
+          <el-select v-model="query.wechatPass" filterable clearable placeholder="请选择微信审核状态">
+            <el-option v-for="item in wxstatusOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
       </template>
     </Search>
     <div class="table-default">
@@ -38,20 +43,44 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="短剧名称" show-overflow-tooltip min-width="250">
+        <el-table-column label="短剧名称" min-width="250">
           <template #default="scope">
-            <div class="wrapper">
-              <span class="text-lg font-bold text-blue-400 cursor-pointer content"
-                @click="openType('videoDetailVisible', scope.row)">
-                {{ scope.row.name }}
-              </span>
-              <span>
-                【 {{ scope.row.update_type_str }} 】
-              </span>
-            </div>
-            <div class="wrapper">
-              <span class="label">上架时间:</span>
-              <span class="content">{{ scope.row.shelf_at }}</span>
+            <el-tooltip placement="top" v-if="scope.row.wechat_pass">
+              <template #content> 当前短剧已通过微信审核<br /> </template>
+              <div>
+                <div class="wrapper">
+                  <span class="text-lg font-bold text-blue-400 cursor-pointer content"
+                    @click="openType('videoDetailVisible', scope.row)">
+                    {{ scope.row.name }}
+                  </span>
+                  <span>
+                    【 {{ scope.row.update_type_str }} 】
+                  </span>
+                </div>
+                <div class="wrapper">
+                  <span class="label">上架时间:</span>
+                  <span class="content">{{ scope.row.shelf_at }}</span>
+                </div>
+                <div class="ml-2">
+                  <el-image style="width: 20px; height: 20px" class="mt-1" :src="scope.row.wechat_pass_img"
+                    fit="contain" />
+                </div>
+              </div>
+            </el-tooltip>
+            <div v-else>
+              <div class="wrapper">
+                <span class="text-lg font-bold text-blue-400 cursor-pointer content"
+                  @click="openType('videoDetailVisible', scope.row)">
+                  {{ scope.row.name }}
+                </span>
+                <span>
+                  【 {{ scope.row.update_type_str }} 】
+                </span>
+              </div>
+              <div class="wrapper">
+                <span class="label">上架时间:</span>
+                <span class="content">{{ scope.row.shelf_at }}</span>
+              </div>
             </div>
           </template>
         </el-table-column>
@@ -122,9 +151,13 @@
     <Dialog v-model="uploadVisible" width="50%" title="上传视频" destroy-on-close>
       <uploadVideo @close="closeType('uploadVisible')" :primary="uploadData"></uploadVideo>
     </Dialog>
-    <Dialog v-action="'video.video.list'" v-model="videoDetailVisible" width="50%" title="短剧详情" destroy-on-close>
+    <el-dialog draggable v-action="'video.video.list'" align-center append-to-body v-model="videoDetailVisible" width="50%" title="短剧详情"
+      destroy-on-close>
       <videoDetail @close="closeType('videoDetailVisible')" :primary="videoDetailData"></videoDetail>
-    </Dialog>
+    </el-dialog>
+    <!-- <Dialog v-action="'video.video.list'" v-model="videoDetailVisible" width="50%" title="短剧详情" destroy-on-close>
+      <videoDetail @close="closeType('videoDetailVisible')" :primary="videoDetailData"></videoDetail>
+    </Dialog> -->
   </div>
 </template>
 
@@ -164,6 +197,7 @@ const videoDetailData = ref({})
 const current = ref({})
 const selectType = ref([])
 const statusOptions = ref([{ label: '连载中', value: '1' }, { label: '完结', value: '2' }]);
+const wxstatusOptions = ref([{ label: '未通过', value: 0 }, { label: '已通过', value: 1 }]);
 const cooperations = ref([]);
 const rolesIdentify = ref([]);
 const isShowCreatePromotion = computed(() => JSON.parse(Cache.get('nav_data'))?.advertiser?.miniProgramIds && JSON.parse(Cache.get('nav_data'))?.app)

+ 32 - 0
src/views/videoManage/wechatAudit/index.vue

@@ -0,0 +1,32 @@
+<template>
+  <div>
+    <el-card shadow="always" :body-style="{ padding: '20px' }">
+      <el-tabs v-model="activeName" class="demo-tabs" @tab-change="handChange">
+        <el-tab-pane label="微信提审" name="wechatAudit">
+          <wechatAuditList v-if="activeName == 'wechatAudit'"></wechatAuditList>
+        </el-tab-pane>
+        <el-tab-pane label="审核状态" name="wechatAuditStatus">
+          <wechatAuditStatus v-if="activeName == 'wechatAuditStatus'"></wechatAuditStatus>
+        </el-tab-pane>
+      </el-tabs>
+    </el-card>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { useRouter, useRoute } from 'vue-router'
+import type { TabsPaneContext } from 'element-plus'
+import wechatAuditList from "./tabs/wechatAuditList/index.vue"
+import wechatAuditStatus from "./tabs/wechatAuditStatus/index.vue"
+const router = useRouter()
+const route = useRoute()
+const handChange = (tab: TabsPaneContext, event: Event) => {
+  activeName.value = tab
+}
+const activeName = ref('wechatAudit')
+onMounted(() => {
+  activeName.value = route.query.tab || 'wechatAudit'
+});
+</script>
+
+<style scoped lang="scss"></style>

+ 58 - 1
src/views/videoManage/detail.vue

@@ -1,4 +1,54 @@
 <template>
+  <el-card class="box-card">
+    <template #header>
+      <div class="card-header">
+        <span>简介</span>
+      </div>
+    </template>
+    <div class="flex">
+      <div>
+        <el-image class="mr-2 rounded-sm" :src="props.primary.cover_image" style="width:128px;height:160px;" fit="cover"
+          :lazy="true"></el-image>
+      </div>
+      <div>
+        <div class="flex items-center">
+          <span class="text-lg font-bold text-blue-400">
+            {{ props.primary.name }}
+          </span>
+          <div class="ml-3">
+            剧号:
+            <span class="font-bold">{{ props.primary.id }}</span>
+          </div>
+        </div>
+        <div class="flex items-center mt-2">
+          <span>
+            集数:
+          </span>
+          <div class="flex items-center font-bold">
+            <div v-if="props.primary.update_type == 1">
+              <span class="">
+                {{ props.primary.updated_episode_num }}
+              </span>
+              <span>/</span>
+            </div>
+            <div>
+              <span class="">
+                {{ props.primary.total_episode_num }}
+              </span>
+            </div>
+            <span>
+              【 {{ props.primary.update_type_str }} 】
+            </span>
+          </div>
+        </div>
+        <div class="mt-2">
+          简介:
+          <span class="font-bold note">{{ props.primary.note }}</span>
+        </div>
+      </div>
+    </div>
+  </el-card>
+
   <div class="flex flex-col justify-between w-full sm:flex-row" style="width:100%;">
     <div class="table-default" style="width:100%;">
       <el-table :data="tableData" class="w-full mt-3" style="width:100%;">
@@ -71,7 +121,7 @@ const { open, close, title, visible, id } = useOpen();
 if (props.primary) {
   query.value.video_id = props.primary.id
   formDataForm.value.video_id = props.primary.id
-  formDataForm.value.miniprogram_id = JSON.parse(Cache.get('nav_data'))?.advertiser?.miniProgramIds
+  formDataForm.value.miniprogram_id = JSON.parse(Cache.get('nav_data'))?.app?.id
 }
 const tableData = computed(() => data.value?.data);
 const play = (e: object) => {
@@ -116,4 +166,11 @@ video#my-player.video-js {
   height: 500px;
   background-color: #000;
 }
+
+.note {
+  font-size: 16px;
+  width: fit-content;
+  word-wrap: break-word;
+  word-break: break-all;
+}
 </style>

+ 6 - 1
src/views/videoManage/form/create.vue

@@ -56,9 +56,12 @@
           </el-radio-group>
         </el-form-item>
         <el-form-item label="封面" prop="cover_image">
-          <my-upload acceptType=".png,.jpeg" :isMultiple="true" @fileRemove="fileRemove" @fileSuccess="fileSuccess"
+          <my-upload acceptType=".png,.jpg,.jpeg" :isMultiple="true" @fileRemove="fileRemove" @fileSuccess="fileSuccess"
             :fileList="formData.fileList" action="/qiniu/upload/image"></my-upload>
         </el-form-item>
+        <el-form-item label="简介" prop="note">
+          <el-input v-model="formData.note" placeholder="请输入简介" :rows="3" autosize type="textarea" />
+        </el-form-item>
       </div>
     </div>
     <div class="flex justify-end">
@@ -82,6 +85,7 @@ const categoryList = ref([])
 const formData = ref({ status: 2, miniProgramIds: [] })
 const rules = reactive({
   name: [{ required: true, message: '请输入短剧名称', trigger: 'blur' }],
+  note: [{ required: true, message: '请输入简介', trigger: 'blur' }],
   total_episode_num: [
     {
       required: true,
@@ -198,6 +202,7 @@ const submitForm = (formEl: FormInstance | undefined) => {
           "cp_name": formData.value.cp_name,
           "cp_share_type": formData.value.cp_share_type,
           "cover_image": formData.value.cover_image,
+          "note": formData.value.note
         };
         if (props.primary) {
           api = videoStockVideoUpdate

src/views/videoManage/form/subscribeSet.vue → src/views/videoManage/wechatAudit/tabs/wechatAuditList/form/subscribeSet.vue


src/views/videoManage/form/uploadVideo.vue → src/views/videoManage/wechatAudit/tabs/wechatAuditList/form/uploadVideo.vue


+ 183 - 0
src/views/videoManage/wechatAudit/tabs/wechatAuditList/form/videoSync.vue

@@ -0,0 +1,183 @@
+<template>
+  <el-alert title="注:如需批量下载,则多选目标集数,点击下载按钮即可" type="warning" show-icon :closable="false" />
+  <div class="wrapper">
+    <!-- :poster="videoImg"视频封面 -->
+    <video id="my-player" style="width:500px;" :key="current.public_video_url" class="video-js" controls autoplay
+      ref="myVideo">
+      <source :src="current.public_video_url" type="video/mp4">
+    </video>
+    <!-- 视频名称列表布局 -->
+    <div class="video-wrapper">
+      <div class="flex items-center justify-between h-10">
+        <div class="w-full text-base font-medium">剧名: <span class="ml-2 text-lg font-bold text-dark-600">{{
+          props.primary.name }}</span> <span v-if="current.series_name">(当前播放{{ current.series_name }})</span></div>
+        <el-button type="primary" size="default" @click="syncVideoChange">同步视频</el-button>
+        <el-popover placement="top" :width="400" trigger="click">
+          <template #reference>
+            <el-button style="margin-right: 16px" @click="viewStatusChange">查看状态</el-button>
+          </template>
+          <div class="flex items-center">
+            <div class="dot-success"></div>
+            <span>同步成功</span>
+          </div>
+          <div class="flex items-center">
+            <div class="dot-lose"></div>
+            <span>同步失败</span>
+          </div>
+          <div class="flex items-center">
+            <div class="dot-ing"></div>
+            <span>同步中</span>
+          </div>
+        </el-popover>
+      </div>
+      <div>
+        <el-checkbox v-model="checkAll" border :indeterminate="isIndeterminate" @change="handleCheckAllChange">
+          全选
+        </el-checkbox>
+      </div>
+      <mytabs :meta="meta" v-if="meta.total" @change="handChange">
+        <template v-slot:content>
+          <el-checkbox-group v-model="videoChoose" size="large" class="flex items-center" v-if="viewStatus">
+            <el-checkbox border class="video-item" @change="videoShow(source)" v-for="(source, index) in videoUrlList"
+              :key="index" :label="source" :style="{ backgroundColor: colorType(source) }">
+              {{ source.series_sequence }}
+            </el-checkbox>
+          </el-checkbox-group>
+          <el-checkbox-group v-model="videoChoose" size="large" class="flex items-center" v-else>
+            <el-checkbox border class="video-item" @change="videoShow(source)" v-for="(source, index) in videoUrlList"
+              :key="index" :label="source">
+              {{ source.series_sequence }}
+            </el-checkbox>
+          </el-checkbox-group>
+        </template>
+      </mytabs>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+import { ref } from 'vue'
+import { videoStockEpisodeList } from '@/api/video/index'
+const myVideo = ref()
+const videoChoose = ref([])
+const changeForm = ref({ page: 1, limit: 100 })
+const props = defineProps({
+  primary: String | Number,
+});
+const checkAll = ref(false)
+const videoUrlList = ref([])
+const viewStatus = ref(false)
+if (props.primary) {
+
+}
+const meta = ref({})
+const colorType = (data: object) => {
+  console.log(data, 'datacolorTypecolorType');
+  const type = data.series_sequence
+  switch (type) {
+    case 1:
+      return '#f18e00'
+    case 2:
+      return '#28c445'
+    case 3:
+      return '#ed0b0b'
+  }
+}
+const current = ref({})
+const videoChooseUrls = ref([])
+// 查看状态
+const viewStatusChange = () => {
+  viewStatus.value = true
+}
+// 同步视频
+const syncVideoChange = () => {
+  viewStatus.value = false
+}
+const initVideoList = (params: object) => {
+  videoStockEpisodeList({ video_id: props.primary.id, ...params }).then(res => {
+    videoUrlList.value = res.data;
+    meta.value = { limit: res.limit, total: res.total }
+  })
+}
+
+const handleCheckAllChange = (val: boolean) => {
+  videoChoose.value = val ? videoUrlList.value : []
+  // isIndeterminate.value = false
+}
+
+const handChange = (e) => {
+  console.log(e, 'handChange');
+  changeForm.value.page = Number(e.page);
+  initVideoList(changeForm.value);
+}
+const videoShow = (source: object) => {
+  console.log(source);
+  current.value = videoChoose.value.find(el => el.public_video_url == source.public_video_url) ?? {}
+  videoChooseUrls.value = videoChoose.value
+  console.log(videoChooseUrls.value, 'videoChooseUrls.value');
+}
+
+onMounted(() => {
+  initVideoList(changeForm.value)
+})
+</script>
+
+
+<style lang="scss" scoped>
+.dot-success,
+.dot-lose,
+.dot-ing {
+  width: 12px;
+  height: 12px;
+  border-radius: 50%;
+  margin-right: 6px;
+}
+
+.dot-success {
+  background-color: #28c445;
+}
+
+.dot-lose {
+  background-color: #ed0b0b;
+}
+
+.dot-ing {
+  background-color: #f18e00;
+}
+
+.wrapper {
+  padding-left: 40px;
+  margin-top: 30px;
+  display: flex;
+  width: 100%;
+}
+
+//播放器样式
+video#my-player.video-js {
+  flex: 1;
+  min-width: 300px;
+  height: 580px;
+  background-color: #000;
+}
+
+.video-wrapper {
+  flex: 2;
+  min-width: 600px;
+  margin-left: 40px;
+
+  .video-item {
+    margin: 6px;
+  }
+
+  :deep(.el-checkbox-group .el-checkbox.is-checked) {
+    background-color: #2566ff;
+  }
+
+  :deep(.el-checkbox.is-bordered.is-checked) {
+    background-color: #2566ff;
+  }
+
+  :deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
+    color: #fff
+  }
+}
+</style>

+ 58 - 75
src/views/videoManage/index.vue

@@ -6,7 +6,7 @@
           <el-input v-model="query.videoName" placeholder="请输入短剧名称" clearable />
         </el-form-item>
         <el-form-item label="状态" prop="updateType">
-          <el-select v-model="query.updateType" filterable clearable remote placeholder="请选择状态">
+          <el-select v-model="query.updateType" filterable clearable placeholder="请选择状态">
             <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
           </el-select>
         </el-form-item>
@@ -14,17 +14,35 @@
           <el-cascader v-model="selectType" :options="cooperations" filterable clearable :change-on-select="true"
             @change="handleCascaderChange" />
         </el-form-item>
+        <el-form-item label="微信审核状态" prop="wechatPass">
+          <el-select v-model="query.wechatPass" filterable clearable placeholder="请选择微信审核状态">
+            <el-option v-for="item in wxstatusOptions" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
       </template>
     </Search>
     <div class="table-default">
-      <!-- <div class="set-warpper">
-        <el-button type="primary" @click="mulSet" size="default" v-action="'video.video.mulSet'">批量操作</el-button>
-      </div> -->
+      <div class="set-warpper">
+        <el-button type="primary" @click="mulSet" size="default" v-action="'video.video.mulSet'">批量提审</el-button>
+      </div>
       <Operate :show="open" v-action="'video.video.add'" />
       <el-table :data="tableData" class="mt-3" v-loading="loading" @selection-change="handleSelectionChange">
         <el-table-column type="selection" />
         <el-table-column prop="id" label="剧号" />
-        <el-table-column label="封面" show-overflow-tooltip>
+        <el-table-column label="剧目名称" prop="name" min-width="150">
+        </el-table-column>
+        <el-table-column label="制作方名称" prop="name" min-width="150">
+        </el-table-column>
+        <el-table-column prop="note" label="剧目简介" min-width="250">
+          <template #default="scope">
+            <span class="note-content">
+              {{ scope.row.note }}
+            </span>
+          </template>
+        </el-table-column>
+        <el-table-column prop="category_str" label="编剧姓名" />
+        <el-table-column prop="category_str" label="总集数" />
+        <el-table-column label="剧目海报" show-overflow-tooltip>
           <template #default="scope">
             <div class="flex flex-col items-start justify-center wrapper">
               <el-popover placement="top" :width="200" trigger="click">
@@ -38,58 +56,33 @@
             </div>
           </template>
         </el-table-column>
-        <el-table-column label="短剧名称" show-overflow-tooltip min-width="250">
+        <el-table-column prop="shelf_type_str" label="《广播电视节目制作许可证》" min-width="250">
           <template #default="scope">
-            <div class="wrapper">
-              <span class="text-lg font-bold text-blue-400 cursor-pointer content"
-                @click="openType('videoDetailVisible', scope.row)">
-                {{ scope.row.name }}
-              </span>
-              <span>
-                【 {{ scope.row.update_type_str }} 】
-              </span>
-            </div>
-            <div class="wrapper">
-              <span class="label">上架时间:</span>
-              <span class="content">{{ scope.row.shelf_at }}</span>
+            <div class="flex flex-col items-start justify-center wrapper">
+              <el-popover placement="top" :width="200" trigger="hover">
+                <template #reference>
+                  <el-image :src="scope.row.cover_image" class="cursor-pointer" style="width:48px;height:48px;"
+                    fit="contain" :lazy="true"></el-image>
+                </template>
+                <el-image :src="scope.row.cover_image" style="width:100%;" fit="contain"></el-image>
+              </el-popover>
+              <el-button type="primary" link size="default" @click="dowload(scope.row)">下载</el-button>
             </div>
           </template>
         </el-table-column>
-        <el-table-column prop="total_episode_num" label="集数">
+        <el-table-column prop="shelf_type_str" label="授权材料" min-width="250">
           <template #default="scope">
-            <div class="flex wrapper">
-              <div v-if="scope.row.update_type == 1">
-                <span class="content">
-                  {{ scope.row.updated_episode_num }}
-                </span>
-                <span>/</span>
-              </div>
-              <div>
-                <span class="content">
-                  {{ scope.row.total_episode_num }}
-                </span>
-              </div>
-            </div>
-          </template>
-        </el-table-column>
-        <el-table-column prop="category_str" label="频道" />
-        <el-table-column prop="shelf_type_str" label="上架状态" v-if="!rolesIdentify.includes('company')" />
-        <el-table-column prop="charge_sequence" label="起始集" v-if="!rolesIdentify.includes('company')" />
-        <el-table-column prop="charge_coin" label="定价" v-if="!rolesIdentify.includes('company')">
-          <template #header>
-            <div class="flex items-center">
-              <span>定价</span>
-              <el-tooltip placement="top">
-                <template #content> 定价为所需看剧币<br />1元等于100币 </template>
-                <el-icon>
-                  <InfoFilled />
-                </el-icon>
-              </el-tooltip>
+            <div class="flex flex-col items-start justify-center wrapper">
+              <el-popover placement="top" :width="200" trigger="click">
+                <template #reference>
+                  <el-image :src="scope.row.cover_image" class="cursor-pointer" style="width:48px;height:48px;"
+                    fit="contain" :lazy="true"></el-image>
+                </template>
+                <el-image :src="scope.row.cover_image" style="width:100%;" fit="contain"></el-image>
+              </el-popover>
+              <el-button type="primary" link size="default" @click="dowload(scope.row)">下载</el-button>
             </div>
           </template>
-          <template #default="scope">
-            <span>{{ scope.row.charge_coin }}</span>
-          </template>
         </el-table-column>
         <el-table-column label="操作">
           <template #default="scope">
@@ -99,11 +92,9 @@
               v-action="'video.video.update'">编辑</el-button><br />
             <el-button @click="openType('takeVisible', scope.row)" link type="primary" size="small"
               v-action="'video.video.setChargeConfig'">订阅设置</el-button><br />
-            <el-button link type="primary" size="small" @click="openType('videoDLVisible', scope.row)"
-              v-action="'video.episode.downloadList'">视频下载</el-button>
+            <el-button link type="primary" size="small" @click="openType('videoSyncVisible', scope.row)"
+              v-action="'video.episode.downloadList'">同步视频</el-button>
             <br />
-            <el-button link type="primary" size="small" v-if="isShowCreatePromotion" v-action="'tuiguang.Promotion.add'"
-              @click="openType('videoDetailVisible', scope.row)">生成推广链接</el-button>
           </template>
         </el-table-column>
       </el-table>
@@ -113,8 +104,8 @@
     <Dialog v-model="visible" :title="title" destroy-on-close>
       <Create @close="close(search)" :primary="id" :eidapi="addApi" :addapi="addApi" :ismulSet="ismulSet" />
     </Dialog>
-    <Dialog v-model="videoDLVisible" width="80%" title="视频下载" destroy-on-close>
-      <videoDL @close="closeType('videoDLVisible')" :primary="depotsData"></videoDL>
+    <Dialog v-model="videoSyncVisible" width="80%" title="视频下载" destroy-on-close>
+      <videoSync @close="closeType('videoSyncVisible')" :primary="depotsData"></videoSync>
     </Dialog>
     <Dialog v-model="takeVisible" width="50%" title="订阅设置" destroy-on-close>
       <subscribeSet @close="closeType('takeVisible')" :primary="takeData"></subscribeSet>
@@ -122,9 +113,6 @@
     <Dialog v-model="uploadVisible" width="50%" title="上传视频" destroy-on-close>
       <uploadVideo @close="closeType('uploadVisible')" :primary="uploadData"></uploadVideo>
     </Dialog>
-    <Dialog v-action="'video.video.list'" v-model="videoDetailVisible" width="50%" title="短剧详情" destroy-on-close>
-      <videoDetail @close="closeType('videoDetailVisible')" :primary="videoDetailData"></videoDetail>
-    </Dialog>
   </div>
 </template>
 
@@ -133,8 +121,7 @@ import { downloadImage } from '@/utils/index'
 import { InfoFilled } from '@element-plus/icons-vue';
 import { provide } from 'vue'
 import Create from './form/create.vue';
-import videoDL from './form/videoDL.vue';
-import videoDetail from './detail.vue';
+import videoSync from './form/videoSync.vue';
 import subscribeSet from './form/subscribeSet.vue';
 import uploadVideo from './form/uploadVideo.vue';
 import { useGetList } from '@/hook/curd/useGetList';
@@ -153,17 +140,16 @@ const multipleSelection = ref([]);
 const { data, query, search, reset, loading } = useGetList(api);
 const { deleted } = useDestroy();
 const uploadBooksVisible = ref(false)
-const videoDLVisible = ref(false)
+const videoSyncVisible = ref(false)
 const depotsData = ref({})
 const uploadVisible = ref(false)
 const uploadData = ref({})
 const takeVisible = ref(false)
 const takeData = ref({})
-const videoDetailVisible = ref(false)
-const videoDetailData = ref({})
 const current = ref({})
 const selectType = ref([])
 const statusOptions = ref([{ label: '连载中', value: '1' }, { label: '完结', value: '2' }]);
+const wxstatusOptions = ref([{ label: '未通过', value: 0 }, { label: '已通过', value: 1 }]);
 const cooperations = ref([]);
 const rolesIdentify = ref([]);
 const isShowCreatePromotion = computed(() => JSON.parse(Cache.get('nav_data'))?.advertiser?.miniProgramIds && JSON.parse(Cache.get('nav_data'))?.app)
@@ -191,8 +177,8 @@ const resetQuery = () => {
 const openType = (type: string, data: object) => {
   current.value = data;
   switch (type) {
-    case 'videoDLVisible':
-      videoDLVisible.value = true
+    case 'videoSyncVisible':
+      videoSyncVisible.value = true
       depotsData.value = data
       break;
     case 'takeVisible':
@@ -203,10 +189,6 @@ const openType = (type: string, data: object) => {
       uploadVisible.value = true
       uploadData.value = data
       break;
-    case 'videoDetailVisible':
-      videoDetailVisible.value = true
-      videoDetailData.value = data
-      break;
   }
 }
 provide('video', current)
@@ -232,8 +214,8 @@ const handleSelectionChange = (val: []) => {
 const closeType = (type) => {
   console.log(type, 'typetype');
   switch (type) {
-    case 'videoDLVisible':
-      videoDLVisible.value = false
+    case 'videoSyncVisible':
+      videoSyncVisible.value = false
       break;
     case 'takeVisible':
       takeVisible.value = false
@@ -241,9 +223,6 @@ const closeType = (type) => {
     case 'uploadVisible':
       uploadVisible.value = false
       break;
-    case 'videoDetailVisible':
-      videoDetailVisible.value = false
-      break;
   }
   search()
 }
@@ -294,6 +273,10 @@ onMounted(() => {
 </script>
 
 <style scoped lang="scss">
+.note-content {
+  @include text-ellipsis(3);
+}
+
 .table-default {
   .set-warpper {
     height: 60px;

+ 86 - 0
src/views/videoManage/wechatAudit/tabs/wechatAuditStatus/excelTitle.ts

@@ -0,0 +1,86 @@
+// 导出中文/字段
+export const titleObj = {
+  0: {
+    商户名称: 'company_name',
+    商户ID: 'puser_id',
+    优化师: 'username',
+    小程序: 'xcx_name',
+    用户ID: 'uid',
+    订单号: 'trade_no',
+    订单时间: 'order_created_at',
+    染色注册时间: 'ranse_created_at',
+    申退金额: 'refund_price',
+    充值金额: 'order_price',
+    推广名称: 'promotion_name',
+    档位类型: 'tip_text',
+    支付方式: 'pay_name',
+    平台审核: 'pt_verify_status_text',
+    平台审核备注: 'pt_verify_remark',
+    商户审核: 'sh_verify_status_text',
+    商户审核备注: 'sh_verify_remark'
+  },
+  1: {
+    商户名称: 'company_name',
+    商户ID: 'puser_id',
+    优化师: 'username',
+    小程序: 'xcx_name',
+    用户ID: 'uid',
+    订单号: 'trade_no',
+    订单时间: 'order_created_at',
+    染色注册时间: 'ranse_created_at',
+    申退金额: 'refund_price',
+    充值金额: 'order_price',
+    推广名称: 'promotion_name',
+    档位类型: 'tip_text',
+    支付方式: 'pay_name',
+    退款时间: 'pay_at',
+    退款单号: 'refund_no',
+    订单状态: 'status_text'
+  }
+};
+
+export const titlePtObj = {
+	0: {
+	  商户名称: 'company_name',
+	  商户ID: 'puser_id',
+	  优化师: 'username',
+	  小程序: 'xcx_name',
+	  用户ID: 'uid',
+	  订单号: 'trade_no',
+	  订单时间: 'order_created_at',
+	  染色注册时间: 'ranse_created_at',
+	  申退金额: 'refund_price',
+	  充值金额: 'order_price',
+	  推广名称: 'promotion_name',
+	  档位类型: 'tip_text',
+	  支付方式: 'pay_name',
+	  支付名称:"pay_merchant_name",
+	  收款主体:"payee_name",
+	  支付商户号:"pay_appid",
+	  平台审核: 'pt_verify_status_text',
+	  平台审核备注: 'pt_verify_remark',
+	  商户审核: 'sh_verify_status_text',
+	  商户审核备注: 'sh_verify_remark'
+	},
+	1: {
+	  商户名称: 'company_name',
+	  商户ID: 'puser_id',
+	  优化师: 'username',
+	  小程序: 'xcx_name',
+	  用户ID: 'uid',
+	  订单号: 'trade_no',
+	  订单时间: 'order_created_at',
+	  染色注册时间: 'ranse_created_at',
+	  申退金额: 'refund_price',
+	  充值金额: 'order_price',
+	  推广名称: 'promotion_name',
+	  档位类型: 'tip_text',
+	  支付方式: 'pay_name',
+	  支付名称:"pay_merchant_name",
+	  收款主体:"payee_name",
+	  支付商户号:"pay_appid",
+	  退款时间: 'pay_at',
+	  退款单号: 'refund_no',
+	  订单状态: 'status_text'
+	}
+}

+ 385 - 0
src/views/videoManage/wechatAudit/tabs/wechatAuditStatus/index.vue

@@ -0,0 +1,385 @@
+<template>
+  <div>
+    <div class="pl-5">
+      <el-radio-group v-model="query.refund_status" @change="search">
+        <el-radio v-for="item in statusListTop" :label="item.value" :key="item.value">{{ item.name }}</el-radio>
+      </el-radio-group>
+    </div>
+    <div class="flex justify-between">
+      <Search :search="search" :reset="resetQuery">
+        <template v-slot:body>
+          <el-form-item label="订单号" prop="trade_no">
+            <el-input v-model="query.trade_no" placeholder="请输入订单号" clearable />
+          </el-form-item>
+          <el-form-item label="用户ID" prop="uid">
+            <el-input v-model="query.uid" placeholder="请输入用户ID" clearable />
+          </el-form-item>
+          <el-form-item label="充值类型" prop="order_type">
+            <el-select v-model="query.order_type" filterable clearable placeholder="选择充值类型">
+              <el-option v-for="item in channelOrderTypeList" :key="item.value" :label="item.name" :value="item.value" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="推广名称" prop="promotion_id">
+            <el-select v-model="query.promotion_id" filterable remote clearable
+              :remote-method="(query) => { remoteMethod(query, 'channelPromotions') }" placeholder="全部推广名称">
+              <el-option v-for="item in channelPromotions" :key="item.promotion_id" :label="item.name"
+                :value="item.promotion_id" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="小程序" v-if="!query.promotion_id" prop="miniprogram_id">
+            <el-select v-model="query.miniprogram_id" filterable remote
+              :remote-method="(query) => { remoteMethod(query, 'channelMiniprogram') }" clearable placeholder="选择小程序">
+              <el-option v-for="item in channelMiniprogram" :key="item.miniprogram_id" :label="item.name"
+                :value="item.miniprogram_id" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="优化师" v-if="!query.promotion_id && !rolesIdentify.includes('optimizer')" prop="user_id">
+            <el-select v-model="query.user_id" filterable remote clearable
+              :remote-method="(query) => { remoteMethod(query, 'channelPromotionsUsers') }" placeholder="选择优化师">
+              <el-option v-for="item in promotionsUsersList" :key="item.user_id" :label="item.name"
+                :value="item.user_id" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="订单时间">
+            <el-date-picker unlink-panels clearable @change="orderTimeChange" format="YYYY/MM/DD"
+              value-format="YYYY-MM-DD" v-model="query.orderTime" type="daterange" :shortcuts="shortcuts"
+              range-separator="To" start-placeholder="开始时间" end-placeholder="结束时间" />
+          </el-form-item>
+		  <el-form-item label="支付名称" prop="pay_merchant_name"  v-if="rolesIdentify.includes('administrator')">
+		    <el-input v-model="query.pay_merchant_name" placeholder="请输入支付名称" clearable />
+		  </el-form-item>
+		  <el-form-item label="收款主体" prop="payee_name" v-if="rolesIdentify.includes('administrator')">
+		    <el-input v-model="query.payee_name" placeholder="请输入收款主体" clearable />
+		  </el-form-item>
+		  <el-form-item label="支付商户号" prop="pay_appid"  v-if="rolesIdentify.includes('administrator')">
+		    <el-input v-model="query.pay_appid" placeholder="请输入支付商户号" clearable />
+		  </el-form-item>
+        </template>
+        <template v-slot:extra_button>
+          <exportExcel v-if="rolesIdentify.includes('administrator')"  api="orderRefund/order_list" sheet_name="订单列表" :title_obj="titlePtObj[query.refund_status]"
+            :extro_params="{ is_all: true, ...query }">
+          </exportExcel>
+		  <exportExcel v-else="rolesIdentify.includes('administrator')"  api="orderRefund/order_list" sheet_name="订单列表" :title_obj="titleObj[query.refund_status]"
+		    :extro_params="{ is_all: true, ...query }">
+		  </exportExcel>
+		  
+        </template>
+      </Search>
+    </div>
+    <div class="table-default">
+      <el-table :data="tableData" class="mt-3" v-loading="loading">
+        <el-table-column prop="company_name" label="商户名称" min-width="200px"
+          v-if="rolesIdentify.includes('administrator')">
+          <template #default="scope">
+            <div>{{ scope.row.company_name }}</div>
+            <div>ID:{{ scope.row.puser_id }}</div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="username" label="优化师" show-overflow-tooltip min-width="200px"
+          v-if="!rolesIdentify.includes('optimizer')">
+        </el-table-column>
+        <el-table-column prop="xcx_name" show-overflow-tooltip label="小程序" min-width="200px">
+        </el-table-column>
+        <el-table-column prop="uid" label="用户ID" show-overflow-tooltip>
+        </el-table-column>
+        <el-table-column prop="trade_no" label="订单号" show-overflow-tooltip min-width="200px">
+        </el-table-column>
+        <el-table-column prop="order_created_at" label="订单时间" show-overflow-tooltip min-width="200px" />
+        <el-table-column prop="ranse_created_at" label="染色注册时间" show-overflow-tooltip min-width="200px" />
+        <el-table-column prop="refund_price" label="申退金额" show-overflow-tooltip min-width="200px" />
+        <el-table-column prop="order_price" label="充值金额" show-overflow-tooltip>
+        </el-table-column>
+        <el-table-column prop="promotion_name" label="推广名称" show-overflow-tooltip min-width="200px">
+        </el-table-column>
+        <el-table-column prop="tip_text" label="档位类型" show-overflow-tooltip min-width="150px">
+        </el-table-column>
+        <el-table-column prop="pay_name" label="支付方式" show-overflow-tooltip min-width="150px">
+        </el-table-column>
+		<el-table-column prop="pay_merchant_name" label="支付名称" show-overflow-tooltip min-width="150px"  v-if="rolesIdentify.includes('administrator')">
+		</el-table-column>
+		<el-table-column prop="payee_name" label="收款主体" show-overflow-tooltip min-width="150px"  v-if="rolesIdentify.includes('administrator')">
+		</el-table-column>
+		<el-table-column prop="pay_appid" label="支付商户号" show-overflow-tooltip min-width="150px"  v-if="rolesIdentify.includes('administrator')">
+		</el-table-column>
+        <el-table-column prop="pay_at" label="退款时间" v-if="query.refund_status == 1" show-overflow-tooltip
+          min-width="180px">
+        </el-table-column>
+        <el-table-column prop="refund_no" label="退款单号" v-if="query.refund_status == 1" show-overflow-tooltip
+          min-width="150px">
+        </el-table-column>
+        <el-table-column v-if="query.refund_status == 1" prop="status_text" label="订单状态" show-overflow-tooltip
+          min-width="150px">
+          <template #default="scope">
+            <div class="wrapper">
+              <span class="text-lg font-bold content">
+                <el-text class="mx-1" type="info">{{ scope.row.status_text }}</el-text>
+              </span>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column v-if="query.refund_status == 0" prop="pt_verify_status_text" label="平台审核" show-overflow-tooltip
+          min-width="150px">
+          <template #default="scope">
+            <div class="wrapper">
+              <span class="text-lg font-bold content">
+                <el-text class="mx-1" :type="colorType(scope.row)">{{ scope.row.pt_verify_status_text }}</el-text>
+              </span>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column v-if="query.refund_status == 0" prop="pt_verify_remark" label="平台审核备注" show-overflow-tooltip
+          min-width="150px">
+        </el-table-column>
+        <el-table-column v-if="query.refund_status == 0" prop="sh_verify_status_text" label="商户审核" show-overflow-tooltip
+          min-width="150px">
+          <template #default="scope">
+            <div class="wrapper">
+              <span class="text-lg font-bold content">
+                <el-text class="mx-1" :type="colorType(scope.row)">{{ scope.row.sh_verify_status_text }}</el-text>
+              </span>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column v-if="query.refund_status == 0" prop="sh_verify_remark" label="商户审核备注" show-overflow-tooltip
+          min-width="150px">
+        </el-table-column>
+        <el-table-column v-if="query.refund_status == 0" label="操作" fixed="right">
+          <template #default="scope">
+            <el-button link type="primary" size="small" v-action="'orderRefund.RefundOrder.platformVerify'"
+              @click="openType('noapprovedVisible', scope.row, '平台审核')">平台审核</el-button>
+            <br />
+            <el-button link type="primary" size="small" v-action="'orderRefund.RefundOrder.companyVerify'"
+              @click="openType('noapprovedVisible', scope.row, '商户审核')">商户审核</el-button>
+            <br />
+            <el-button :disabled="!scope.row.can_pay" link type="primary" size="small"
+              v-action="'orderRefund.RefundOrder.payToUser'"
+              @click="openType('approvedVisible', scope.row)">确认打款</el-button>
+            <br />
+          </template>
+        </el-table-column>
+      </el-table>
+      <Paginate />
+    </div>
+    <el-dialog width="500px" v-model="noapprovedVisible" :title="titleDialog" destroy-on-close @close="noapprovedClose">
+      <el-form :model="form" label-width="120px">
+        <el-form-item label="审核结果">
+          <el-radio-group v-model="form.status" @change="search">
+            <el-radio v-for="item in statusList" :label="item.value" :key="item.value">{{ item.name }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注">
+          <el-input v-model="form.remark" :rows="3" type="textarea" placeholder="请输入内容" autocomplete="off" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="noapprovedClose">取消</el-button>
+          <el-button type="primary" @click="noapproveChange">
+            确认
+          </el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { shortcuts } from '@/utils/shortcuts'
+import { useRouter, useRoute } from 'vue-router'
+import { InfoFilled } from '@element-plus/icons-vue';
+import { useGetList } from '@/hook/curd/useGetList';
+import {titleObj,titlePtObj} from "./excelTitle"
+import {
+  channelOrderList,
+  channelMiniprogramUseList,
+  channelPromotionsOptions,
+  channelPromotionsUsers,
+  channelOrderStatus,
+  channelOrderType,
+} from '@/api/orders/index'
+
+import { orderRefundVerifyPt, orderRefundVerifySh, orderRefundPayToUser } from '@/api/orders/index'
+import moment from 'moment';
+const form = ref({ status: 1 })
+const start_date = moment().startOf('month').format('YYYY-MM-DD')
+const end_date = moment().endOf('month').format('YYYY-MM-DD')
+const statusList = ref([
+  { name: '审核通过', value: 1 },
+  { name: '审核不通过', value: 2 },
+])
+const statusListTop = ref([
+  { name: '待审核', value: 0 },
+  { name: '已退款', value: 1 },
+])
+const api = 'orderRefund/order_list';
+const router = useRouter()
+const route = useRoute()
+const approvedVisible = ref(false)
+const noapprovedVisible = ref(false)
+const { data, query, search, reset, loading } = useGetList(api);
+const titleDialog = ref('')
+const current = ref({})
+const promotionsUsersList = ref([])
+const channelMiniprogram = ref([])
+const channelPromotions = ref([])
+const channelOrderStatusList = ref([])
+const channelOrderTypeList = ref([])
+const rolesIdentify = inject('rolesIdentify')
+
+const colorType = (data: object) => {
+  const type = data.pt_verify_status || data.sh_verify_status
+  switch (type) {
+    case 0:
+      return 'warning'
+    case 1:
+      return 'success'
+    case 2:
+      return 'danger'
+  }
+}
+const noapprovedClose = () => {
+  form.value = { status: 1 };
+  noapprovedVisible.value = false;
+}
+
+const noapproveChange = () => {
+  let api;
+  if (titleDialog.value == '平台审核') {
+    api = orderRefundVerifyPt
+  } else if (titleDialog.value == '商户审核') {
+    api = orderRefundVerifySh
+  }
+  api({ refund_id: current.value.id, ...form.value }).then(res => {
+    console.log(res, 'apiapiapiapi');
+    ElMessage.success(res.message)
+    noapprovedVisible.value = false;
+    search()
+  })
+}
+
+const openType = (type: string, data?: object, title?: string) => {
+  current.value = data || {}
+  switch (type) {
+    case 'approvedVisible':
+      ElMessageBox.confirm(
+        '确认打款吗?',
+        '提示',
+        {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        }
+      )
+        .then(() => {
+          orderRefundPayToUser({ refund_id: current.value.id }).then(res => {
+            ElMessage.success(res.message)
+            search()
+          })
+        })
+        .catch(() => {
+
+        })
+      break;
+    case 'noapprovedVisible':
+      titleDialog.value = title || ''
+      noapprovedVisible.value = true
+      break;
+  }
+}
+
+const orderTimeChange = (e: object) => {
+  console.log(e, 'timeChangetimeChangetimeChange');
+  if (query.value.orderTime) {
+    const timeArr = toRaw(e);
+    query.value.created_at_start = timeArr[0]
+    query.value.created_at_end = timeArr[1]
+  } else {
+    delete query.value.created_at_start
+    delete query.value.created_at_end
+  }
+}
+const remoteMethod = (query: string, type: string,) => {
+  console.log(query, 'queryquery', type);
+  switch (type) {
+    case 'channelPromotionsUsers':
+      initRemoteOption('channelPromotionsUsers', { name: query })
+      break;
+    case 'channelMiniprogram':
+      initRemoteOption('channelMiniprogram', { name: query })
+      break;
+    case 'channelPromotions':
+      initRemoteOption('channelPromotions', { name: query })
+      break;
+  }
+}
+
+const initRemoteOption = (type: string, params?: object) => {
+  switch (type) {
+    case 'channelPromotionsUsers':
+      channelPromotionsUsers({ limit: 30, ...params }).then(res => {
+        promotionsUsersList.value = res.data
+      })
+      break;
+    case 'channelMiniprogram':
+      channelMiniprogramUseList({ limit: 30, ...params }).then(res => {
+        channelMiniprogram.value = res.data
+      })
+      break;
+    case 'channelPromotions':
+      channelPromotionsOptions({ limit: 30, ...params }).then(res => {
+        channelPromotions.value = res.data
+      })
+      break;
+  }
+}
+
+const init = () => {
+  channelOrderStatus().then(res => {
+    console.log(res);
+    channelOrderStatusList.value = res.data
+  })
+  channelOrderType().then(res => {
+    console.log(res);
+    channelOrderTypeList.value = res.data
+  })
+}
+
+const resetQuery = () => {
+  query.value = Object.assign({ page: query.value.page, limit: query.value.limit, refund_status: 0 });
+  search()
+}
+const tableData = computed(() => data.value?.data);
+
+onMounted(() => {
+  console.log(rolesIdentify, 'rolesIdentifyrolesIdentify');
+  initRemoteOption('channelPromotionsUsers')
+  initRemoteOption('channelMiniprogram')
+  initRemoteOption('channelPromotions')
+  init()
+  query.value.refund_status = 0;
+  search();
+});
+</script>
+
+<style scoped lang="scss">
+.table-default {
+  .set-warpper {
+    height: 60px;
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+  }
+
+  .wrapper {
+    margin: 8px;
+
+    .label {
+      margin-right: 6px;
+    }
+
+    .content {
+      font-size: 15px;
+    }
+  }
+}
+</style>