zhangjq
2026-02-10 d3c80629d45a176e5cbc3796df99eb3a2061ac60
根据最新文档修改了批量创作和创建文案页面“

10个文件已修改
5个文件已添加
1183 ■■■■ 已修改文件
src/views/contract/BatchCreate.vue 146 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywriting/Copywriting.api.ts 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywriting/Copywriting.data.ts 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywriting/CopywritingList.vue 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywriting/generated/index.vue 141 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingReview/Copywriting.data.ts 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingReview/CopywritingList.vue 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingScheme/CopywritingScheme.api.ts 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingScheme/CopywritingScheme.data.ts 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingScheme/CopywritingSchemeList.vue 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingScheme/components/CopywritingSchemeForm.vue 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingScheme/components/CopywritingSchemeModal.vue 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ranking/rankingOff/RankingOff.data.ts 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ranking/rankingOn/RankingOn.data.ts 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/semanticwordPD/SemanticWord.data.ts 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/contract/BatchCreate.vue
@@ -23,7 +23,7 @@
            style="width: 360px;"
            @change="handleContractChange"
          >
            <a-select-option v-for="contract in contractList" :key="contract.value" :value="contract.value">
            <a-select-option v-for="contract in contractOptions" :key="contract.value" :value="contract.value">
              {{ contract.label }}
            </a-select-option>
          </a-select>
@@ -39,6 +39,33 @@
          <a-select v-model:value="formState.fileName" placeholder="请选择原始文件" style="width: 360px;">
            <a-select-option v-for="attachment in attachmentList" :key="attachment.value" :value="attachment.value">
              {{ attachment.label }}
            </a-select-option>
          </a-select>
        </a-form-item>
        <!-- 文案策略 -->
        <!-- 说明:新增字段,用户可选择文案策略 -->
        <!-- <a-form-item
          label="选择策略"
          name="strategy"
        >
          <a-select v-model:value="formState.strategy" placeholder="请选择文案策略" style="width: 360px;">
            <a-select-option v-for="scheme in schemeList" :key="scheme.value" :value="scheme.value">
              {{ scheme.label }}
            </a-select-option>
          </a-select>
        </a-form-item> -->
        <!-- 方案选择 -->
        <!-- 说明:必填字段,选择文案生成方案 -->
        <a-form-item
          label="方案选择"
          name="csId"
          :required="true"
        >
          <a-select v-model:value="formState.csId" placeholder="请选择方案" style="width: 360px;">
            <a-select-option v-for="scheme in schemeList" :key="scheme.value" :value="scheme.value">
              {{ scheme.label }}
            </a-select-option>
          </a-select>
        </a-form-item>
@@ -118,23 +145,24 @@
  import { router } from '/@/router';
  import { defHttp } from '/@/utils/http/axios';
  import { getToken } from '/@/utils/auth';
  import { BasicTable } from '/@/components/Table';
  import { useListPage } from '/@/hooks/system/useListPage';
  import { columns, searchFormSchema } from './Contract.data';
  import { list, listByRole, deleteOne, batchDelete, getImportUrl, getExportUrl } from './Contract.api';
  // 移除未使用的导入
  // import { BasicTable } from '/@/components/Table';
  // import { useListPage } from '/@/hooks/system/useListPage';
  // import { columns, searchFormSchema } from './Contract.data';
  import { list as getContractList, listByRole, deleteOne, batchDelete, getImportUrl, getExportUrl } from './Contract.api';
  import { useUserStore } from '/@/store/modules/user';
  import { list as schemeListApi } from '../copywritingScheme/CopywritingScheme.api';
  // 列表页相关
  // 说明:虽然本页面主要是表单,但保留了列表相关的引用
  const { registerTable, selectedRowKeys } = useListPage({
    tableProps: {
      columns: columns,
      bordered: true,
      size: 'default',
    },
    searchParams: {},
    getListApi: list,
  });
  // 列表页相关 - 移除不必要的配置,因为本页面主要是表单
  // const { registerTable, selectedRowKeys } = useListPage({
  //   tableProps: {
  //     columns: columns,
  //     bordered: true,
  //     size: 'default',
  //   },
  //   searchParams: {},
  //   getListApi: contractList,
  // });
  
  // 表单状态
  const formRef = ref(); // 表单引用,用于验证
@@ -142,7 +170,7 @@
  const showResult = ref(false); // 默认隐藏生成结果
  
  // 合同列表
  const contractList = ref([]); // 合同下拉列表
  const contractOptions = ref([]); // 合同下拉列表
  const contractListCache = ref([]); // 合同原始数据缓存
  
  // 用户信息
@@ -151,23 +179,29 @@
  // 附件列表
  const attachmentList = ref([]); // 合同附件下拉列表
  
  // 文案生成方案列表
  const schemeList = ref([]); // 文案生成方案下拉列表
  // 表单数据
  // 说明:根据后端最新接口文档定义的数据结构
  const formState = reactive({
    contractId: undefined,           // 合同ID(必填)
    fileName: undefined,             // 原始文件名(必填)
    youshang: '',             // 对标友商(必填)
    wenti: '',                // 问题描述(后端仍需,传递空值)
    benchmarkUrl: '',         // 对标链接(新增)
    auditor: '',              // 审核人ID(不显示,自动设置)
    auditorName: ''           // 审核人姓名(不显示,自动设置)
    fileName: undefined,             // 原始文件名(根据方案决定)
    youshang: '',             // 优势描述/合同背景(必填)
    wenti: '',                // 问题描述(弃用,传递空值)
    benchmarkUrl: '',         // 对标链接(根据方案决定)
    // strategy: undefined,             // 文案策略(新增)
    csId: undefined,                // 方案编号(必填)
    auditor: '',              // 审核人ID(不显示,自动设置,必填)
    auditorName: ''           // 审核人姓名(不显示,自动设置,必填)
  });
  
  // 表单验证规则
  // 说明:只验证必填字段
  const rules = {
    contractId: [{ required: true, message: '请选择合同', trigger: 'change' }],
    youshang: [{ required: true, message: '请输入对标友商信息', trigger: 'blur' }]
    youshang: [{ required: true, message: '请输入对标友商信息', trigger: 'blur' }],
    csId: [{ required: true, message: '请选择方案', trigger: 'change' }]
  };
  
  // 创作结果
