Gqingci 19 часов назад
Родитель
Сommit
f974248dfb

+ 3 - 0
.env.development

@@ -38,3 +38,6 @@ VITE_APP_SSE = true
 
 # 平台号
 VITE_APP_PLATFORM_CODE="PINGTAIDUAN"
+
+# 门户地址
+VITE_PORTAL_BASE_URL=http://localhost:3000/

+ 3 - 0
.env.production

@@ -37,3 +37,6 @@ VITE_APP_WEBSOCKET = false
 
 # sse 开关
 VITE_APP_SSE = true
+
+# 门户地址
+VITE_PORTAL_BASE_URL=

+ 8 - 0
src/api/system/backRecord/types.ts

@@ -2,11 +2,18 @@
  * 背调执行记录(候选人)相关类型定义
  */
 
+export interface CompanyInfo {
+  id: number;
+  name: string;
+  status: string;
+}
+
 export interface BackRecordVO {
   id: string | number;
   orderId: string | number;
   candidateId: string | number;
   status: string;
+  reportStatus?: number;
   reportUrl?: string;
   finishTime?: string;
   createTime?: string;
@@ -17,6 +24,7 @@ export interface BackRecordVO {
   studentGender?: string;
   studentStatus?: string;
   studentUserType?: string;
+  companies?: CompanyInfo[];
 }
 
 export interface BackRecordQuery {

+ 8 - 1
src/views/system/backcheck/BackgroundCheckForm.vue

@@ -283,7 +283,7 @@
           </table>
         </div>
 
-        <div class="form-actions" v-if="!props.recordId || currentReportStatus < 2">
+        <div class="form-actions" v-if="showAuditActions">
           <template v-if="props.recordId">
             <el-button type="primary" size="large" class="submit-btn" :loading="submitting" @click="handleSubmit(2)">
               审核通过
@@ -338,6 +338,13 @@ const currentReportStatus = computed(() => {
   return formReportStatus.value;
 });
 
+const showAuditActions = computed(() => {
+  if (!props.recordId) {
+    return true;
+  }
+  return currentReportStatus.value === 1;
+});
+
 const form = ref({
   candidateName: '',
   applyPosition: '',

+ 87 - 7
src/views/system/backcheck/candidateList.vue

@@ -57,7 +57,7 @@
         <el-table-column label="状态" min-width="100">
           <template #default="scope">
             <div class="flex items-center">
-              <span :class="['status-dot', scope.row.status === '完成' ? 'dot-success' : 'dot-danger']"></span>
+              <span :class="['status-dot', isCompletedStatus(scope.row.status) ? 'dot-success' : 'dot-danger']"></span>
               <span>{{ scope.row.status }}</span>
             </div>
           </template>
@@ -86,22 +86,29 @@
               <el-link type="primary" :underline="false" @click="handleDetail(scope.row)">详情</el-link>
               
               <!-- 情况1:完成状态 -> 显示打款 -->
-              <template v-if="scope.row.status === '完成'">
+              <template v-if="canShowPay(scope.row)">
                 <el-link type="primary" :underline="false" @click="openPayDialog(scope.row)">打款</el-link>
               </template>
 
               <!-- 情况2:未完成且有待审核公司 -> 显示审核通过/拒绝、退款 -->
-              <template v-else-if="scope.row.status === '未完成' && scope.row.companies && scope.row.companies.length > 0">
+              <template v-else-if="canAudit(scope.row) && scope.row.companies && scope.row.companies.length > 0">
+                <el-link type="primary" :underline="false" @click="copyCheckLink(scope.row)">复制背调链接</el-link>
                 <el-link type="primary" :underline="false" @click="handleAudit(scope.row, '通过')">审核通过</el-link>
                 <el-link type="primary" :underline="false" @click="handleAudit(scope.row, '拒绝')">审核拒绝</el-link>
-                <el-link type="danger" :underline="false" @click="handleRefund(scope.row)">退款</el-link>
               </template>
 
               <!-- 情况3:未完成且无供职公司 -> 显示开始核验、退款 -->
-              <template v-else-if="scope.row.status === '未完成'">
+              <template v-else-if="canCopyCheckLink(scope.row)">
+                <el-link type="primary" :underline="false" @click="copyCheckLink(scope.row)">复制背调链接</el-link>
                 <el-link type="primary" :underline="false" @click="handleStartCheck(scope.row)">开始核验</el-link>
-                <el-link type="danger" :underline="false" @click="handleRefund(scope.row)">退款</el-link>
               </template>
+
+              <el-link
+                v-if="canShowRefund(scope.row)"
+                type="danger"
+                :underline="false"
+                @click="handleRefund(scope.row)"
+              >退款</el-link>
             </div>
           </template>
         </el-table-column>
@@ -197,6 +204,11 @@ import { BackRecordVO } from '@/api/system/backRecord/types';
 
 const route = useRoute();
 const router = useRouter();
+const portalBaseUrl = (
+  import.meta.env.VITE_PORTAL_BASE_URL ||
+  import.meta.env.VITE_PORTAL_URL ||
+  ''
+).replace(/\/$/, '');
 
 const loading = ref(false);
 const total = ref(0);
@@ -296,7 +308,13 @@ const getList = async () => {
           showIdNo: false,
           mobile: record.studentMobile || '****',
           status: statusMap[record.status] || record.status,
-          companies: [],
+          rawStatus: record.status,
+          reportStatus: record.reportStatus,
+          companies: (record.companies || []).map((c: any) => ({
+            id: c.id,
+            name: c.name,
+            status: c.status
+          })),
           finishTime: record.finishTime || '-',
           reportUrl: record.reportUrl,
           createTime: record.createTime
@@ -365,6 +383,18 @@ const handleTagClick = (comp: any, row: any) => {
   }
 };
 
+const isCompletedStatus = (status: string) => status === '已完成';
+
+const canCopyCheckLink = (row: any) => {
+  return !isCompletedStatus(row.status) && row.status !== '失败';
+};
+
+const canAudit = (row: any) => row.reportStatus === 1;
+
+const canShowRefund = (row: any) => row.reportStatus === 3;
+
+const canShowPay = (row: any) => row.reportStatus === 2;
+
 const handleAudit = (row: any, type: string, comp?: any) => {
   rejectDialog.form.id = row.id;
   rejectDialog.form.result = type;
@@ -374,6 +404,56 @@ const handleAudit = (row: any, type: string, comp?: any) => {
   rejectDialog.visible = true;
 };
 
+const fallbackCopyText = (text: string) => {
+  const textarea = document.createElement('textarea');
+  const previousActiveElement = document.activeElement as HTMLElement | null;
+
+  textarea.value = text;
+  textarea.setAttribute('readonly', '');
+  textarea.style.position = 'absolute';
+  textarea.style.left = '-9999px';
+  textarea.style.fontSize = '12pt';
+
+  document.body.appendChild(textarea);
+  textarea.select();
+  textarea.selectionStart = 0;
+  textarea.selectionEnd = text.length;
+
+  let copied = false;
+  try {
+    copied = document.execCommand('copy');
+  } catch (error) {
+    console.error('execCommand 复制失败:', error);
+  }
+
+  document.body.removeChild(textarea);
+  previousActiveElement?.focus();
+  return copied;
+};
+
+const copyCheckLink = async (row: any) => {
+  const targetOrigin = portalBaseUrl || window.location.origin;
+  const routePath = `/background-check/form?recordId=${row.id}&candidateId=${row.candidateId || row.id}&candidateName=${encodeURIComponent(row.name || '')}`;
+  const fullUrl = `${targetOrigin}${routePath}`;
+
+  try {
+    if (navigator.clipboard?.writeText) {
+      await navigator.clipboard.writeText(fullUrl);
+    } else if (!fallbackCopyText(fullUrl)) {
+      throw new Error('Clipboard API unavailable');
+    }
+    ElMessage.success('背调表单链接已复制到剪贴板,请发送给上家公司填写');
+  } catch (error) {
+    const copied = fallbackCopyText(fullUrl);
+    if (copied) {
+      ElMessage.success('背调表单链接已复制到剪贴板,请发送给上家公司填写');
+      return;
+    }
+    console.error('复制背调链接失败:', error);
+    ElMessage.error(`复制失败,请手动复制:${fullUrl}`);
+  }
+};
+
 const handleStartCheck = (row: any) => {
   ElMessage.success(`已为候选人 ${row.name} 开始核验`);
 };