liubp
2025-10-20 ed5f1fac13f35e41928ae980848a90fac6b30dcd
登录验证
Signed-off-by: liubp <1535785116@qq.com>
3个文件已修改
3个文件已添加
595 ■■■■■ 已修改文件
src/views/contract/ContractList.vue 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywriting/Copywriting.api.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/copywriting/generated/index.vue 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/page/desc/copywriting/data.tsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/page/desc/copywriting/index.vue 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/page/form/copywriting/index.vue 280 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/contract/ContractList.vue
@@ -23,13 +23,20 @@
        </a-dropdown>
        <!-- 高级查询 -->
        <super-query :config="superQueryConfig" @search="handleSuperQuery" />
        <!-- 权限提示 -->
        <a-alert
          v-if="currentUsername"
          :message="isAdmin ? '管理员权限:可查看所有合同数据' : `当前用户:${currentUsername},仅可查看自己创建的合同数据`"
          type="info"
          show-icon
          style="margin-top: 8px;"
          size="small"
        />
      </template>
       <!--操作栏-->
      <template #action="{ record }">
        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
      </template>
      <!--字段回显插槽-->
      <template v-slot:bodyCell="{ column, record, index, text }">
      </template>
    </BasicTable>
    <!-- 表单区域 -->
@@ -83,7 +90,7 @@
</template>
<script lang="ts" name="contract-contract" setup>
  import {ref, reactive} from 'vue';
  import {ref, reactive, computed} from 'vue';
  import {BasicTable, TableAction} from '/@/components/Table';
  import { useListPage } from '/@/hooks/system/useListPage'
  import {useModal} from '/@/components/Modal';