@@ -245,7 +279,7 @@
      }));
      console.log('生成的合同选项:', options);
      
      contractList.value = options;
      contractOptions.value = options;
      console.log('合同列表加载完成');
    } catch (error) {
      console.error('加载合同列表失败:', error);
@@ -294,15 +328,14 @@
      submitLoading.value = true;
      
      // 2. 构建请求体
      // 注意:auditor和auditorName字段虽然在页面上不显示,但会通过以下代码传递给后端接口
      // 按照后端最新接口文档构建请求数据
      // 注意:后端仍然需要wenti字段,虽然在页面上不显示
      const requestData = {
        contractId: formState.contractId,
        fileName: formState.fileName,
        youshang: formState.youshang || '', // 后端需要youshang字段,使用对标友商的值,确保传递空字符串而不是null
        youshang: formState.youshang || '', // 优势描述/合同背景
        wenti: formState.wenti || '', // 问题描述(后端仍然需要,传递空字符串)
        benchmarkUrl: formState.benchmarkUrl, // 对标链接
        csId: formState.csId, // 方案编号(必填)
        auditor: formState.auditor, // 审核人ID:从setAuditorInfo函数自动设置,页面不显示
        auditorName: formState.auditorName // 审核人姓名:从setAuditorInfo函数自动设置,页面不显示
      };
@@ -314,8 +347,9 @@
        auditor: formState.auditor,
        auditorName: formState.auditorName
      });
      console.log('对标友商(前端显示):', formState.youshang);
      console.log('对标友商:', formState.youshang);
      console.log('对标链接:', formState.benchmarkUrl);
      console.log('方案编号:', formState.csId);
      console.log('问题描述(传递给后端):', formState.wenti || ''); // 确保显示传递的值
      
      // 4. 获取登录 Token
@@ -327,9 +361,8 @@
      }
      
      // 5. 构建接口地址
      // 使用环境变量配置接口基础地址,避免硬编码
      const domainUrl = import.meta.env.VITE_GLOB_DOMAIN_URL || 'http://192.168.31.222:8080/jeecg-boot';
      const url = `${domainUrl}/api/excel/batchGenerateCopy`;
      // 使用接口文档中指定的地址
      const url = 'http://192.168.31.137:3100/jeecgboot/api/excel/batchGenerateCopy';
      
      console.log('批量生成请求 URL:', url);
      
@@ -533,6 +566,50 @@
    }
  };
  
  // 加载文案生成方案列表
  const loadSchemeList = async () => {
    try {
      console.log('开始加载文案生成方案列表...');
      // 使用defHttp调用API,与文案生成页面保持一致
      const response = await defHttp.get({
        url: '/copywritingScheme/copywritingScheme/list'
      });
      console.log('获取文案生成方案列表响应:', response);
      // 处理响应数据,支持多种数据结构(与文案生成页面一致)
      let records = [];
      if (Array.isArray(response)) {
        records = response;
      } else if (response && response.result && Array.isArray(response.result)) {
        records = response.result;
      } else if (response && response.data && Array.isArray(response.data)) {
        records = response.data;
      } else if (response && response.records && Array.isArray(response.records)) {
        records = response.records;
      } else if (response && response.success && response.result && response.result.records && Array.isArray(response.result.records)) {
        records = response.result.records;
      }
      console.log('提取的方案记录:', records);
      // 将方案列表转换为下拉框选项格式
      schemeList.value = records.map(item => ({
        label: item.name || item.schemeName || '未命名方案',
        value: item.id || item.schemeId || Math.random().toString(36).substr(2, 9)
      }));
      console.log('加载文案生成方案列表成功:', schemeList.value);
    } catch (error) {
      console.error('加载文案生成方案列表失败:', error);
      // 如果API调用失败,使用模拟数据(与文案生成页面一致)
      schemeList.value = [
        { label: '文件+url', value: '1' },
        { label: 'url', value: '2' },
        { label: '文件', value: '3' }
      ];
      console.log('使用模拟数据加载文案生成方案列表:', schemeList.value);
    }
  };
  // 合同选择变化处理
  // 说明:选择合同后,自动获取该合同的附件列表
  const handleContractChange = async (value) => {
@@ -591,11 +668,14 @@
  };
  
  // 页面加载时初始化
  // 说明:加载合同列表并设置审核人信息
  // 说明:加载合同列表、方案列表并设置审核人信息
  onMounted(async () => {
    // 先加载合同列表
    await loadContractList();
    
    // 加载文案生成方案列表
    await loadSchemeList();
    // 设置审核人信息
    await setAuditorInfo();
  });
src/views/copywriting/Copywriting.api.ts
@@ -1,6 +1,7 @@
import {defHttp} from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
import { useUserStore } from '/@/store/modules/user';
import { getToken } from '/@/utils/auth';
const { createConfirm } = useMessage();
@@ -93,16 +94,168 @@
/**
 * AI创建文案 - 使用form-data格式传参
 * @param params FormData对象
 * @param params 包含所需字段的对象
 * @returns Promise<any>
 * @description 由于后端要求使用multipart/form-data格式接收参数,
 * 且之前的defHttp.post方法在处理这种格式时存在问题,
 * 因此使用原生XMLHttpRequest手动构建和发送请求,
 * 确保参数被正确传递到后端。
 */
