Alex 9 месяцев назад
Родитель
Сommit
25ab7248b8

+ 0 - 0
src/views/marketing/ipMrakup/booklist/index.vue


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

@@ -0,0 +1,131 @@
+<!-- 搜索表单 -->
+<template>
+  <ele-card :body-style="{ paddingBottom: '8px' }">
+    <el-form ref="formRef" :model="form" label-width="80px" inline>
+      <el-row :gutter="12">
+        <el-col :span="6">
+          <el-form-item label="IP标题">
+            <el-input
+              v-model="form.name"
+              placeholder="请输入IP标题"
+              clearable
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="IP序号">
+            <el-input v-model="form.id" placeholder="请输入IP序号" clearable />
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="类型">
+            <el-select
+              v-model="form.type"
+              placeholder="请选择类型"
+              clearable
+              style="width: 100%"
+            >
+              <el-option label="全部" value="" />
+              <el-option label="小说" value="novel" />
+              <el-option label="动漫" value="anime" />
+              <el-option label="电影" value="movie" />
+              <el-option label="综艺" value="variety" />
+              <el-option label="其他" value="other" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="来源">
+            <el-select
+              v-model="form.source"
+              placeholder="请选择来源"
+              clearable
+              style="width: 100%"
+            >
+              <el-option label="全部" value="" />
+              <el-option label="原创" value="original" />
+              <el-option label="转载" value="repost" />
+              <el-option label="合作" value="cooperation" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+      </el-row>
+      <el-row :gutter="12">
+        <el-col :span="6">
+          <el-form-item label="状态">
+            <el-select
+              v-model="form.status"
+              placeholder="请选择状态"
+              clearable
+              style="width: 100%"
+            >
+              <el-option label="全部" value="" />
+              <el-option label="已启用" value="1" />
+              <el-option label="已禁用" value="0" />
+            </el-select>
+          </el-form-item>
+        </el-col>
+        <el-col :span="6">
+          <el-form-item label="发布日期">
+            <el-date-picker
+              v-model="form.timeRange"
+              type="daterange"
+              range-separator="-"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              style="width: 100%"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="12" style="text-align: right">
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button type="info" @click="handleReset">重置</el-button>
+        </el-col>
+      </el-row>
+    </el-form>
+  </ele-card>
+</template>
+
+<script setup>
+  import { ref, reactive } from 'vue';
+
+  const emit = defineEmits(['search']);
+
+  // 表单数据
+  const form = reactive({
+    name: '',
+    id: '',
+    type: '',
+    source: '',
+    status: '',
+    timeRange: []
+  });
+
+  // 表单引用
+  const formRef = ref(null);
+
+  // 处理搜索
+  const handleSearch = () => {
+    // 转换日期范围为开始时间和结束时间
+    const params = { ...form };
+    if (params.timeRange && params.timeRange.length > 0) {
+      params.startTime = params.timeRange[0];
+      params.endTime = params.timeRange[1];
+    }
+    delete params.timeRange;
+
+    emit('search', params);
+  };
+
+  // 处理重置
+  const handleReset = () => {
+    formRef.value.resetFields();
+    emit('search', {});
+  };
+</script>
+
+<style lang="scss" scoped>
+  :deep(.el-form-item__content) {
+    width: 100%;
+  }
+</style>

+ 175 - 0
src/views/marketing/ipMrakup/datalist/components/share-info.vue