@@ -94,6 +101,7 @@
  import { getDateByPicker } from '/@/utils';
  import { router } from '/@/router';
  import { getContractFilesApi, selectContractFilesApi } from '/@/api/demo/contract';
  import { useUserStore } from '/@/store/modules/user';
  
  //日期个性化选择
  const fieldPickers = reactive({
@@ -101,13 +109,19 @@
  const queryParam = reactive<any>({});
  const { createMessage } = useMessage();
  
  // 获取当前登录用户信息
  const userStore = useUserStore();
  const currentUser = computed(() => userStore.getUserInfo);
  const currentUsername = computed(() => currentUser.value?.username);
  const isAdmin = computed(() => currentUsername.value === 'admin');
  // 合同文件选择相关状态
  const contractFiles = ref<any[]>([]);
  const selectedContractIds = ref<string[]>([]);
  const showContractSelectModal = ref(false);
  
  //注册model
  const [registerModal, {openModal}] = useModal();
  const [registerModal, {openModal: _openModal}] = useModal();
  
  //注册table数据
  const { tableContext } = useListPage({
@@ -138,7 +152,15 @@
                  }
                }
              }
             return Object.assign(params, queryParam);
             // 添加当前用户作为查询条件
             // admin用户可以查看所有数据,其他用户只能查看自己创建的数据
             const finalParams = Object.assign(params, queryParam);
             if (currentUsername.value && !isAdmin.value) {
               finalParams.createBy = currentUsername.value;
             }
             return finalParams;
           },
        },
        exportConfig: {
src/views/copywriting/Copywriting.api.ts
@@ -72,6 +72,7 @@
  return defHttp.post({
    url: Api.aiCreateCopyWriting, 
    data: params,
    timeout:30000,
    headers: {
      'Content-Type': 'multipart/form-data'
    }
src/views/copywriting/generated/index.vue
@@ -182,38 +182,64 @@
        const userInfo = userStore.getUserInfo;
        const userId = userInfo?.id || userInfo?.username || 'unknown';
        // 构建FormData对象(form-data格式专用)
        const formData = new FormData();
        // // 构建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);
        // 逐个添加参数(键名必须和接口要求一致,这里是"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,
          louchu: 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
            : ''
        };
        
        // 检查jianli数组是否存在且不为空
        if (this.jianli && this.jianli.length > 0 && this.jianli[0].name) {
          formData.append('jianli', this.jianli[0].name); // 关键:添加jianli参数(String类型)
        } else {
          formData.append('jianli', ''); // 如果简历为空,传递空字符串
        }
        // 调试FormData内容
        console.log('FormData参数:');
        for (let [key, value] of formData.entries()) {
          console.log(`${key}: ${value}`);
        }
        // 调用接口时直接传递FormData对象
        const result = await aiCreateCopyWriting(formData);
        console.log('AI创建文案结果:', result);
        // 直接传递JSON对象(接口会自动处理为application/json类型)
        const response = await aiCreateCopyWriting(params);
        console.log('AI接口完整响应:', response);
        if (result && result.data && result.data.text) {
          this.editorContent = result.data.text;
        // // 调整响应处理逻辑,匹配新的返回格式
        // if (response && response.success && response.result) {
        //   this.editorContent = response.result;
        //   console.log('AI接口完整响应:', response);
        //   message.success('AI文案生成成功');
        // } else {
        //   message.warning('未获取到文案内容,请重试');
        // }
        // console.log('测试:', this.editorContent || "kong");
        // 修复响应处理逻辑
        let content = '';
        // 优先检查response是否为字符串(直接返回内容的情况)
        if (typeof response === 'string') {
          content = response;
        }
        // 其次检查是否是标准接口格式(带result字段)
        else if (response && response.success && response.result) {
          content = response.result;
        }
        // 验证内容有效性
        const isValidContent = typeof content === 'string' && content.trim() !== '';
        if (isValidContent) {
          this.editorContent = content;
          message.success('AI文案生成成功');
        } else {
          message.warning('未获取到文案内容,请重试');
          this.editorContent = 'AI未返回有效文案,请检查输入参数或重试';
          message.warning('未获取到有效文案内容,请重试');
        }
        console.log('测试:', this.editorContent || "kong");
      } catch (error) {
        console.error('AI文案生成失败:', error);
        message.error('AI文案生成失败,请重试');
src/views/demo/page/desc/copywriting/data.tsx
New file
@@ -0,0 +1,7 @@
// 语义词详情页数据
export const keywordData = {
  keyword: '示例语义词',
  rank: '1',
  cooperationPeriod: '2024-01-01 至 2024-12-31',
  status: '进行中',
};
src/views/demo/page/desc/copywriting/index.vue
New file
@@ -0,0 +1,195 @@
<template>
  <PageWrapper title="语义词派单" contentBackground>
    <a-card title="基本信息">
      <div v-if="semanticWords.length > 0">
        <a-descriptions title="">
          <a-descriptions-item label="语义词">
            <span>{{ semanticWords || '-' }}</span>
          </a-descriptions-item>
          <a-descriptions-item label="签约名次">
            <span>{{ ranking || '-' }}</span>
          </a-descriptions-item>
        </a-descriptions>
      </div>
      <div v-else>
        <a-empty description="暂无语义词数据" />
      </div>
    </a-card>
    <a-card title="审核信息">
      <a-descriptions-item label="审核状态">
          <span>{{ formData.customer?.customerAddress || '-' }}</span>
      </a-descriptions-item>
      <a-descriptions-item label="审核时间">
          <span>{{ formData.customer?.customerAddress || '-' }}</span>
      </a-descriptions-item>
      <a-descriptions-item label="审核人">
          <span>{{ formData.customer?.customerAddress || '-' }}</span>
      </a-descriptions-item>
    </a-card>
    <a-card title="发布平台">
      <span>推荐平台:</span>
    </a-card>
    <!-- 返回按钮 -->
    <div class="action-buttons">
      <a-button type="default" @click="handleBack" class="back-btn">返回</a-button>
    </div>
  </PageWrapper>
</template>
<script lang="ts">
import { defineComponent, reactive, ref, onMounted } from 'vue';
import { PageWrapper } from '/@/components/Page';
// import { message } from 'ant-design-vue';
import { useRoute, useRouter } from 'vue-router';
import { defHttp } from '/@/utils/http/axios';
// import { error } from 'console';
export default defineComponent({
  name: 'DescCopyWriting',
  components: { PageWrapper },
  setup() {
    const route = useRoute();
    const router = useRouter();
    // 初始数据
    const initialData = {
      id: '',
      createTime: '',
      updateBy: null,
      updateTime: null,
      agentsId: null,
      agentsName: null,
      contractFileList: null,
      contractName: '',
      createBy: '',
      customer: {
        id: '',
        createBy: '',
        createTime: '',
        updateBy: null,
        updateTime: null,
        agentsName: null,
        contactPerson: '',
        contract: null,
        customerAddress: '',
        customerEmail: '',
        customerPhone: '',
        enterpriseName: '',
        industry: '',
        semanticWordList: null
      },
      customerName: '',
      endDate: '',
      rejectionReasons: null,
      reviewStatus: '',
      semanticWordList: null,
      startDate: '',
      sysOrgCode: ''
    };
    // 响应式表单数据
    const formData = reactive({ ...initialData });
    // 语义词列表
    const semanticWords = ref<any[]>([]);
    const ranking = ref<any[]>([]);
    // 合同文件列表
    const reviewStatus = ref<any[]>([]);
    const attachmentFiles = ref<any[]>([]);
    // 加载语义词数据
    const loadSemanticWords = async () => {
      const id = route.query.id as string;
      if(id){
        try {
        const result = await defHttp.get({
          url: '/copywriting/copywriting/list',
          params: { id }
        });
        // 这里可以根据返回的数据结构处理语义词
        console.log("222222222222222222222222",result)
        console.log("1111111111111111111111111",ranking)
        if (result) {
          // 将语义词列表保存到响应式变量中
          semanticWords.value = result.records[0].semanticWord.word;
          ranking.value = result.records[0].semanticWord.ranking;
          await loadReview(id);
        }
      } catch (error) {
        console.error('加载语义词失败:', error);
      }
      }
    else{
      console.log("获取ID失败")
    }
    };
    //加载审核信息
    const loadReview = async (id: string) =>{
      try {
          const result = await defHttp.get({
            url: '/contract/contract/edit',
            params: { id },
          });
          console.log("审核",result)
          // if(result){
          //   reviewStatus.value = result.
          // }
        } catch (error) {
        console.error('加载语义词失败:', error);
      }
  }
      onMounted(() => {
        loadSemanticWords();
      });
    // 返回功能
    const handleBack = () => {
      router.back();
    };
    return {
      formData,
      attachmentFiles,
      semanticWords,
      ranking,
      handleBack
    };
  },
});
</script>
<style lang="less" scoped>
.desc-wrap {
  padding: 16px;
  background-color: @component-background;
}
.action-buttons {
  position: fixed;
  right: 24px;
  bottom: 24px;
  display: flex;
  gap: 12px;
  z-index: 1000;
  .back-btn {
    min-width: 80px;
    height: 40px;
    border-radius: 6px;
    font-weight: 500;
    background-color: #f5f5f5;
    border-color: #d9d9d9;
    color: #666;
    &:hover {
      background-color: #e6f7ff;
      border-color: #40a9ff;
      color: #40a9ff;
    }
  }
}
</style>
src/views/demo/page/form/copywriting/index.vue
New file
@@ -0,0 +1,280 @@
<template>
  <PageWrapper title="语义词菜单" contentBackground>
    <a-card title="基本信息">
      <a-descriptions title="" :column="3">
        <a-descriptions-item label="企业名称">
          <span>{{ formData.customer?.enterpriseName || '-' }}</span>
        </a-descriptions-item>
        <a-descriptions-item label="行业">
          <span>{{ formData.customer?.industry || '-' }}</span>
        </a-descriptions-item>
        <a-descriptions-item label="客户地址">
          <span>{{ formData.customer?.customerAddress || '-' }}</span>
        </a-descriptions-item>
        <a-descriptions-item label="对接人">
          <span>{{ formData.customer?.contactPerson || '-' }}</span>
        </a-descriptions-item>
        <a-descriptions-item label="客户电话">
          <span>{{ formData.customer?.customerPhone || '-' }}</span>
        </a-descriptions-item>
        <a-descriptions-item label="客户邮箱">
          <span>{{ formData.customer?.customerEmail || '-' }}</span>
        </a-descriptions-item>
      </a-descriptions>
    </a-card>
    <a-card title="合同信息">
      <a-descriptions title="" :column="1">
        <a-descriptions-item label="合作开始时间">
          <span>{{ formData.startDate || '-' }}</span>
        </a-descriptions-item>
        <a-descriptions-item label="合作结束时间">
          <span>{{ formData.endDate || '-' }}</span>
        </a-descriptions-item>
        <a-descriptions-item label="合同文件">
          <div v-if="contractFiles.length > 0">
            <a-list :data-source="contractFiles" size="small">
              <template #renderItem="{ item }">
                <a-list-item>
                  <a :href="item.url" target="_blank">{{ item.name }}</a>
                </a-list-item>
              </template>
            </a-list>
          </div>
          <div v-else>
            <span>-</span>
          </div>
        </a-descriptions-item>
        <a-descriptions-item label="附件">
          <div v-if="attachmentFiles.length > 0">
            <a-list :data-source="attachmentFiles" size="small">
              <template #renderItem="{ item }">
                <a-list-item>
                  <a :href="item.url" target="_blank">{{ item.name }}</a>
                </a-list-item>
              </template>
            </a-list>
          </div>
          <div v-else>
            <span>-</span>
          </div>
        </a-descriptions-item>
      </a-descriptions>
    </a-card>
    <a-card title="语义词信息">
      <div v-if="semanticWords.length > 0">
        <a-descriptions title="" :column="1">
          <a-descriptions-item v-for="(word, index) in semanticWords" :key="index" :label="`语义词 ${index + 1}`">
            <span>{{ word.word || '-' }}</span>
          </a-descriptions-item>
        </a-descriptions>
      </div>
      <div v-else>
        <a-empty description="暂无语义词数据" />
      </div>
    </a-card>
    <!-- 返回按钮 -->
    <div class="action-buttons">
      <a-button type="default" @click="handleBack" class="back-btn">返回</a-button>
    </div>
  </PageWrapper>
</template>
<script lang="ts">
  import { defineComponent, reactive, ref, onMounted } from 'vue';
  import { PageWrapper } from '/@/components/Page';
  import { message } from 'ant-design-vue';
  import { useRoute, useRouter } from 'vue-router';
  import { defHttp } from '/@/utils/http/axios';
  export default defineComponent({
    name: 'FormDetailKehu',
    components: { PageWrapper },
    setup() {
      const route = useRoute();
      const router = useRouter();
      // 初始数据
      const initialData = {
        id: '',
        createTime: '',
        updateBy: null,
        updateTime: null,
        agentsId: null,
        agentsName: null,
        contractFileList: null,
        contractName: '',
        createBy: '',
        customer: {
          id: '',
          createBy: '',
          createTime: '',
          updateBy: null,
          updateTime: null,
          agentsName: null,
          contactPerson: '',
          contract: null,
          customerAddress: '',
          customerEmail: '',
          customerPhone: '',
          enterpriseName: '',
          industry: '',
          semanticWordList: null,
        },
        customerName: '',
        endDate: '',
        rejectionReasons: null,
        reviewStatus: '',
        semanticWordList: null,
        startDate: '',
        sysOrgCode: '',
      };
      // 响应式表单数据
      const formData = reactive({ ...initialData });
      // 语义词列表
      const semanticWords = ref<any[]>([]);
      // 合同文件列表
      const contractFiles = ref<any[]>([]);
      const attachmentFiles = ref<any[]>([]);
      // 加载客户数据
      const loadCustomerData = async () => {
        const id = route.query.id as string;
        if (id) {
          try {
            // 调用API根据id获取客户数据
            const result = await defHttp.get({
              url: '/contract/contract/queryById',
              params: { id },
            });
            console.log('客户详情数据:', result);
            if (result) {
              const customerData = result;
              // 填充表单数据
              Object.assign(formData, customerData);
              // 加载合同文件数据
              await loadContractFiles(id);
              // 加载语义词数据
              await loadSemanticWords(id);
            } else {
              message.error('加载客户详情数据失败');
            }
          } catch (error) {
            console.error('加载客户详情数据失败:', error);
            message.error('加载客户详情数据失败');
          }
        } else {
          message.error('缺少客户ID参数');
        }
      };
      // 加载合同文件数据
      const loadContractFiles = async (id: string) => {
        try {
          const result = await defHttp.get({
            url: '/contract/contract/queryContractFileByMainId',
            params: { id },
          });
          console.log('合同文件数据:', result);
          // 这里可以根据返回的数据结构处理合同文件
          if (result && Array.isArray(result)) {
            // 根据 fileType 区分合同文件和附件
            const contractFileList = [];
            const attachmentFileList = [];
            result.forEach((file: any) => {
              const fileItem = {
                uid: file.id,
                name: file.appendixFile || '文件',
                status: 'done',
                url: file.appendixFile,
              };
              if (file.fileType === '合同文件') {
                contractFileList.push(fileItem);
              } else if (file.fileType === '合同附件') {
                attachmentFileList.push(fileItem);
              }
            });
            contractFiles.value = contractFileList;
            attachmentFiles.value = attachmentFileList;
          }
        } catch (error) {
          console.error('加载合同文件失败:', error);
        }
      };
      // 加载语义词数据
      const loadSemanticWords = async (id: string) => {
        try {
          const result = await defHttp.get({
            url: '/contract/contract/querySemanticWordByMainId',
            params: { id },
          });
          console.log('语义词数据:', result);
          // 这里可以根据返回的数据结构处理语义词
          if (result && Array.isArray(result)) {
            // 将语义词列表保存到响应式变量中
            semanticWords.value = result;
          }
        } catch (error) {
          console.error('加载语义词失败:', error);
        }
      };
      onMounted(() => {
        loadCustomerData();
      });
      // 返回功能
      const handleBack = () => {
        router.back();
      };
      return {
        formData,
        contractFiles,
        attachmentFiles,
        semanticWords,
        handleBack,
      };
    },
  });
</script>
<style lang="less" scoped>
  .desc-wrap {
    padding: 16px;
    background-color: @component-background;
  }
  .action-buttons {
    position: fixed;
    right: 24px;
    bottom: 24px;
    display: flex;
    gap: 12px;
    z-index: 1000;
    .back-btn {
      min-width: 80px;
      height: 40px;
      border-radius: 6px;
      font-weight: 500;
      background-color: #f5f5f5;
      border-color: #d9d9d9;
      color: #666;
      &:hover {
        background-color: #e6f7ff;
        border-color: #40a9ff;
        color: #40a9ff;
      }
    }
  }
</style>