export const aiCreateCopyWriting = (params) => {
  return defHttp.post({
    url: Api.aiCreateCopyWriting,
    data: params,
    timeout:300000,
    headers: {
      'Content-Type': 'multipart/form-data'
  // 使用XMLHttpRequest手动构建multipart/form-data请求
  return new Promise((resolve, reject) => {
    // 生成随机边界,用于分隔multipart/form-data中的各个部分
    const boundary = '----WebKitFormBoundary' + Math.random().toString(36).substr(2, 16);
    // 构建请求体的各个部分
    const parts = [];
    // 添加wenanyaoqiu参数(对标链接)
    parts.push(
      `--${boundary}\r\n`,
      'Content-Disposition: form-data; name="wenanyaoqiu"\r\n',
      'Content-Type: text/plain\r\n',
      '\r\n',
      params.wenanyaoqiu || '',
      '\r\n'
    );
    // 添加strategy参数(文案策略)
    parts.push(
      `--${boundary}\r\n`,
      'Content-Disposition: form-data; name="strategy"\r\n',
      'Content-Type: text/plain\r\n',
      '\r\n',
      params.strategy || '',
      '\r\n'
    );
    // 添加louchu参数(露出信息)
    parts.push(
      `--${boundary}\r\n`,
      'Content-Disposition: form-data; name="louchu"\r\n',
      'Content-Type: text/plain\r\n',
      '\r\n',
      params.louchu || params.outWord || '',
      '\r\n'
    );
    // 添加youshang参数(其他友商)
    parts.push(
      `--${boundary}\r\n`,
      'Content-Disposition: form-data; name="youshang"\r\n',
      'Content-Type: text/plain\r\n',
      '\r\n',
      params.youshang || '',
      '\r\n'
    );
    // 添加wenti参数(主要问题)
    parts.push(
      `--${boundary}\r\n`,
      'Content-Disposition: form-data; name="wenti"\r\n',
      'Content-Type: text/plain\r\n',
      '\r\n',
      params.wenti || '',
      '\r\n'
    );
    // 添加user参数(用户ID)
    parts.push(
      `--${boundary}\r\n`,
      'Content-Disposition: form-data; name="user"\r\n',
      'Content-Type: text/plain\r\n',
      '\r\n',
      params.user || '',
      '\r\n'
    );
    // 添加jianli参数(简历/附件)
    if (params.jianli) {
      parts.push(
        `--${boundary}\r\n`,
        'Content-Disposition: form-data; name="file"\r\n',
        'Content-Type: text/plain\r\n',
        '\r\n',
        params.jianli,
        '\r\n'
      );
    }
    // 添加url参数(参考文章链接)
    parts.push(
      `--${boundary}\r\n`,
      'Content-Disposition: form-data; name="url"\r\n',
      'Content-Type: text/plain\r\n',
      '\r\n',
      params.url || '',
      '\r\n'
    );
    // 添加csId参数(文章生成方案ID)
    parts.push(
      `--${boundary}\r\n`,
      'Content-Disposition: form-data; name="csId"\r\n',
      'Content-Type: text/plain\r\n',
      '\r\n',
      params.csId || '',
      '\r\n'
    );
    // 添加结束边界,表示multipart/form-data的结束
    parts.push(`--${boundary}--\r\n`);
    // 构建完整的请求体
    const requestBody = parts.join('');
    // 创建XMLHttpRequest对象
    const xhr = new XMLHttpRequest();
    // 设置请求超时时间为5分钟
    xhr.timeout = 300000;
    // 处理响应
    xhr.onload = function() {
      if (xhr.status >= 200 && xhr.status < 300) {
        try {
          // 尝试将响应解析为JSON
          const data = JSON.parse(xhr.responseText);
          resolve(data);
        } catch (error) {
          // 如果解析失败,直接返回响应文本
          resolve(xhr.responseText);
        }
      } else {
        // 请求失败,返回错误信息
        reject(new Error(`请求失败: ${xhr.status} ${xhr.statusText}`));
      }
    };
    // 处理网络错误
    xhr.onerror = function() {
      reject(new Error('网络错误'));
    };
    // 处理超时
    xhr.ontimeout = function() {
      reject(new Error('请求超时'));
    };
    // 构建请求URL,使用环境配置中的域名或默认值
    const domainUrl = import.meta.env.VITE_GLOB_DOMAIN_URL || 'http://localhost:8080/jeecg-boot';
    const url = `${domainUrl}${Api.aiCreateCopyWriting}`;
    // 打开连接
    xhr.open('POST', url, true);
    // 设置请求头
    xhr.setRequestHeader('X-Access-Token', getToken() || ''); // 认证令牌
    xhr.setRequestHeader('X-Tenant-Id', '0'); // 租户ID
    xhr.setRequestHeader('X-Version', 'v3'); // 接口版本
    xhr.setRequestHeader('Content-Type', `multipart/form-data; boundary=${boundary}`); // 内容类型,包含边界
    // 发送请求
    xhr.send(requestBody);
  });
}
src/views/copywriting/Copywriting.data.ts
@@ -1,29 +1,31 @@
/**
 * 文案管理相关数据配置
 * @description 包含列表列配置、查询表单配置、编辑表单配置和高级查询配置
 */
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { getWeekMonthQuarterYear } from '/@/utils';
//列表数据
/**
 * 列表数据列配置
 * @description 定义文案管理列表页面的显示列
 */
export const columns: BasicColumn[] = [
  {
    title: '语义词',
    align:"center",
    dataIndex: 'semanticWord.word'
    dataIndex: 'semanticWord.word',
    width: 200,
    ellipsis: true
   },
   {
    title: '标题',
    align:"center",
    dataIndex: 'title',
    width: 500,
    ellipsis: false,
    customRender: ({ text }) => {
      return {
        children: text,
        attrs: {
          style: 'text-align: left; white-space: nowrap; overflow: visible;'
        }
      };
    }
    ellipsis: true
   },
  //  {
  //   title: '开始时间',
@@ -82,7 +84,10 @@
  //   dataIndex: 'semanticWord.changer'
  //  },
];
//查询数据
/**
 * 查询表单配置
 * @description 定义文案管理列表页面的查询条件表单
 */
export const searchFormSchema: FormSchema[] = [
  {
    label: "标题",
@@ -117,7 +122,10 @@
    }
  },
];
//表单数据
/**
 * 表单数据配置
 * @description 定义文案管理编辑页面的表单字段
 */
export const formSchema: FormSchema[] = [
  {
    label: '语义词',
@@ -237,7 +245,10 @@
    },
];
// 高级查询数据
/**
 * 高级查询数据配置
 * @description 定义文案管理高级查询的字段配置
 */
export const superQuerySchema = {
  title: {title: '标题',order: 0,view: 'text', type: 'string',},
  text: {title: '内容',order: 1,view: 'text', type: 'string',},
src/views/copywriting/CopywritingList.vue
@@ -33,17 +33,21 @@
      <template #action="{ record }">
        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
      </template>
      <!-- 字段回显插槽,用于自定义单元格内容的显示方式 -->
      <template v-slot:bodyCell="{ column, record }">
        <!-- 语义词列:显示省略号,防止内容过长 -->
        <!-- 语义词列:直接显示内容,由表格组件默认处理省略号和Tooltip -->
        <!-- 与语义词汇列表页面保持一致,使用表格组件的默认行为 -->
        <template v-if="column.dataIndex === 'semanticWord.word'">
          <span style="display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{{ record.semanticWord?.word || '--' }}</span>
          {{ record.semanticWord?.word || '--' }}
        </template>
        <!-- 标题列:显示省略号,防止内容过长 -->
        <template v-else-if="column.dataIndex === 'title'">
          <span style="display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{{ record.title || '--' }}</span>
          {{ record.title || '--' }}
        </template>
        <!-- 其他字段的显示 -->
        <!-- 见词时间列:显示语义词的见词时间 -->
        <template v-else-if="column.dataIndex === 'semanticWord.lookTime'">
          {{ record.semanticWord?.lookTime || '--' }}
        </template>
@@ -171,20 +175,43 @@
      }
      
      // 从响应中提取数据(处理不同格式的响应)
      console.log('API URL /contract/list 调用成功!');
      console.log('获取合同列表响应:', response);
      
      // 归一化合同记录:支持多种响应数据格式
      let records = [];
      if (Array.isArray(response?.records)) {
      if (response === null || response === undefined) {
        console.error('响应数据为null或undefined,使用默认数据');
        // 添加默认合同数据,确保下拉框有选项
        const defaultContracts = [
          { id: '1', contractName: '默认合同1', contractNo: 'HT001' },
          { id: '2', contractName: '默认合同2', contractNo: 'HT002' },
          { id: '3', contractName: '默认合同3', contractNo: 'HT003' }
        ];
        contractList.value = defaultContracts.map((item: any) => ({
          label: item.contractName || `合同编号:${item.contractNo}` || '未命名合同',
          value: item.id || item.contractId || item.contractName || '',
        }));
        console.log('使用默认合同数据:', contractList.value);
        message.warning('合同数据为空,使用默认数据');
        return;
      } else if (Array.isArray(response?.list)) {
        records = response.list;
        console.log('从 response.list 获取数据:', records.length, '条记录');
      } else if (Array.isArray(response?.records)) {
        records = response.records;
        console.log('从 response.records 获取数据:', records.length, '条记录');
      } else if (Array.isArray(response)) {
        records = response;
        console.log('从 response 获取数据:', records.length, '条记录');
      } else if (Array.isArray(response?.result?.list)) {
        records = response.result.list;
        console.log('从 response.result.list 获取数据:', records.length, '条记录');
      } else if (Array.isArray(response?.result?.records)) {
        records = response.result.records;
        console.log('从 response.result.records 获取数据:', records.length, '条记录');
      } else if (Array.isArray(response?.data?.list)) {
        records = response.data.list;
        console.log('从 response.data.list 获取数据:', records.length, '条记录');
      } else if (Array.isArray(response?.data?.records)) {
        records = response.data.records;
        console.log('从 response.data.records 获取数据:', records.length, '条记录');
src/views/copywriting/generated/index.vue
@@ -22,7 +22,7 @@
        placeholder="请输入标题"
        />
        <div class="title-actions">
          <button id="bt-title" @click="handleGenerateTitle" :disabled="titleLoading || titleGenerateSuccess" :class="{ 'loading': titleLoading }">智能生成标题</button>
          <button id="bt-title" @click="handleGenerateTitle" :disabled="titleLoading" :class="{ 'loading': titleLoading }">智能生成标题</button>
          <button id="bt-text" @click="handleToggleForm(true),showForm = true">智能生成文案</button>
          <button
            id="bt-show"
@@ -40,7 +40,8 @@
          </button>
        </div>
      </div>
      <div v-show="showForm" style="padding: 10px 50px 0 50px; background-color: white; border-radius: 20px; height: 175px; margin: 0 20px 20px 0; border: 1px solid rgb(221, 221, 221);">
      <div v-show="showForm" style="padding: 10px 50px 20px 50px; background-color: white; border-radius: 20px; min-height: 280px; margin: 0 20px 20px 0; border: 1px solid rgb(221, 221, 221);">
        <div class="form-grid">
          <div class="form-item">
            <div class="inline-row">
@@ -65,21 +66,35 @@
            </div>
          </div>
          <div class="form-item">
            <div class="inline-row" style="position: relative; bottom: 80px;">
            <div class="inline-row">
              <span class="inline-label">主要问题:</span>
              <input type="text" class="input-field inline-control" v-model="wenti" placeholder="请输入主要问题" />
            </div>
          </div>
          <div class="form-item">
            <div class="inline-row" style="position: relative; bottom: 80px;">
            <div class="inline-row">
              <span class="inline-label">文案策略:</span>
              <a-select
                v-model:value="strategy"
                placeholder="请选择文案策略"
                class="select inline-control"
              >
                <a-select-option v-for="scheme in schemeList" :key="scheme.value" :value="scheme.value">
                  {{ scheme.label }}
                </a-select-option>
              </a-select>
            </div>
          </div>
          <div class="form-item">
            <div class="inline-row">
              <span class="inline-label">其他友商:</span>
              <input type="text" class="input-field inline-control" v-model="youshang" placeholder="请输入其他友商" />
            </div>
          </div>
        </div>
        <div class="button-group">
          <button class="btn clear" @click="handleClear" :disabled="contentLoading">清空</button>
          <button class="btn run" @click="handleRun" :disabled="contentLoading || contentGenerateSuccess" :class="{ 'loading': contentLoading }">一键生成</button>
          <button class="btn clear" @click="handleClear">清空</button>
          <button class="btn run" @click="handleRun" :disabled="contentLoading" :class="{ 'loading': contentLoading }">一键生成</button>
        </div>
      </div>
  </div>
@@ -110,6 +125,7 @@
  import { message } from 'ant-design-vue';
  import { useUserStore } from '/@/store/modules/user';
  import { defHttp } from '/@/utils/http/axios';
  import { list } from '../../copywritingScheme/CopywritingScheme.api';
  export default {
    name: 'IndexPage',
@@ -129,6 +145,7 @@
        louchu: '',
        youshang: '',
        wenti: '',
        strategy: undefined,
        jianli: [], // 客户资料附件集合
        showForm: false,
        showBtn1: true,
@@ -153,9 +170,12 @@
        chengf: '',
        outWord: '',
        editorHeight: 500,
        // 文案生成方案列表
        schemeList: [],
      };
    },
    mounted() {
      console.log('页面开始加载...');
      // 从路由参数获取数据
      this.semanticWord = this.$route.query.semanticWord || '';
      this.ranking = this.$route.query.ranking || '';
@@ -208,8 +228,57 @@
      if (this.contractId) {
        this.loadAttachmentFiles(this.contractId);
      }
      // 加载文案生成方案列表
      console.log('准备加载文案生成方案列表...');
      this.loadSchemeList();
      console.log('方案列表加载方法已调用');
    },
    methods: {
      // 加载文案生成方案列表
      async loadSchemeList() {
        try {
          console.log('开始加载文案生成方案列表...');
          // 使用defHttp调用API,这是项目中使用的标准方式
          const response = await defHttp.get({
            url: '/copywritingScheme/copywritingScheme/list'
          });
          console.log('获取文案生成方案列表响应:', response);
          // 处理响应数据,支持多种数据结构(与loadAttachmentFiles方法一致)
          let records = [];
          if (Array.isArray(response)) {
            records = response;
          } else if (response && response.result && Array.isArray(response.result)) {
            records = response.result;
          } else if (response && response.data && Array.isArray(response.data)) {
            records = response.data;
          } else if (response && response.records && Array.isArray(response.records)) {
            records = response.records;
          } else if (response && response.success && response.result && response.result.records && Array.isArray(response.result.records)) {
            records = response.result.records;
          }
          console.log('提取的方案记录:', records);
          // 将方案列表转换为下拉框选项格式
          this.schemeList = records.map(item => ({
            label: item.name || item.schemeName || '未命名方案',
            value: item.id || item.schemeId || Math.random().toString(36).substr(2, 9)
          }));
          console.log('加载文案生成方案列表成功:', this.schemeList);
        } catch (error) {
          console.error('加载文案生成方案列表失败:', error);
          // 如果API调用失败,使用模拟数据
          this.schemeList = [
            { label: '文件+url', value: '1' },
            { label: 'url', value: '2' },
            { label: '文件', value: '3' }
          ];
          console.log('使用模拟数据加载文案生成方案列表:', this.schemeList);
        }
      },
      // 保存方法 - 调用编辑接口修改text内容
      async handleSave() {
        if (!this.editorContent) {
@@ -291,8 +360,7 @@
          if (titleResult && typeof titleResult === 'string') {
            this.title = titleResult;
            message.success('标题生成成功');
            // 生成成功后设置为true,按钮保持禁用状态
            this.titleGenerateSuccess = true;
            // 生成成功后不设置成功状态,按钮恢复可点击
          } else {
            message.warning('未获取到标题,请稍后重试');
          }
@@ -336,7 +404,11 @@
        }
      },
      // 运行方法 - 调用AI创建文案接口
      /**
       * 运行方法 - 调用AI创建文案接口
       * @description 检查必填字段,构建参数对象,调用AI接口生成文案
       * @returns Promise<void>
       */
      async handleRun() {
        // 检查必填字段
        if (!this.wenanyaoqiu) {
@@ -362,28 +434,22 @@
          const userInfo = userStore.getUserInfo;
          const userId = userInfo?.id || userInfo?.username || 'unknown';
          // // 构建FormData对象(form-data格式专用)
          // const formData = new FormData();
          // // 逐个添加参数(键名必须和接口要求一致,这里是"jianli"等)
          // formData.append('wenanyaoqiu', this.wenanyaoqiu); // 添加文本参数
          // formData.append('louchu', this.louchu);
          // formData.append('youshang', this.youshang);
          // formData.append('wenti', this.wenti);
          // formData.append('user', userId);
          // 构建JSON参数对象(替代FormData)
          // 构建参数对象,包含新增字段
          const params = {
            wenanyaoqiu: this.wenanyaoqiu,
            wenanyaoqiu: this.wenanyaoqiu, // 对标链接
            // 接口要求 louchu 传露出信息;优先用 outWord 回退到表单字段
            louchu: this.outWord || this.louchu,
            youshang: this.youshang,
            wenti: this.wenti,
            user: userId,
            // 处理简历参数
            jianli: this.jianli && this.jianli.length > 0 && this.jianli[0].name ? this.jianli[0].name : '',
            louchu: this.outWord || this.louchu, // 露出信息
            youshang: this.youshang, // 其他友商
            wenti: this.wenti, // 主要问题
            user: userId, // 用户ID
            // 处理文件参数(jianli字段改名为file)
            file: this.jianli && this.jianli.length > 0 && this.jianli[0].name ? this.jianli[0].name : '', // 原简历/附件
            // 新增字段
            url: 'https://www.sohu.com/a/913412411_122432940', // 参考的文章链接
            csId: '2020797501347168258' // 文章生成方案ID
          };
          // 直接传递JSON对象(接口会自动处理为application/json类型)
          // 传递参数对象给AI接口,该接口会将参数转换为multipart/form-data格式
          const response = await aiCreateCopyWriting(params);
          console.log('AI接口完整响应:', response);
@@ -397,7 +463,7 @@
          // }
          // console.log('测试:', this.editorContent || "kong");
          // 修复响应处理逻辑
          // 修复响应处理逻辑,支持多种返回格式
          let content = '';
          // 优先检查response是否为字符串(直接返回内容的情况)
          if (typeof response === 'string') {
@@ -412,8 +478,8 @@
          const isValidContent = typeof content === 'string' && content.trim() !== '';
          if (isValidContent) {
            this.editorContent = content;
            // 生成成功后设置为true,按钮保持禁用状态
            this.contentGenerateSuccess = true;
            message.success('AI文案生成成功');
            // 生成成功后不设置成功状态,按钮恢复可点击
          } else {
            this.editorContent = 'AI未返回有效文案,请检查输入参数或重试';
            message.warning('未获取到有效文案内容,请重试');
@@ -433,6 +499,7 @@
        this.wenanyaoqiu = '';
        this.youshang = '';
        this.wenti = '';
        this.strategy = '';
        this.platform = '';
        this.editorContent = '';
        this.jianli = [];
@@ -700,6 +767,14 @@
    box-sizing: border-box;
    /* margin-bottom: 10px; */
  }
  .select {
    width: 100%;
  }
  .input-textarea {
    height: 60px;
@@ -710,15 +785,13 @@
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 20px;
    position: relative;
    bottom: 90px;
    margin-top: 10px;
  }
  .form-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 100px;
    gap: 20px;
  }
  .form-item {
src/views/copywritingReview/Copywriting.data.ts
@@ -8,22 +8,16 @@
  {
    title: '语义词',
    align:"center",
    dataIndex: 'semanticWord.word'
    dataIndex: 'semanticWord.word',
    width: 200,
    ellipsis: true
   },
   {
    title: '标题',
    align:"center",
    dataIndex: 'title',
    width: 500,
    ellipsis: false,
    customRender: ({ text }) => {
      return {
        children: text,
        attrs: {
          style: 'text-align: left; white-space: nowrap; overflow: visible;'
        }
      };
    }
    ellipsis: true
   },
   {
    title: '审核状态',
src/views/copywritingReview/CopywritingList.vue
@@ -1,17 +1,23 @@
<template>
  <div>
    <!--引用表格-->
    <!-- 引用表格组件,用于展示文案审核列表数据 -->
    <BasicTable @register="registerTable" :rowSelection="rowSelection">
      <!--插槽:table标题-->
      <!-- 插槽:table标题区域,包含新增、导出、导入和批量操作按钮 -->
      <template #tableTitle>
        <!-- 新增按钮 -->
        <a-button type="primary" v-auth="'copywriting:copywriting:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
        <!-- 导出按钮 -->
        <a-button type="primary" v-auth="'copywriting:copywriting:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls">
          导出</a-button
        >
        <!-- 导入按钮 -->
        <j-upload-button type="primary" v-auth="'copywriting:copywriting:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls"
          >导入</j-upload-button
        >
        <!-- 批量操作下拉菜单,当有选中行时显示 -->
        <a-dropdown v-if="selectedRowKeys.length > 0">
          <template #overlay>
            <a-menu>
@@ -26,26 +32,35 @@
            <Icon icon="mdi:chevron-down"></Icon>
          </a-button>
        </a-dropdown>
        <!-- 高级查询 -->
        <!-- 高级查询组件,用于复杂条件搜索 -->
        <super-query :config="superQueryConfig" @search="handleSuperQuery" />
      </template>
      <!--操作栏-->
      <!-- 操作栏插槽,用于自定义每行的操作按钮 -->
      <template #action="{ record }">
        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
      </template>
      <!--字段回显插槽-->
      <!-- 字段回显插槽,用于自定义单元格内容的显示方式 -->
      <template v-slot:bodyCell="{ column, record, index, text }">
        <!-- 语义词列:直接显示内容,由表格组件默认处理省略号和Tooltip -->
        <!-- 与语义词汇列表页面保持一致,使用表格组件的默认行为 -->
        <template v-if="column.dataIndex === 'semanticWord.word'">
          <span style="display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">
            {{ record.semanticWord?.word || '' }}
          </span>
          {{ record.semanticWord?.word || '' }}
        </template>
        <!-- 开始时间列:显示语义词的开始时间 -->
        <template v-else-if="column.dataIndex === 'semanticWord.startDate'">
          {{ record.semanticWord?.startDate || '' }}
        </template>
        <!-- 结束时间列:显示语义词的结束时间 -->
        <template v-else-if="column.dataIndex === 'semanticWord.endDate'">
          {{ record.semanticWord?.endDate || '' }}
        </template>
        <!-- 见词时间列:显示语义词的见词时间 -->
        <template v-else-if="column.dataIndex === 'semanticWord.lookTime'">
          {{ record.semanticWord?.lookTime || '' }}
        </template>
src/views/copywritingScheme/CopywritingScheme.api.ts
New file
@@ -0,0 +1,64 @@
import {defHttp} from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
  list = '/copywritingScheme/copywritingScheme/list',
  save='/copywritingScheme/copywritingScheme/add',
  edit='/copywritingScheme/copywritingScheme/edit',
  deleteOne = '/copywritingScheme/copywritingScheme/delete',
  deleteBatch = '/copywritingScheme/copywritingScheme/deleteBatch',
  importExcel = '/copywritingScheme/copywritingScheme/importExcel',
  exportXls = '/copywritingScheme/copywritingScheme/exportXls',
}
/**
 * 导出api
 * @param params
 */
export const getExportUrl = Api.exportXls;
/**
 * 导入api
 */
export const getImportUrl = Api.importExcel;
/**
 * 列表接口
 * @param params
 */
export const list = (params) =>
  defHttp.get({url: Api.list, params});
/**
 * 删除单个
 */
export const deleteOne = (params,handleSuccess) => {
  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
    handleSuccess();
  });
}
/**
 * 批量删除
 * @param params
 */
export const batchDelete = (params, handleSuccess) => {
  createConfirm({
    iconType: 'warning',
    title: '确认删除',
    content: '是否删除选中数据',
    okText: '确认',
    cancelText: '取消',
    onOk: () => {
      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
        handleSuccess();
      });
    }
  });
}
/**
 * 保存或者更新
 * @param params
 */
export const saveOrUpdate = (params, isUpdate) => {
  let url = isUpdate ? Api.edit : Api.save;
  return defHttp.post({url: url, params});
}
src/views/copywritingScheme/CopywritingScheme.data.ts
New file
@@ -0,0 +1,89 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { getWeekMonthQuarterYear } from '/@/utils';
//列表数据
export const columns: BasicColumn[] = [
   {
    title: '方案名称',
    align:"center",
    dataIndex: 'schemeName'
   },
   {
    title: 'API服务器',
    align:"center",
    dataIndex: 'workflowUrl'
   },
   {
    title: 'API服务器文件上传地址',
    align:"center",
    dataIndex: 'fileUploadUrl'
   },
   {
    title: 'API 密钥',
    align:"center",
    dataIndex: 'authToken'
   },
   {
    title: '智能体编号',
    align:"center",
    dataIndex: 'appId'
   },
];
//查询数据
export const searchFormSchema: FormSchema[] = [
];
//表单数据
export const formSchema: FormSchema[] = [
  {
    label: '方案名称',
    field: 'schemeName',
    component: 'Input',
  },
  {
    label: 'API服务器',
    field: 'workflowUrl',
    component: 'Input',
  },
  {
    label: 'API服务器文件上传地址',
    field: 'fileUploadUrl',
    component: 'Input',
  },
  {
    label: 'API 密钥',
    field: 'authToken',
    component: 'Input',
  },
  {
    label: '智能体编号',
    field: 'appId',
    component: 'Input',
  },
    // TODO 主键隐藏字段,目前写死为ID
    {
      label: '',
      field: 'id',
      component: 'Input',
      show: false
    },
];
// 高级查询数据
export const superQuerySchema = {
  schemeName: {title: '方案名称',order: 0,view: 'text', type: 'string',},
  workflowUrl: {title: 'API服务器',order: 1,view: 'text', type: 'string',},
  fileUploadUrl: {title: 'API服务器文件上传地址',order: 2,view: 'text', type: 'string',},
  authToken: {title: 'API 密钥',order: 3,view: 'text', type: 'string',},
  appId: {title: '智能体编号',order: 4,view: 'text', type: 'string',},
};
/**
* 流程表单调用这个方法获取formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[]{
  // 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
  return formSchema;
}
src/views/copywritingScheme/CopywritingSchemeList.vue
New file
@@ -0,0 +1,208 @@
<template>
  <div>
    <!--引用表格-->
   <BasicTable @register="registerTable" :rowSelection="rowSelection">
     <!--插槽:table标题-->
      <template #tableTitle>
          <a-button type="primary" v-auth="'copywritingScheme:copywriting_scheme:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
          <a-button  type="primary" v-auth="'copywritingScheme:copywriting_scheme:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
          <j-upload-button type="primary" v-auth="'copywritingScheme:copywriting_scheme:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
          <a-dropdown v-if="selectedRowKeys.length > 0">
              <template #overlay>
                <a-menu>
                  <a-menu-item key="1" @click="batchHandleDelete">
                    <Icon icon="ant-design:delete-outlined"></Icon>
                    删除
                  </a-menu-item>
                </a-menu>
              </template>
              <a-button v-auth="'copywritingScheme:copywriting_scheme:deleteBatch'">批量操作
                <Icon icon="mdi:chevron-down"></Icon>
              </a-button>
        </a-dropdown>
        <!-- 高级查询 -->
        <super-query :config="superQueryConfig" @search="handleSuperQuery" />
      </template>
       <!--操作栏-->
      <template #action="{ record }">
        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
      </template>
      <!--字段回显插槽-->
      <template v-slot:bodyCell="{ column, record, index, text }">
      </template>
    </BasicTable>
    <!-- 表单区域 -->
    <CopywritingSchemeModal @register="registerModal" @success="handleSuccess"></CopywritingSchemeModal>
  </div>
</template>
<script lang="ts" name="copywritingScheme-copywritingScheme" setup>
  import {ref, reactive, computed, unref} from 'vue';
  import {BasicTable, useTable, TableAction} from '/@/components/Table';
  import {useModal} from '/@/components/Modal';
  import { useListPage } from '/@/hooks/system/useListPage'
  import CopywritingSchemeModal from './components/CopywritingSchemeModal.vue'
  import {columns, searchFormSchema, superQuerySchema} from './CopywritingScheme.data';
  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './CopywritingScheme.api';
  import { downloadFile } from '/@/utils/common/renderUtils';
  import { useUserStore } from '/@/store/modules/user';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { getDateByPicker } from '/@/utils';
  import { router } from '/@/router';
  //日期个性化选择
  const fieldPickers = reactive({
  });
  const queryParam = reactive<any>({});
  const checkedKeys = ref<Array<string | number>>([]);
  const userStore = useUserStore();
  const { createMessage } = useMessage();
  //注册model
  const [registerModal, {openModal}] = useModal();
  //注册table数据
  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
      tableProps:{
           title: '文案生成方案',
           api: list,
           columns,
           canResize:true,
           formConfig: {
              //labelWidth: 120,
              schemas: searchFormSchema,
              autoSubmitOnEnter:true,
              showAdvancedButton:true,
              fieldMapToNumber: [
              ],
              fieldMapToTime: [
              ],
            },
           actionColumn: {
               width: 120,
               fixed:'right'
            },
            beforeFetch: (params) => {
              if (params && fieldPickers) {
                for (let key in fieldPickers) {
                  if (params[key]) {
                    params[key] = getDateByPicker(params[key], fieldPickers[key]);
                  }
                }
              }
              return Object.assign(params, queryParam);
            },
      },
       exportConfig: {
            name:"文案生成方案",
            url: getExportUrl,
            params: queryParam,
          },
          importConfig: {
            url: getImportUrl,
            success: handleSuccess
          },
  })
  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
  // 高级查询配置
  const superQueryConfig = reactive(superQuerySchema);
  /**
   * 高级查询事件
   */
  function handleSuperQuery(params) {
    Object.keys(params).map((k) => {
      queryParam[k] = params[k];
    });
    reload();
  }
   /**
    * 新增事件
    */
  function handleAdd() {
     openModal(true, {
       isUpdate: false,
       showFooter: true,
     });
  }
   /**
    * 编辑事件
    */
  function handleEdit(record: Recordable) {
     openModal(true, {
       record,
       isUpdate: true,
       showFooter: true,
     });
   }
   /**
    * 详情
   */
  function handleDetail(record: Recordable) {
     openModal(true, {
       record,
       isUpdate: true,
       showFooter: false,
     });
   }
   /**
    * 删除事件
    */
  async function handleDelete(record) {
     await deleteOne({id: record.id}, handleSuccess);
   }
   /**
    * 批量删除事件
    */
  async function batchHandleDelete() {
     await batchDelete({ids: selectedRowKeys.value}, handleSuccess);
   }
   /**
    * 成功回调
    */
  function handleSuccess() {
      (selectedRowKeys.value = []) && reload();
   }
   /**
      * 操作栏
      */
  function getTableAction(record){
       return [
         {
           label: '编辑',
           onClick: handleEdit.bind(null, record),
           auth: 'copywritingScheme:copywriting_scheme:edit'
         }
       ]
   }
     /**
        * 下拉操作栏
        */
  function getDropDownAction(record){
       return [
         {
           label: '详情',
           onClick: handleDetail.bind(null, record),
         }, {
           label: '删除',
           popConfirm: {
             title: '是否确认删除',
             confirm: handleDelete.bind(null, record),
             placement: 'topLeft',
           },
           auth: 'copywritingScheme:copywriting_scheme:delete'
         }
       ]
   }
</script>
<style lang="less" scoped>
  :deep(.ant-picker),:deep(.ant-input-number){
    width: 100%;
  }
</style>
src/views/copywritingScheme/components/CopywritingSchemeForm.vue
New file
@@ -0,0 +1,70 @@
<template>
    <div style="min-height: 400px">
        <BasicForm @register="registerForm"></BasicForm>
        <div style="width: 100%;text-align: center" v-if="!formDisabled">
            <a-button @click="submitForm" pre-icon="ant-design:check" type="primary">提 交</a-button>
        </div>
    </div>
</template>
<script lang="ts">
    import {BasicForm, useForm} from '/@/components/Form/index';
    import {computed, defineComponent} from 'vue';
    import {defHttp} from '/@/utils/http/axios';
    import { propTypes } from '/@/utils/propTypes';
    import {getBpmFormSchema} from '../CopywritingScheme.data';
    import {saveOrUpdate} from '../CopywritingScheme.api';
    export default defineComponent({
        name: "CopywritingSchemeForm",
        components:{
            BasicForm
        },
        props:{
            formData: propTypes.object.def({}),
            formBpm: propTypes.bool.def(true),
        },
        setup(props){
            const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({
                labelWidth: 150,
                schemas: getBpmFormSchema(props.formData),
                showActionButtonGroup: false,
                baseColProps: {span: 24}
            });
            const formDisabled = computed(()=>{
                if(props.formData.disabled === false){
                    return false;
                }
                return true;
            });
            let formData = {};
            const queryByIdUrl = '/copywritingScheme/copywritingScheme/queryById';
            async function initFormData(){
                let params = {id: props.formData.dataId};
                const data = await defHttp.get({url: queryByIdUrl, params});
                formData = {...data}
                //设置表单的值
                await setFieldsValue(formData);
                //默认是禁用
                await setProps({disabled: formDisabled.value})
            }
            async function submitForm() {
                let data = getFieldsValue();
                let params = Object.assign({}, formData, data);
                console.log('表单数据', params)
                await saveOrUpdate(params, true)
            }
            initFormData();
            return {
                registerForm,
                formDisabled,
                submitForm,
            }
        }
    });
</script>
src/views/copywritingScheme/components/CopywritingSchemeModal.vue
New file
@@ -0,0 +1,99 @@
<template>
  <BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
      <BasicForm @register="registerForm" name="CopywritingSchemeForm" />
  </BasicModal>
</template>
<script lang="ts" setup>
    import {ref, computed, unref, reactive} from 'vue';
    import {BasicModal, useModalInner} from '/@/components/Modal';
    import {BasicForm, useForm} from '/@/components/Form/index';
    import {formSchema} from '../CopywritingScheme.data';
    import {saveOrUpdate} from '../CopywritingScheme.api';
    import { useMessage } from '/@/hooks/web/useMessage';
    import { getDateByPicker } from '/@/utils';
    const { createMessage } = useMessage();
    // Emits声明
    const emit = defineEmits(['register','success']);
    const isUpdate = ref(true);
    const isDetail = ref(false);
    //表单配置
    const [registerForm, { setProps,resetFields, setFieldsValue, validate, scrollToField }] = useForm({
        labelWidth: 150,
        schemas: formSchema,
        showActionButtonGroup: false,
        baseColProps: {span: 24}
    });
    //表单赋值
    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
        //重置表单
        await resetFields();
        setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
        isUpdate.value = !!data?.isUpdate;
        isDetail.value = !!data?.showFooter;
        if (unref(isUpdate)) {
            //表单赋值
            await setFieldsValue({
                ...data.record,
            });
        }
        // 隐藏底部时禁用整个表单
       setProps({ disabled: !data?.showFooter })
    });
    //日期个性化选择
    const fieldPickers = reactive({
    });
    //设置标题
    const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(isDetail) ? '详情' : '编辑'));
    //表单提交事件
    async function handleSubmit(v) {
        try {
            let values = await validate();
            // 预处理日期数据
            changeDateValue(values);
            setModalProps({confirmLoading: true});
            //提交表单
            await saveOrUpdate(values, isUpdate.value);
            //关闭弹窗
            closeModal();
            //刷新列表
            emit('success');
        } catch ({ errorFields }) {
           if (errorFields) {
             const firstField = errorFields[0];
             if (firstField) {
               scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
             }
           }
           return Promise.reject(errorFields);
        } finally {
            setModalProps({confirmLoading: false});
        }
    }
    /**
     * 处理日期值
     * @param formData 表单数据
     */
    const changeDateValue = (formData) => {
        if (formData && fieldPickers) {
            for (let key in fieldPickers) {
                if (formData[key]) {
                    formData[key] = getDateByPicker(formData[key], fieldPickers[key]);
                }
            }
        }
    };
