liu
2026-09-29 7a6351a1fa5fc6e67b55c475bcd253d6d3e5d68f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
<script lang="ts" setup>
import type { UmsApplicationApi } from '#/api/ums/application';
import type { DescriptionItemSchema } from '#/components/description';
 
import { computed, h, onMounted, ref } from 'vue';
 
import { ContentWrap } from '@vben/common-ui';
import { DICT_TYPE } from '@vben/constants';
import { formatDateTime } from '@vben/utils';
 
import { Alert, Spin } from 'ant-design-vue';
 
import { getApplication } from '#/api/ums/application';
import { DictTag } from '#/components/dict-tag';
import { useDescription } from '#/components/description';
 
import { ApplicationStatus, MemberType } from '../../data';
 
defineOptions({ name: 'UmsApplicationApproveDetail' });
 
const props = defineProps<{ id: string }>();
 
const loading = ref(false);
const formData = ref<UmsApplicationApi.Application>();
 
/** 文本字段空值占位 */
function textRender(val: unknown) {
  return val === 0 || val ? String(val) : '-';
}
 
/** 申请等级:按会员类型取个人/单位不同的等级字典 */
function getGradeDictType(memberType?: number) {
  return memberType === MemberType.UNIT
    ? DICT_TYPE.UMS_UNIT_GRADE
    : DICT_TYPE.UMS_PERSONAL_GRADE;
}
 
const [Descriptions] = useDescription({
  bordered: true,
  column: 2,
  schema: [
    { label: '申请编号', field: 'no', render: textRender },
    {
      label: '会员类型',
      field: 'memberType',
      render: (val) =>
        h(DictTag, { type: DICT_TYPE.UMS_MEMBER_TYPE, value: val }),
    },
    { label: '申请人/单位名称', field: 'applicantName', render: textRender },
    {
      label: '申请等级',
      field: 'memberGrade',
      render: (val, data) =>
        h(DictTag, {
          type: getGradeDictType(data?.memberType),
          value: val,
        }),
    },
    {
      label: '状态',
      field: 'status',
      render: (val) =>
        h(DictTag, { type: DICT_TYPE.UMS_APPLICATION_STATUS, value: val }),
    },
    { label: '联系电话', field: 'contactPhone', render: textRender },
    { label: '邮箱', field: 'contactEmail', render: textRender },
    {
      label: '研究方向',
      field: 'researchDirection',
      render: textRender,
      span: 2,
    },
    {
      label: '法定代表人',
      field: 'legalPerson',
      render: textRender,
      show: (data) => data?.memberType === MemberType.UNIT,
    },
    {
      label: '统一社会信用代码',
      field: 'organizationCode',
      render: textRender,
      show: (data) => data?.memberType === MemberType.UNIT,
    },
    {
      label: '工作单位',
      field: 'workUnit',
      render: textRender,
      show: (data) => data?.memberType === MemberType.PERSONAL,
    },
    {
      label: '职称',
      field: 'title',
      render: textRender,
      show: (data) => data?.memberType === MemberType.PERSONAL,
    },
    {
      label: '地区编码',
      field: 'regionCode',
      render: textRender,
    },
    {
      label: '行业',
      field: 'industry',
      render: (val) => h(DictTag, { type: DICT_TYPE.UMS_INDUSTRY, value: val }),
    },
    { label: '创建人', field: 'creatorName', render: textRender },
    {
      label: '创建时间',
      field: 'createTime',
      render: (val) => (val ? (formatDateTime(val) as string) : '-'),
    },
    { label: '备注', field: 'remark', render: textRender, span: 2 },
  ] as DescriptionItemSchema[],
});
 
/** 账号凭据提醒:审批中提示审批人核对联系电话,通过后提示账号已开通及初始密码 */
const credentialTip = computed(() => {
  const status = formData.value?.status;
  const phone = formData.value?.contactPhone;
  if (status === ApplicationStatus.APPROVING) {
    return {
      type: 'warning' as const,
      message: `审批通过后将自动为申请人创建系统登录账号(用户名与初始密码均为联系电话 ${phone || '未填写'}),请先核对联系电话是否准确后再通过。`,
    };
  }
  if (status === ApplicationStatus.APPROVED) {
    if (!phone) {
      return {
        type: 'warning' as const,
        message:
          '未填写联系电话,账号用户名/密码使用了兜底值 unknown,请到会员列表核实并手工修正。',
      };
    }
    return {
      type: 'success' as const,
      message: `系统登录账号已自动开通:用户名 ${phone},初始密码 ${phone}。请通知申请人尽快登录并修改密码。`,
    };
  }
  return null;
});
 
onMounted(async () => {
  try {
    loading.value = true;
    formData.value = await getApplication(Number(props.id));
  } finally {
    loading.value = false;
  }
});
</script>
 
<template>
  <ContentWrap class="m-2">
    <Spin :spinning="loading" tip="加载中...">
      <div class="space-y-4">
        <!-- 账号凭据提醒 -->
        <Alert
          v-if="credentialTip"
          :type="credentialTip.type"
          :message="credentialTip.message"
          show-icon
        />
        <!-- 入会申请基本信息 -->
        <div class="rounded-lg border border-border bg-background p-4">
          <div class="mb-4 flex items-center gap-2">
            <span class="inline-block h-4 w-1 rounded bg-primary" />
            <span class="text-base font-semibold">入会申请基本信息</span>
          </div>
          <Descriptions :data="formData" />
        </div>
        <!-- 证明材料附件 -->
        <div
          v-if="formData?.attachmentList?.length"
          class="rounded-lg border border-border bg-background p-4"
        >
          <div class="mb-4 flex items-center gap-2">
            <span class="inline-block h-4 w-1 rounded bg-primary" />
            <span class="text-base font-semibold">证明材料附件</span>
          </div>
          <div class="flex flex-wrap gap-3">
            <a
              v-for="file in formData.attachmentList"
              :key="file.id"
              :href="file.previewURL || file.url"
              target="_blank"
              class="text-blue-500 hover:underline"
            >
              {{ file.name || file.originalFilename || `附件-${file.id}` }}
            </a>
          </div>
        </div>
      </div>
    </Spin>
  </ContentWrap>
</template>