@@ -0,0 +1,175 @@
+<!-- 分享信息弹窗 -->
+<template>
+  <el-dialog
+    v-model="visible"
+    title="分享IP信息"
+    width="600px"
+    :close-on-click-modal="false"
+    :append-to-body="true"
+  >
+    <el-form ref="formRef" :model="form" label-width="100px" :rules="rules">
+      <el-form-item label="IP标题" prop="name">
+        <el-input v-model="form.name" :disabled="true" />
+      </el-form-item>
+      <el-form-item label="分享方式" prop="shareType">
+        <el-select v-model="form.shareType" placeholder="请选择分享方式" style="width: 100%">
+          <el-option label="微信" value="wechat" />
+          <el-option label="QQ" value="qq" />
+          <el-option label="微博" value="weibo" />
+          <el-option label="链接" value="link" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="分享标题" prop="shareTitle">
+        <el-input v-model="form.shareTitle" placeholder="请输入分享标题" />
+      </el-form-item>
+      <el-form-item label="分享描述" prop="shareDesc">
+        <el-input v-model="form.shareDesc" type="textarea" rows="3" placeholder="请输入分享描述" />
+      </el-form-item>
+      <el-form-item label="分享图片" prop="shareImg">
+        <el-upload
+          class="share-upload"
+          action="#"
+          :http-request="handleUpload"
+          :show-file-list="false"
+          :before-upload="beforeUpload"
+        >
+          <img v-if="form.shareImg" :src="form.shareImg" class="share-image" />
+          <el-icon v-else class="share-upload-icon"><Plus /></el-icon>
+        </el-upload>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <el-row justify="center">
+        <el-button @click="visible = false">取消</el-button>
+        <el-button type="primary" @click="handleSubmit">确认分享</el-button>
+      </el-row>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import { getCurrentInstance } from 'vue';
+import { Plus } from '@element-plus/icons-vue';
+
+const { proxy } = getCurrentInstance();
+
+// 弹窗可见性
+const visible = ref(false);
+
+// 表单引用
+const formRef = ref(null);
+
+// 表单数据
+const form = reactive({
+  id: '',
+  name: '',
+  shareType: 'wechat',
+  shareTitle: '',
+  shareDesc: '',
+  shareImg: ''
+});
+
+// 表单验证规则
+const rules = {
+  shareType: [
+    { required: true, message: '请选择分享方式', trigger: 'change' }
+  ],
+  shareTitle: [
+    { required: true, message: '请输入分享标题', trigger: 'blur' },
+    { max: 50, message: '长度不能超过50个字符', trigger: 'blur' }
+  ],
+  shareDesc: [
+    { required: true, message: '请输入分享描述', trigger: 'blur' },
+    { max: 200, message: '长度不能超过200个字符', trigger: 'blur' }
+  ]
+};
+
+// 打开弹窗
+const openDialog = (row) => {
+  visible.value = true;
+  form.id = row.id;
+  form.name = row.name;
+  form.shareTitle = row.name;
+  form.shareDesc = row.description || '';
+  form.shareImg = row.image || '';
+};
+
+// 上传前检查
+const beforeUpload = (file) => {
+  const isJPG = file.type === 'image/jpeg';
+  const isPNG = file.type === 'image/png';
+  const isLt2M = file.size / 1024 / 1024 < 2;
+
+  if (!isJPG && !isPNG) {
+    proxy.$message.error('上传图片只能是 JPG 或 PNG 格式!');
+    return false;
+  }
+  if (!isLt2M) {
+    proxy.$message.error('上传图片大小不能超过 2MB!');
+    return false;
+  }
+  return true;
+};
+
+// 处理上传
+const handleUpload = (options) => {
+  const { file } = options;
+  // 这里应该替换为实际的上传API
+  const formData = new FormData();
+  formData.append('file', file);
+
+  // 模拟上传
+  setTimeout(() => {
+    // 模拟一个图片URL
+    form.shareImg = URL.createObjectURL(file);
+  }, 300);
+};
+
+// 提交分享
+const handleSubmit = () => {
+  formRef.value.validate((valid) => {
+    if (valid) {
+      // 这里应该替换为实际的分享API调用
+      proxy.$message.success('分享成功');
+      visible.value = false;
+    }
+  });
+};
+
+// 向外暴露方法
+defineExpose({
+  openDialog
+});
+</script>
+
+<style lang="scss" scoped>
+.share-upload {
+  border: 1px dashed #d9d9d9;
+  border-radius: 6px;
+  cursor: pointer;
+  position: relative;
+  overflow: hidden;
+  width: 148px;
+  height: 148px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+
+  &:hover {
+    border-color: #409eff;
+  }
+
+  .share-upload-icon {
+    font-size: 28px;
+    color: #8c939d;
+  }
+
+  .share-image {
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+  }
+}
+</style>

+ 84 - 0
src/views/marketing/ipMrakup/datalist/components/view-detail.vue

@@ -0,0 +1,84 @@
+<!-- 查看详情弹窗 -->
+<template>
+  <el-dialog
+    v-model="visible"
+    title="IP详情"
+    width="800px"
+    :close-on-click-modal="false"
+    :append-to-body="true"
+  >
+    <el-descriptions :column="2" border>
+      <el-descriptions-item label="IP序号">{{ detail.id }}</el-descriptions-item>
+      <el-descriptions-item label="IP标题">{{ detail.name }}</el-descriptions-item>
+      <el-descriptions-item label="发布时间">{{ detail.time }}</el-descriptions-item>
+      <el-descriptions-item label="类型">{{ detail.type }}</el-descriptions-item>
+      <el-descriptions-item label="来源">{{ detail.source }}</el-descriptions-item>
+      <el-descriptions-item label="状态">
+        <el-tag type="success" v-if="detail.status === 1">已启用</el-tag>
+        <el-tag type="danger" v-else>已禁用</el-tag>
+      </el-descriptions-item>
+      <el-descriptions-item label="浏览量">{{ detail.views }}</el-descriptions-item>
+      <el-descriptions-item label="点赞数">{{ detail.likes }}</el-descriptions-item>
+      <el-descriptions-item label="分享次数">{{ detail.shares }}</el-descriptions-item>
+      <el-descriptions-item label="创建时间">{{ detail.createTime }}</el-descriptions-item>
+      <el-descriptions-item label="IP简介" :span="2">
+        {{ detail.description || '暂无简介' }}
+      </el-descriptions-item>
+    </el-descriptions>
+
+    <template #footer>
+      <el-row justify="center">
+        <el-button @click="visible = false">关闭</el-button>
+        <el-button type="primary" @click="handleShare">分享</el-button>
+      </el-row>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+
+const emit = defineEmits(['share']);
+
+// 弹窗可见性
+const visible = ref(false);
+
+// 详情数据
+const detail = reactive({
+  id: '',
+  name: '',
+  time: '',
+  type: '',
+  source: '',
+  status: 0,
+  views: 0,
+  likes: 0,
+  shares: 0,
+  createTime: '',
+  description: ''
+});
+
+// 打开弹窗
+const openDialog = (row) => {
+  visible.value = true;
+  // 复制行数据到详情对象
+  Object.assign(detail, row);
+};
+
+// 处理分享
+const handleShare = () => {
+  emit('share', detail);
+  visible.value = false;
+};
+
+// 向外暴露方法
+defineExpose({
+  openDialog
+});
+</script>
+
+<style lang="scss" scoped>
+:deep(.el-dialog__body) {
+  padding: 20px;
+}
+</style>