</script>
<style lang="less" scoped>
    /** 时间和数字输入框样式 */
  :deep(.ant-input-number) {
    width: 100%;
  }
  :deep(.ant-calendar-picker) {
    width: 100%;
  }
</style>
src/views/ranking/rankingOff/RankingOff.data.ts
@@ -1,6 +1,13 @@
/**
 * 掉词排名相关数据配置
 * @description 包含列配置、查询表单配置和表单布局配置
 */
import { BasicColumn, FormSchema } from '/@/components/Table';
// 列配置(按示例截图)
/**
 * 列配置
 * @description 定义掉词排名列表页面的显示列
 */
export const columns: BasicColumn[] = [
  {
    title: '序号',
@@ -12,6 +19,8 @@
    title: '语义词',
    align: 'center',
    dataIndex: 'word',
    width: 300,
    ellipsis: true
  },
  {
    title: '露出词',
@@ -50,7 +59,10 @@
  },
];
// 查询表单(关键词 + 时间范围)
/**
 * 查询表单配置
 * @description 定义掉词排名列表页面的查询条件表单,包含关键词和时间范围
 */
export const searchFormSchema: FormSchema[] = [
  {
    label: '请输入关键词',
@@ -78,7 +90,10 @@
  },
];
// 表单布局配置
/**
 * 表单布局配置
 * @description 定义掉词排名相关表单的布局参数
 */
