zhangjq
2026-02-07 81846734e6ee1bf7da9acbbd5871e277b8a0ccd0
“加了编辑加了批量发稿,改了文案编辑获取人名”
6个文件已修改
458 ■■■■ 已修改文件
src/views/copywriting/generated/index.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingReview/Copywriting.api.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingReview/CopywritingList.vue 81 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingReview/review/index.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywritingUp/BatchPublish.vue 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
tatus 241 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywriting/generated/index.vue
@@ -218,13 +218,8 @@
            wenti: this.wenti || '',
          };
          // 直接调用编辑接口,禁用自动成功提示
          await defHttp.post({
            url: '/copywriting/copywriting/edit',
            params
          }, {
            successMessageMode: 'none' // 禁用自动成功提示
          });
          // 调用编辑接口
          await saveOrUpdate(params, false);
          // 保存成功后返回上一级页面
          this.$router.back();
        } catch (error) {
src/views/copywritingReview/Copywriting.api.ts
@@ -75,7 +75,8 @@
/**
 * 审核接口
 * @param params 审核参数
 * @param options 配置选项
 */
export const reviewCopywriting = (params) => {
  return defHttp.post({url: Api.edit, params});
export const reviewCopywriting = (params, options = {}) => {
  return defHttp.post({url: Api.edit, params}, options);
}
src/views/copywritingReview/CopywritingList.vue
@@ -54,7 +54,7 @@
          {{ record.semanticWord?.nowNo || '' }}
        </template>
        <template v-else-if="column.dataIndex === 'semanticWord.changer'">
          {{ record.semanticWord?.changer || '' }}
          {{ getChangerName(record.semanticWord?.changer) }}
        </template>
      </template>
    </BasicTable>
@@ -162,16 +162,24 @@
  }
  function handleEdit(record: Recordable) {
    try {
      // 直接跳转到生成页面,传递当前页面的参数
      router.push({
        path: '/copywritingReview/review/index',
        path: '/copywriting/generated/index',
        query: {
          semanticWord: record.semanticWord?.word || '',
          ranking: record.semanticWord?.ranking || '',
          outWord: record.semanticWord?.outWord || '',
          contractId: record.semanticWord?.contractId || '',
          id: record.id || '',
          title: record.title || '',
          text: record.text || '',
          fromEdit: 'true', // 添加标识,表示来自编辑按钮跳转
        },
      });
    } catch (error) {
      console.error('路由跳转失败:', error);
      console.error('跳转失败:', error);
      // 如果路由跳转失败,尝试使用完整路径
      window.location.href = '/#/copywriting/download';
      window.location.href = '/#/copywriting/generated/index?id=' + (record.id || '');
    }
  }
  /**
@@ -206,6 +214,22 @@
  }
 
  /**
   * 审核事件
   */
  function handleReview(record: Recordable) {
    try {
      router.push({
        path: '/copywritingReview/review/index',
        query: {
          id: record.id || '',
        },
      });
    } catch (error) {
      console.error('跳转失败:', error);
      window.location.href = '/#/copywritingReview/review/index?id=' + (record.id || '');
    }
  }
  /**
   * 删除事件
   */
  async function handleDelete(record) {
@@ -230,14 +254,14 @@
    // 根据状态值决定按钮显示和点击事件
    const isReviewStatus = record.status == 3 || record.status == 4;
    const buttonLabel = isReviewStatus ? '查看' : '审核';
    const onClickHandler = isReviewStatus ? handleReviewDetail : handleEdit;
    const onClickHandler = isReviewStatus ? handleReviewDetail : handleReview;
    return [
      //  {
      //    label: '编辑',
      //    onClick: handleEdit.bind(null, record),
      //    auth: 'copywriting:copywriting:edit'
      //  },
      {
        label: '编辑',
        onClick: handleEdit.bind(null, record),
        auth: 'copywriting:copywriting:edit'
      },
      {
        label: buttonLabel,
        onClick: onClickHandler.bind(null, record),
@@ -265,6 +289,41 @@
      },
    ];
  }
  /**
   * 获取编辑者名称
   * @param changer 编辑者信息
   * @returns 格式化后的编辑者名称
   */
  function getChangerName(changer) {
    if (!changer) return '';
    // 如果changer是对象且包含name字段,返回name
    if (typeof changer === 'object' && changer.name) {
      return changer.name;
    }
    // 如果changer是对象且包含realname字段,返回realname
    if (typeof changer === 'object' && changer.realname) {
      return changer.realname;
    }
    // 如果changer是对象且包含username字段,返回username
    if (typeof changer === 'object' && changer.username) {
      return changer.username;
    }
    // 如果changer是字符串,检查是否是ID格式
    if (typeof changer === 'string') {
      // 尝试从字符串中提取可能的名称部分
      // 处理类似 "197876356840171 5702" 这样的格式
      const parts = changer.split(' ');
      if (parts.length > 1) {
        // 如果有多个部分,返回最后一个部分
        return parts[parts.length - 1];
      }
      // 否则直接返回
      return changer;
    }
    // 其他情况返回空字符串
    return '';
  }
</script>
 
<style lang="less" scoped>
src/views/copywritingReview/review/index.vue
@@ -164,7 +164,9 @@
          platform: reviewForm.recommendedPlatform,
        };
 
        reviewCopywriting(params)
        reviewCopywriting(params, {
          successMessageMode: 'none' // 禁用默认成功消息
        })
          .then(() => {
            loading.reject = false;
            message.success('文案已驳回');
@@ -204,7 +206,9 @@
          platform: reviewForm.recommendedPlatform,
        };
 
        reviewCopywriting(params)
        reviewCopywriting(params, {
          successMessageMode: 'none' // 禁用默认成功消息
        })
          .then(() => {
            loading.approve = false;
            message.success('文案已通过');
src/views/copywritingUp/BatchPublish.vue
@@ -207,22 +207,16 @@
  // 批量发稿
  const handleBatchPublish = async () => {
    if (!formRef.value) return;
    try {
      // 1. 表单验证
      await formRef.value.validate();
      if (!formState.contractId) {
        createMessage.error('请选择合同');
        return;
      }
      submitLoading.value = true;
      
      // 2. 构建请求参数
      const requestData = {
        contractId: formState.contractId,
      };
      console.log('=== 批量发稿请求数据 ===');
      console.log('请求数据:', requestData);
      // 3. 获取登录 Token
      // 2. 获取登录 Token
      const token = getToken();
      if (!token) {
        createMessage.error('未登录,请先登录系统');
@@ -230,63 +224,34 @@
        return;
      }
      
      // 4. 生成时间戳和签名
      const timestamp = Date.now().toString();
      const sign = generateSign(token, timestamp, formState.contractId);
      // 5. 构建 FormData
      // 3. 构建 FormData
      const formData = new FormData();
      formData.append('contractId', formState.contractId);
      if (formState.mediaGroups) {
        // 将媒体列表字符串按逗号分割并添加到FormData中
        const mediaArray = formState.mediaGroups.split(',').map(item => item.trim());
        console.log('媒体数组:', mediaArray);
        // 对于multipart/form-data格式,重复添加同名参数来传递数组
        mediaArray.forEach((media, index) => {
          formData.append('mediaList', media);
          console.log(`添加参数: mediaList = ${media}`);
        });
      }
      
      // 6. 发送请求 - 参考批量导入的代码,使用 XMLHttpRequest 手动构建请求
      // 这样可以绕过拦截器,确保在不同环境下都能正常调用
      const domainUrl = import.meta.env.VITE_GLOB_DOMAIN_URL || 'http://192.168.31.222:8080/jeecg-boot';
      // 4. 发送请求 - 使用 XMLHttpRequest 发送 multipart/form-data 请求
      const domainUrl = 'http://192.168.31.222:8080/jeecg-boot';
      const url = `${domainUrl}/api/excel/batchPublish`;
      
      console.log('===== 手动构建 multipart/form-data 请求 =====');
      console.log('===== 发送 multipart/form-data 请求 =====');
      console.log('请求 URL:', url);
      console.log('请求参数:', requestData);
      console.log('合同ID:', formState.contractId);
      console.log('媒体列表:', formState.mediaGroups);
      
      // 手动构建 multipart/form-data 请求
      // 发送请求
      const responseData = await new Promise((resolve, reject) => {
        // 生成随机边界
        const boundary = '----WebKitFormBoundary' + Math.random().toString(36).substr(2, 16);
        // 构建请求体的各个部分
        const parts = [];
        // 添加 contractId 参数
        parts.push(
          `--${boundary}\r\n`,
          'Content-Disposition: form-data; name="contractId"\r\n',
          'Content-Type: text/plain\r\n',
          '\r\n',
          formState.contractId,
          '\r\n'
        );
        // 添加 mediaGroups 参数
        parts.push(
          `--${boundary}\r\n`,
          'Content-Disposition: form-data; name="mediaGroups"\r\n',
          'Content-Type: text/plain\r\n',
          '\r\n',
          formState.mediaGroups,
          '\r\n'
        );
        // 添加结束边界
        parts.push(
          `--${boundary}--\r\n`
        );
        // 创建最终的请求体 Blob
        const requestBody = new Blob(parts, { type: `multipart/form-data; boundary=${boundary}` });
        // 创建 XMLHttpRequest
        const xhr = new XMLHttpRequest();
        
        // 监听请求完成
        // 响应处理
        xhr.onload = function() {
          if (xhr.status >= 200 && xhr.status < 300) {
            try {
@@ -303,37 +268,31 @@
          }
        };
        
        // 监听网络错误
        // 网络错误处理
        xhr.onerror = function() {
          console.error('网络错误');
          reject(new Error('网络错误'));
        };
        
        // 打开请求
        // 打开连接
        xhr.open('POST', url, true);
        
        // 设置请求头 - 参考批量导入的代码,确保包含所有必需的请求头
        xhr.setRequestHeader('Accept', 'application/json, text/plain, */*');
        xhr.setRequestHeader('Authorization', `Bearer ${token}`);
        xhr.setRequestHeader('Referer', window.location.href);
        // 设置请求头
        xhr.setRequestHeader('X-Access-Token', token);
        xhr.setRequestHeader('X-Sign', sign);
        xhr.setRequestHeader('X-TIMESTAMP', timestamp);
        xhr.setRequestHeader('X-Tenant-Id', '0');
        xhr.setRequestHeader('X-Version', 'v3');
        // 手动设置正确的 Content-Type,包含边界
        xhr.setRequestHeader('Content-Type', `multipart/form-data; boundary=${boundary}`);
        // 设置 Content-Length
        xhr.setRequestHeader('Content-Length', requestBody.size.toString());
        xhr.setRequestHeader('Accept', 'application/json, text/plain, */*');
        // 注意:使用FormData时,浏览器会自动设置Content-Type头,包含正确的边界
        
        // 发送请求
        xhr.send(requestBody);
        xhr.send(formData);
      });
      
      console.log('后端响应数据:', responseData);
      
      // 7. 处理响应
      if (responseData && (responseData.success || responseData.code === 200 || responseData.code === 201)) {
      // 4. 处理响应
      const data = responseData.data;
      if (data && (data.success || data.code === 200 || data.code === 201)) {
        // 处理成功响应
        publishResults.value = [
          {
@@ -352,7 +311,7 @@
      } else {
        // 处理失败响应
        showResult.value = false; // 失败时不显示结果
        createMessage.error(responseData?.message || responseData?.msg || '批量发稿失败');
        createMessage.error(data?.message || data?.msg || '批量发稿失败');
      }
      
    } catch (error: any) {
@@ -380,6 +339,11 @@
    console.log('选择的合同ID:', value);
  };
  
  // 过滤选项
  const filterOption = (input: string, option: any) => {
    return (option?.label || '').toLowerCase().includes(input.toLowerCase());
  };
  // 页面加载时初始化
  onMounted(async () => {
    // 加载合同列表
tatus
@@ -71,3 +71,244 @@
  ESC-^F _<_c_1_> _<_c_2_>  *  Find close bracket _<_c_2_>.
  ESC-^B _<_c_1_> _<_c_2_>  *  Find open bracket _<_c_1_>.
        ---------------------------------------------------
        Each "find close bracket" command goes forward to the close bracket
          matching the (_N-th) open bracket in the top line.
        Each "find open bracket" command goes backward to the open bracket
          matching the (_N-th) close bracket in the bottom line.
  m_<_l_e_t_t_e_r_>            Mark the current top line with <letter>.
  M_<_l_e_t_t_e_r_>            Mark the current bottom line with <letter>.
  '_<_l_e_t_t_e_r_>            Go to a previously marked position.
  ''                   Go to the previous position.
  ^X^X                 Same as '.
  ESC-m_<_l_e_t_t_e_r_>        Clear a mark.
        ---------------------------------------------------
        A mark is any upper-case or lower-case letter.
        Certain marks are predefined:
             ^  means  beginning of the file
             $  means  end of the file
 ---------------------------------------------------------------------------
                        CCHHAANNGGIINNGG FFIILLEESS
  :e [_f_i_l_e]            Examine a new file.
  ^X^V                 Same as :e.
  :n                *  Examine the (_N-th) next file from the command line.
  :p                *  Examine the (_N-th) previous file from the command line.
  :x                *  Examine the first (or _N-th) file from the command line.
  ^O^O                 Open the currently selected OSC8 hyperlink.
  :d                   Delete the current file from the command line list.
  =  ^G  :f            Print current file name.
 ---------------------------------------------------------------------------
                    MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS
  -_<_f_l_a_g_>              Toggle a command line option [see OPTIONS below].
  --_<_n_a_m_e_>             Toggle a command line option, by name.
  __<_f_l_a_g_>              Display the setting of a command line option.
  ___<_n_a_m_e_>             Display the setting of an option, by name.
  +_c_m_d                 Execute the less cmd each time a new file is examined.
  !_c_o_m_m_a_n_d             Execute the shell command with $SHELL.
  #_c_o_m_m_a_n_d             Execute the shell command, expanded like a prompt.
  |XX_c_o_m_m_a_n_d            Pipe file between current pos & mark XX to shell command.
  s _f_i_l_e               Save input to a file.
  v                    Edit the current file with $VISUAL or $EDITOR.
  V                    Print version number of "less".
 ---------------------------------------------------------------------------
                           OOPPTTIIOONNSS
        Most options may be changed either on the command line,
        or from within less by using the - or -- command.
        Options may be given in one of two forms: either a single
        character preceded by a -, or a name preceded by --.
  -?  ........  --help
                  Display help (from command line).
  -a  ........  --search-skip-screen
                  Search skips current screen.
  -A  ........  --SEARCH-SKIP-SCREEN
                  Search starts just after target line.
  -b [_N]  ....  --buffers=[_N]
                  Number of buffers.
  -B  ........  --auto-buffers
                  Don't automatically allocate buffers for pipes.
  -c  ........  --clear-screen
                  Repaint by clearing rather than scrolling.
  -d  ........  --dumb
                  Dumb terminal.
  -D xx_c_o_l_o_r  .  --color=xx_c_o_l_o_r
                  Set screen colors.
  -e  -E  ....  --quit-at-eof  --QUIT-AT-EOF
                  Quit at end of file.
  -f  ........  --force
                  Force open non-regular files.
  -F  ........  --quit-if-one-screen
                  Quit if entire file fits on first screen.
  -g  ........  --hilite-search
                  Highlight only last match for searches.
  -G  ........  --HILITE-SEARCH
                  Don't highlight any matches for searches.
  -h [_N]  ....  --max-back-scroll=[_N]
                  Backward scroll limit.
  -i  ........  --ignore-case
                  Ignore case in searches that do not contain uppercase.
  -I  ........  --IGNORE-CASE
                  Ignore case in all searches.
  -j [_N]  ....  --jump-target=[_N]
                  Screen position of target lines.
  -J  ........  --status-column
                  Display a status column at left edge of screen.
  -k _f_i_l_e  ...  --lesskey-file=_f_i_l_e
                  Use a compiled lesskey file.
  -K  ........  --quit-on-intr
                  Exit less in response to ctrl-C.
  -L  ........  --no-lessopen
                  Ignore the LESSOPEN environment variable.
  -m  -M  ....  --long-prompt  --LONG-PROMPT
                  Set prompt style.
  -n .........  --line-numbers
                  Suppress line numbers in prompts and messages.
  -N .........  --LINE-NUMBERS
                  Display line number at start of each line.
  -o [_f_i_l_e] ..  --log-file=[_f_i_l_e]
                  Copy to log file (standard input only).
  -O [_f_i_l_e] ..  --LOG-FILE=[_f_i_l_e]
                  Copy to log file (unconditionally overwrite).
  -p _p_a_t_t_e_r_n .  --pattern=[_p_a_t_t_e_r_n]
                  Start at pattern (from command line).
  -P [_p_r_o_m_p_t]   --prompt=[_p_r_o_m_p_t]
                  Define new prompt.
  -q  -Q  ....  --quiet  --QUIET  --silent --SILENT
                  Quiet the terminal bell.
  -r  -R  ....  --raw-control-chars  --RAW-CONTROL-CHARS
                  Output "raw" control characters.
  -s  ........  --squeeze-blank-lines
                  Squeeze multiple blank lines.
  -S  ........  --chop-long-lines
                  Chop (truncate) long lines rather than wrapping.
  -t _t_a_g  ....  --tag=[_t_a_g]
                  Find a tag.
  -T [_t_a_g_s_f_i_l_e] --tag-file=[_t_a_g_s_f_i_l_e]
                  Use an alternate tags file.
  -u  -U  ....  --underline-special  --UNDERLINE-SPECIAL
                  Change handling of backspaces, tabs and carriage returns.
  -V  ........  --version
                  Display the version number of "less".
  -w  ........  --hilite-unread
                  Highlight first new line after forward-screen.
  -W  ........  --HILITE-UNREAD
                  Highlight first new line after any forward movement.
  -x [_N[,...]]  --tabs=[_N[,...]]
                  Set tab stops.
  -X  ........  --no-init
                  Don't use termcap init/deinit strings.
  -y [_N]  ....  --max-forw-scroll=[_N]
                  Forward scroll limit.
  -z [_N]  ....  --window=[_N]
                  Set size of window.
  -" [_c[_c]]  .  --quotes=[_c[_c]]
                  Set shell quote characters.
  -~  ........  --tilde
                  Don't display tildes after end of file.
  -# [_N]  ....  --shift=[_N]
                  Set horizontal scroll amount (0 = one half screen width).
                --exit-follow-on-close
                  Exit F command on a pipe when writer closes pipe.
                --file-size
                  Automatically determine the size of the input file.
                --follow-name
                  The F command changes files if the input file is renamed.
                --header=[_L[,_C[,_N]]]
                  Use _L lines (starting at line _N) and _C columns as headers.
                --incsearch
                  Search file as each pattern character is typed in.
                --intr=[_C]
                  Use _C instead of ^X to interrupt a read.
                --lesskey-context=_t_e_x_t
                  Use lesskey source file contents.
                --lesskey-src=_f_i_l_e
                  Use a lesskey source file.
                --line-num-width=[_N]
                  Set the width of the -N line number field to _N characters.
                --match-shift=[_N]
                  Show at least _N characters to the left of a search match.
                --modelines=[_N]
                  Read _N lines from the input file and look for vim modelines.
                --mouse
                  Enable mouse input.
                --no-keypad
                  Don't send termcap keypad init/deinit strings.
                --no-histdups
                  Remove duplicates from command history.
                --no-number-headers
                  Don't give line numbers to header lines.
                --no-search-header-lines
                  Searches do not include header lines.
                --no-search-header-columns
                  Searches do not include header columns.
                --no-search-headers
                  Searches do not include header lines or columns.
                --no-vbell
                  Disable the terminal's visual bell.
                --redraw-on-quit
                  Redraw final screen when quitting.
                --rscroll=[_C]
                  Set the character used to mark truncated lines.
                --save-marks
                  Retain marks across invocations of less.
                --search-options=[EFKNRW-]
                  Set default options for every search.
                --show-preproc-errors
                  Display a message if preprocessor exits with an error status.
                --proc-backspace
                  Process backspaces for bold/underline.
                --PROC-BACKSPACE
                  Treat backspaces as control characters.
                --proc-return
                  Delete carriage returns before newline.
                --PROC-RETURN
                  Treat carriage returns as control characters.
                --proc-tab
                  Expand tabs to spaces.
                --PROC-TAB
                  Treat tabs as control characters.
                --status-col-width=[_N]
                  Set the width of the -J status column to _N characters.
                --status-line
                  Highlight or color the entire line containing a mark.
                --use-backslash
                  Subsequent options use backslash as escape char.
                --use-color
                  Enables colored text.
                --wheel-lines=[_N]
                  Each click of the mouse wheel moves _N lines.
                --wordwrap
                  Wrap lines at spaces.
 ---------------------------------------------------------------------------
                          LLIINNEE EEDDIITTIINNGG
        These keys can be used to edit text being entered
        on the "command line" at the bottom of the screen.
 RightArrow ..................... ESC-l ... Move cursor right one character.
 LeftArrow ...................... ESC-h ... Move cursor left one character.
 ctrl-RightArrow  ESC-RightArrow  ESC-w ... Move cursor right one word.
 ctrl-LeftArrow   ESC-LeftArrow   ESC-b ... Move cursor left one word.
 HOME ........................... ESC-0 ... Move cursor to start of line.
 END ............................ ESC-$ ... Move cursor to end of line.
 BACKSPACE ................................ Delete char to left of cursor.
 DELETE ......................... ESC-x ... Delete char under cursor.
 ctrl-BACKSPACE   ESC-BACKSPACE ........... Delete word to left of cursor.
 ctrl-DELETE .... ESC-DELETE .... ESC-X ... Delete word under cursor.
 ctrl-U ......... ESC (MS-DOS only) ....... Delete entire line.
 UpArrow ........................ ESC-k ... Retrieve previous command line.
 DownArrow ...................... ESC-j ... Retrieve next command line.
 TAB ...................................... Complete filename & cycle.
 SHIFT-TAB ...................... ESC-TAB   Complete filename & reverse cycle.
 ctrl-L ................................... Complete filename, list all.