+ 183 - 0
src/views/marketing/ipMrakup/datalist/index.vue

@@ -0,0 +1,183 @@
+<!-- IP营销数据列表 -->
+<template>
+  <div class="app-container">
+    <!-- 搜索表单 -->
+    <page-search @search="handleSearch" />
+
+    <!-- 表格数据 -->
+    <ele-card>
+      <ele-pro-table
+        ref="tableRef"
+        row-key="id"
+        :columns="columns"
+        :datasource="datasource"
+        :show-overflow-tooltip="true"
+        v-model:selections="selections"
+        highlight-current-row
+        border
+      >
+        <!-- 渲染操作按钮 -->
+        <template #action="{ row }">
+          <el-button link type="primary" @click="handleViewDetail(row)">查看详情</el-button>
+          <el-button link type="primary" @click="handleShare(row)">分享</el-button>
+        </template>
+
+        <!-- 渲染状态 -->
+        <template #status="{ row }">
+          <el-tag type="success" v-if="row.status === 1">已启用</el-tag>
+          <el-tag type="danger" v-else>已禁用</el-tag>
+        </template>
+      </ele-pro-table>
+    </ele-card>
+
+    <!-- 查看详情弹窗 -->
+    <view-detail ref="detailRef" />
+
+    <!-- 分享信息弹窗 -->
+    <share-info ref="shareRef" />
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive } from 'vue';
+import { getCurrentInstance } from 'vue';
+import PageSearch from './components/page-search.vue';
+import ViewDetail from './components/view-detail.vue';
+import ShareInfo from './components/share-info.vue';
+
+const { proxy } = getCurrentInstance();
+
+// 表格实例
+const tableRef = ref(null);
+
+// 查看详情弹窗实例
+const detailRef = ref(null);
+
+// 分享信息弹窗实例
+const shareRef = ref(null);
+
+// 表格选中数据
+const selections = ref([]);
+
+// 表格列配置
+const columns = ref([
+  {
+    type: 'selection',
+    columnKey: 'selection',
+    width: 50,
+    align: 'center',
+    fixed: 'left'
+  },
+  {
+    prop: 'id',
+    label: 'IP序号',
+    align: 'center',
+    width: 100
+  },
+  {
+    prop: 'name',
+    label: 'IP标题',
+    align: 'center',
+    minWidth: 150
+  },
+  {
+    prop: 'time',
+    label: '发布时间',
+    align: 'center',
+    width: 160
+  },
+  {
+    prop: 'type',
+    label: '类型',
+    align: 'center',
+    width: 100
+  },
+  {
+    prop: 'source',
+    label: '来源',
+    align: 'center',
+    width: 100
+  },
+  {
+    prop: 'views',
+    label: '浏览量',
+    align: 'center',
+    width: 100
+  },
+  {
+    prop: 'likes',
+    label: '点赞数',
+    align: 'center',
+    width: 100
+  },
+  {
+    prop: 'shares',
+    label: '分享次数',
+    align: 'center',
+    width: 100
+  },
+  {
+    prop: 'status',
+    label: '状态',
+    align: 'center',
+    width: 100,
+    slot: 'status'
+  },
+  {
+    columnKey: 'action',
+    label: '操作',
+    width: 160,
+    align: 'center',
+    slot: 'action',
+    hideInPrint: true,
+    hideInExport: true
+  }
+]);
+
+// 查询参数
+const queryParams = ref({
+  pageNum: 1,
+  pageSize: 20
+});
+
+// 数据源
+const datasource = ({ pages, where, orders }) => {
+  // 这里应该替换为实际的API调用
+  return proxy.$http.get('/marketing/ip/list', {
+    params: {
+      ...where,
+      ...orders,
+      ...pages
+    }
+  }).then(res => {
+    if (res.data.code === 200) {
+      return res.data;
+    }
+    return Promise.reject(new Error(res.data.msg));
+  });
+};
+
+// 搜索处理
+const handleSearch = (params) => {
+  tableRef.value?.reload?.({
+    page: 1,
+    where: params
+  });
+};
+
+// 查看详情
+const handleViewDetail = (row) => {
+  detailRef.value.openDialog(row);
+};
+
+// 分享处理
+const handleShare = (row) => {
+  shareRef.value.openDialog(row);
+};
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+  padding: 15px;
+}
+</style>

+ 0 - 0
src/views/marketing/ipMrakup/fission/index.vue


+ 0 - 0
src/views/marketing/ipMrakup/rules/index.vue