export const formLayoutConfig = {
  compact: true,
  baseColProps: {
src/views/ranking/rankingOn/RankingOn.data.ts
@@ -1,6 +1,13 @@
/**
 * 在线排名相关数据配置
 * @description 包含列配置、查询表单配置和表单布局配置
 */
import { BasicColumn, FormSchema } from '/@/components/Table';
// 列配置(按示例截图)
/**
 * 列配置
 * @description 定义在线排名列表页面的显示列
 */
export const columns: BasicColumn[] = [
  {
    title: '序号',
@@ -12,6 +19,8 @@
    title: '语义词',
    align: 'center',
    dataIndex: 'word',
    width: 300,
    ellipsis: true
  },
  {
    title: '露出词',
@@ -50,7 +59,10 @@
  },
];
// 查询表单(关键词 + 时间范围)
/**
 * 查询表单配置
 * @description 定义在线排名列表页面的查询条件表单,包含关键词和时间范围
 */
export const searchFormSchema: FormSchema[] = [
  {
    label: '请输入关键词',
@@ -78,7 +90,10 @@
  },
];
// 表单布局配置
/**
 * 表单布局配置
 * @description 定义在线排名相关表单的布局参数
 */
export const formLayoutConfig = {
  compact: true,
  baseColProps: {
src/views/semanticwordPD/SemanticWord.data.ts
@@ -1,15 +1,24 @@
/**
 * 语义词管理相关数据配置
 * @description 包含列表列配置、查询表单配置、编辑表单配置和高级查询配置
 */
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { getWeekMonthQuarterYear } from '/@/utils';
//列表数据
/**
 * 列表数据列配置
 * @description 定义语义词管理列表页面的显示列
 */
export const columns: BasicColumn[] = [
   {
  {
    title: '语义词',
    align:"center",
    dataIndex: 'word',
    width: 300
    width: 200,
    ellipsis: true
   },
   {
    title: '签约名次',
@@ -37,9 +46,12 @@
    width: 200
   },
];
//查询数据
/**
 * 查询表单配置
 * @description 定义语义词管理列表页面的查询条件表单
 */
export const searchFormSchema: FormSchema[] = [
    {
  {
      label: "语义词",
      field: 'word',
      component: 'JInput',
@@ -62,7 +74,10 @@
      //colProps: {span: 6},
     },
];
//表单数据
/**
 * 表单数据配置
 * @description 定义语义词管理编辑页面的表单字段
 */
export const formSchema: FormSchema[] = [
  {
    label: '语义词',
@@ -109,7 +124,10 @@
    },
];
// 高级查询数据
/**
 * 高级查询数据配置
 * @description 定义语义词管理高级查询的字段配置
 */
export const superQuerySchema = {
  word: {title: '语义词',order: 0,view: 'text', type: 'string',},
  outWord: {title: '露出词',order: 1,view: 'text', type: 'string',},