931 lines
28 KiB
Vue
931 lines
28 KiB
Vue
<template>
|
||
<a-drawer
|
||
placement="right"
|
||
width="80%"
|
||
:visible="visible"
|
||
:title="isUpdate ? '编辑' : '新增'"
|
||
:body-style="{ paddingBottom: '88px' }"
|
||
@update:visible="updateVisible"
|
||
>
|
||
<a-form ref="formRef" :model="form">
|
||
<a-form-item
|
||
label="年份"
|
||
name="year"
|
||
:rules="[{ required: true, message: '请选择年份' }]"
|
||
>
|
||
<a-date-picker
|
||
v-model:value="form.year"
|
||
picker="year"
|
||
value-format="YYYY"
|
||
style="width: 240px"
|
||
:disabled="!!props.fixedYear"
|
||
placeholder="请选择年份"
|
||
/>
|
||
</a-form-item>
|
||
<a-tabs v-model:activeKey="activeTab" type="card" class="gxmu-tag-tabs">
|
||
<a-tab-pane key="base" tab="项目申报表">
|
||
<div class="sheet-wrap">
|
||
<div class="sheet-header">
|
||
<div class="sheet-tag">附件 1</div>
|
||
<div class="sheet-main-title"
|
||
>{{ title || '' }}参赛项目申报表</div
|
||
>
|
||
</div>
|
||
<table class="sheet-table">
|
||
<colgroup>
|
||
<col style="width: 18%" />
|
||
<col style="width: 32%" />
|
||
<col style="width: 18%" />
|
||
<col style="width: 32%" />
|
||
</colgroup>
|
||
<tbody>
|
||
<tr>
|
||
<td class="sheet-label">所在省<br />(区、市)</td>
|
||
<td class="sheet-value">
|
||
<a-input
|
||
v-model:value="form.provinceCity"
|
||
placeholder="请输入所在省/市"
|
||
/>
|
||
</td>
|
||
<td class="sheet-label">学校名称<br />(全称)</td>
|
||
<td class="sheet-value">
|
||
<a-input
|
||
v-model:value="form.schoolName"
|
||
placeholder="请输入学校名称"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">项目名称</td>
|
||
<td class="sheet-value left" colspan="3">
|
||
<a-input
|
||
v-model:value="form.projectName"
|
||
placeholder="请输入项目名称"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">项目类型</td>
|
||
<td class="sheet-value left" colspan="3">
|
||
<a-radio-group
|
||
v-model:value="form.projectType"
|
||
class="inline-radio"
|
||
>
|
||
<a-radio
|
||
v-for="item in formProjectTypeOptions"
|
||
:key="`base-type-${item.value}`"
|
||
:value="item.value"
|
||
>
|
||
{{ item.label }}
|
||
</a-radio>
|
||
</a-radio-group>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">
|
||
项目分组
|
||
<div class="sheet-note"
|
||
>(仅可选择1个组别,须在此栏中删除其他组别内容)</div
|
||
>
|
||
</td>
|
||
<td class="sheet-value left" colspan="3">
|
||
<a-radio-group
|
||
v-model:value="form.projectGroup"
|
||
class="group-radio"
|
||
>
|
||
<a-radio
|
||
v-for="item in formProjectGroupOptions"
|
||
:key="`base-group-${item.value}`"
|
||
:value="item.value"
|
||
>
|
||
{{ item.label }}
|
||
</a-radio>
|
||
</a-radio-group>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<table class="sheet-table">
|
||
<colgroup>
|
||
<col style="width: 14%" />
|
||
<col style="width: 12%" />
|
||
<col style="width: 10%" />
|
||
<col style="width: 16%" />
|
||
<col style="width: 18%" />
|
||
<col style="width: 12%" />
|
||
<col style="width: 18%" />
|
||
</colgroup>
|
||
<tbody>
|
||
<tr>
|
||
<td class="sheet-label" :rowspan="teamMembersCount + 1"
|
||
>团队成员<br />(最多15人)</td
|
||
>
|
||
<td class="sheet-label">姓名</td>
|
||
<td class="sheet-label">性别</td>
|
||
<td class="sheet-label">学院</td>
|
||
<td class="sheet-label">年级、专业</td>
|
||
<td class="sheet-label">手机</td>
|
||
<td class="sheet-label"
|
||
>备注(负责人及各成员学历-本/硕/博)</td
|
||
>
|
||
</tr>
|
||
<tr
|
||
v-for="(item, index) in form.teamMembers"
|
||
:key="`member-${index}`"
|
||
>
|
||
<td class="sheet-value"
|
||
><a-input v-model:value="item.name"
|
||
/></td>
|
||
<td class="sheet-value">
|
||
<a-select style="width: 120px"
|
||
v-model:value="item.gender"
|
||
:options="genderOptions"
|
||
placeholder="请选择"
|
||
/>
|
||
</td>
|
||
<td class="sheet-value">
|
||
<a-select style="width: 120px"
|
||
allow-clear
|
||
show-search
|
||
v-model:value="item.college"
|
||
:options="collegeOptions"
|
||
:filter-option="filterSelectOption"
|
||
placeholder="请选择"
|
||
/>
|
||
</td>
|
||
<td class="sheet-value"
|
||
><a-input v-model:value="item.gradeMajor"
|
||
/></td>
|
||
<td class="sheet-value"
|
||
><a-input v-model:value="item.phone"
|
||
/></td>
|
||
<td class="sheet-value"
|
||
><a-input v-model:value="item.remark"
|
||
/></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<table class="sheet-table">
|
||
<colgroup>
|
||
<col style="width: 14%" />
|
||
<col style="width: 12%" />
|
||
<col style="width: 10%" />
|
||
<col style="width: 16%" />
|
||
<col style="width: 18%" />
|
||
<col style="width: 16%" />
|
||
<col style="width: 14%" />
|
||
</colgroup>
|
||
<tbody>
|
||
<tr>
|
||
<td class="sheet-label" :rowspan="advisorCount + 1"
|
||
>指导教师<br />(最多5人)</td
|
||
>
|
||
<td class="sheet-label">姓名</td>
|
||
<td class="sheet-label">性别</td>
|
||
<td class="sheet-label">学院</td>
|
||
<td class="sheet-label">职称</td>
|
||
<td class="sheet-label">职务</td>
|
||
<td class="sheet-label">手机</td>
|
||
</tr>
|
||
<tr
|
||
v-for="(item, index) in form.advisors"
|
||
:key="`advisor-${index}`"
|
||
>
|
||
<td class="sheet-value"
|
||
><a-input v-model:value="item.name"
|
||
/></td>
|
||
<td class="sheet-value">
|
||
<a-select style="width: 120px"
|
||
v-model:value="item.gender"
|
||
:options="genderOptions"
|
||
placeholder="请选择"
|
||
/>
|
||
</td>
|
||
<td class="sheet-value">
|
||
<a-select style="width: 120px"
|
||
allow-clear
|
||
show-search
|
||
v-model:value="item.college"
|
||
:options="collegeOptions"
|
||
:filter-option="filterSelectOption"
|
||
placeholder="请选择"
|
||
/>
|
||
</td>
|
||
<td class="sheet-value"
|
||
><a-input v-model:value="item.title"
|
||
/></td>
|
||
<td class="sheet-value"
|
||
><a-input v-model:value="item.duty"
|
||
/></td>
|
||
<td class="sheet-value"
|
||
><a-input v-model:value="item.phone"
|
||
/></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<table class="sheet-table">
|
||
<colgroup>
|
||
<col style="width: 18%" />
|
||
<col style="width: 82%" />
|
||
</colgroup>
|
||
<tbody>
|
||
<tr>
|
||
<td class="sheet-label">项目简介<br />(500字以内)</td>
|
||
<td class="sheet-value left">
|
||
<a-textarea
|
||
v-model:value="form.projectBrief"
|
||
:rows="4"
|
||
placeholder="请输入项目简介"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</a-tab-pane>
|
||
<a-tab-pane key="detail" tab="项目说明">
|
||
<div class="sheet-wrap">
|
||
<table class="sheet-table">
|
||
<colgroup>
|
||
<col style="width: 18%" />
|
||
<col style="width: 82%" />
|
||
</colgroup>
|
||
<tbody>
|
||
<tr>
|
||
<td class="sheet-label">社会价值<br />(500字以内)</td>
|
||
<td class="sheet-value left">
|
||
<a-textarea
|
||
v-model:value="form.socialValue"
|
||
:rows="4"
|
||
placeholder="请输入社会价值"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">实践过程<br />(500字以内)</td>
|
||
<td class="sheet-value left">
|
||
<a-textarea
|
||
v-model:value="form.practiceProcess"
|
||
:rows="4"
|
||
placeholder="请输入实践过程"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">创新意义<br />(500字以内)</td>
|
||
<td class="sheet-value left">
|
||
<a-textarea
|
||
v-model:value="form.innovationMeaning"
|
||
:rows="4"
|
||
placeholder="请输入创新意义"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">发展前景<br />(500字以内)</td>
|
||
<td class="sheet-value left">
|
||
<a-textarea
|
||
v-model:value="form.developmentProspect"
|
||
:rows="4"
|
||
placeholder="请输入发展前景"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">团队协作<br />(500字以内)</td>
|
||
<td class="sheet-value left">
|
||
<a-textarea
|
||
v-model:value="form.teamCooperation"
|
||
:rows="4"
|
||
placeholder="请输入团队协作"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">项目介绍材料</td>
|
||
<td class="sheet-value left">
|
||
<a-textarea
|
||
v-model:value="form.projectMaterials"
|
||
:rows="3"
|
||
placeholder="请输入项目介绍材料"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">其他相关证明材料</td>
|
||
<td class="sheet-value left">
|
||
<a-textarea
|
||
v-model:value="form.otherProofs"
|
||
:rows="3"
|
||
placeholder="选报,所有其他相关证明材料需扫描在同一 PDF 文档中"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</a-tab-pane>
|
||
<a-tab-pane key="public" tab="公开展示信息表">
|
||
<div class="sheet-wrap">
|
||
<div class="public-title">
|
||
<div class="public-tag">附件 2</div>
|
||
<div class="public-main-title"
|
||
>{{ title || '' }}参赛项目公开展示信息表</div
|
||
>
|
||
</div>
|
||
<table class="sheet-table">
|
||
<colgroup>
|
||
<col style="width: 18%" />
|
||
<col style="width: 82%" />
|
||
</colgroup>
|
||
<tbody>
|
||
<tr>
|
||
<td class="sheet-label">项目名称</td>
|
||
<td class="sheet-value left">
|
||
<a-input
|
||
v-model:value="form.projectName"
|
||
placeholder="请输入项目名称"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">参赛学校</td>
|
||
<td class="sheet-value left">
|
||
<a-input
|
||
v-model:value="form.schoolName"
|
||
placeholder="请输入参赛学校"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">项目类型</td>
|
||
<td class="sheet-value left">
|
||
<a-radio-group
|
||
v-model:value="form.publicProjectType"
|
||
class="inline-radio"
|
||
>
|
||
<a-radio
|
||
v-for="item in publicProjectTypeOptions"
|
||
:key="`public-type-${item.value}`"
|
||
:value="item.value"
|
||
>
|
||
{{ item.label }}
|
||
</a-radio>
|
||
</a-radio-group>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">项目分组</td>
|
||
<td class="sheet-value left">
|
||
<a-radio-group
|
||
v-model:value="form.publicProjectGroup"
|
||
class="group-radio"
|
||
>
|
||
<a-radio
|
||
v-for="item in publicProjectGroupOptions"
|
||
:key="`public-group-${item.value}`"
|
||
:value="item.value"
|
||
>
|
||
{{ item.label }}
|
||
</a-radio>
|
||
</a-radio-group>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">我们的项目</td>
|
||
<td class="sheet-value left">
|
||
<a-textarea
|
||
v-model:value="form.projectSummary"
|
||
:rows="3"
|
||
placeholder="150字以内,阐述项目的实践来源、社会背景、基本情况等"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">我们的团队</td>
|
||
<td class="sheet-value left">
|
||
<div class="media-upload-block">
|
||
<div v-if="form.teamIntro" class="media-preview-wrap">
|
||
<img
|
||
class="media-image"
|
||
:src="form.teamIntro"
|
||
alt="团队图片"
|
||
/>
|
||
</div>
|
||
<div v-else class="media-empty">请上传团队图片</div>
|
||
<div class="media-actions">
|
||
<a-upload
|
||
:show-upload-list="false"
|
||
accept="image/*"
|
||
:customRequest="uploadTeamImage"
|
||
>
|
||
<a-button type="primary">上传图片</a-button>
|
||
</a-upload>
|
||
<a-button v-if="form.teamIntro" @click="form.teamIntro = ''">
|
||
移除
|
||
</a-button>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">我们的口号</td>
|
||
<td class="sheet-value left">
|
||
<a-input
|
||
v-model:value="form.teamSlogan"
|
||
placeholder="20字以内"
|
||
/>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td class="sheet-label">我们的实践日志(选填)</td>
|
||
<td class="sheet-value left">
|
||
<div class="media-upload-block">
|
||
<div v-if="form.practiceLog" class="media-preview-wrap media-preview-wrap--video">
|
||
<video class="media-video" :src="form.practiceLog" controls></video>
|
||
</div>
|
||
<div v-else class="media-empty">请上传实践日志视频</div>
|
||
<div class="media-actions">
|
||
<a-upload
|
||
:show-upload-list="false"
|
||
accept="video/*"
|
||
:customRequest="uploadPracticeVideo"
|
||
>
|
||
<a-button type="primary">上传视频</a-button>
|
||
</a-upload>
|
||
<a-button v-if="form.practiceLog" @click="form.practiceLog = ''">
|
||
移除
|
||
</a-button>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</a-tab-pane>
|
||
</a-tabs>
|
||
</a-form>
|
||
<div class="drawer-footer">
|
||
<a-space>
|
||
<a-button @click="updateVisible(false)">取消</a-button>
|
||
<a-button type="primary" :loading="loading" @click="save"
|
||
>保存</a-button
|
||
>
|
||
</a-space>
|
||
</div>
|
||
</a-drawer>
|
||
</template>
|
||
|
||
<script lang="ts" setup>
|
||
import { computed, reactive, ref, watch } from 'vue';
|
||
import { message } from 'ant-design-vue';
|
||
import { addTzbcyForm, updateTzbcyForm } from '@/api/gxmu/tzbcy-form';
|
||
import { uploadFile } from '@/api/system/file';
|
||
import type {
|
||
TzbcyAdvisor,
|
||
TzbcyForm,
|
||
TzbcyTeamMember
|
||
} from '@/api/gxmu/tzbcy-form/model';
|
||
import {
|
||
filterSelectOption,
|
||
useGxmuFormSelectOptions
|
||
} from '@/views/gxmu/useFormSelectOptions';
|
||
import {
|
||
TZBCY_PROJECT_GROUP_OPTIONS,
|
||
TZBCY_PROJECT_TYPE_OPTIONS
|
||
} from '../options';
|
||
|
||
interface ChoiceOption {
|
||
label: string;
|
||
value: string;
|
||
}
|
||
|
||
const emit = defineEmits<{
|
||
(e: 'done'): void;
|
||
(e: 'update:visible', visible: boolean): void;
|
||
}>();
|
||
|
||
const props = defineProps<{
|
||
visible: boolean;
|
||
data?: TzbcyForm | null;
|
||
title?: string;
|
||
fixedYear?: string | number;
|
||
declareFormProjectTypes?: string[];
|
||
declareFormProjectGroups?: string[];
|
||
declarePublicProjectTypes?: string[];
|
||
declarePublicProjectGroups?: string[];
|
||
}>();
|
||
|
||
const formRef = ref();
|
||
const loading = ref(false);
|
||
const isUpdate = ref(false);
|
||
const activeTab = ref('base');
|
||
const { genderOptions, collegeOptions, loadCollegeOptions } =
|
||
useGxmuFormSelectOptions();
|
||
|
||
const createTeamMember = (): TzbcyTeamMember => ({
|
||
name: '',
|
||
gender: '',
|
||
college: '',
|
||
gradeMajor: '',
|
||
phone: '',
|
||
remark: ''
|
||
});
|
||
|
||
const createAdvisor = (): TzbcyAdvisor => ({
|
||
name: '',
|
||
gender: '',
|
||
college: '',
|
||
title: '',
|
||
duty: '',
|
||
phone: ''
|
||
});
|
||
|
||
const createDefaultForm = (): TzbcyForm => ({
|
||
id: undefined,
|
||
year: '',
|
||
provinceCity: '',
|
||
schoolName: '广西医科大学',
|
||
projectName: '',
|
||
projectType: '',
|
||
projectGroup: '',
|
||
publicProjectType: '',
|
||
publicProjectGroup: '',
|
||
leader: '',
|
||
phone: '',
|
||
teamMembers: Array.from({ length: 15 }).map(() => createTeamMember()),
|
||
advisors: Array.from({ length: 5 }).map(() => createAdvisor()),
|
||
projectBrief: '',
|
||
socialValue: '',
|
||
practiceProcess: '',
|
||
innovationMeaning: '',
|
||
developmentProspect: '',
|
||
teamCooperation: '',
|
||
projectMaterials: '',
|
||
otherProofs: '',
|
||
projectSummary: '',
|
||
teamIntro: '',
|
||
teamSlogan: '',
|
||
practiceLog: ''
|
||
});
|
||
|
||
const fillList = <T extends Record<string, unknown>>(
|
||
list: T[] | undefined,
|
||
count: number,
|
||
createItem: () => T
|
||
) => {
|
||
const source = list?.map((item) => ({ ...createItem(), ...item })) ?? [];
|
||
return Array.from({ length: count }).map(
|
||
(_, index) => source[index] ?? createItem()
|
||
);
|
||
};
|
||
|
||
const normalizeForm = (record?: TzbcyForm | null): TzbcyForm => {
|
||
const defaults = createDefaultForm();
|
||
if (!record) {
|
||
return defaults;
|
||
}
|
||
const normalizedProjectType = record.projectType || '';
|
||
const normalizedProjectGroup = record.projectGroup || '';
|
||
return {
|
||
...defaults,
|
||
...record,
|
||
projectType: normalizedProjectType,
|
||
projectGroup: normalizedProjectGroup,
|
||
publicProjectType: record.publicProjectType || normalizedProjectType,
|
||
publicProjectGroup: record.publicProjectGroup || normalizedProjectGroup,
|
||
teamMembers: fillList(record.teamMembers, 15, createTeamMember),
|
||
advisors: fillList(record.advisors, 5, createAdvisor)
|
||
};
|
||
};
|
||
|
||
const form = reactive<TzbcyForm>(createDefaultForm());
|
||
|
||
const teamMembersCount = computed(() => form.teamMembers?.length || 0);
|
||
const advisorCount = computed(() => form.advisors?.length || 0);
|
||
|
||
const buildChoiceOptions = (
|
||
customValues: string[] | undefined,
|
||
fallback: readonly ChoiceOption[],
|
||
currentValue?: string
|
||
): ChoiceOption[] => {
|
||
const values = (customValues?.length
|
||
? customValues
|
||
: fallback.map((item) => item.value)
|
||
)
|
||
.map((item) => item.trim())
|
||
.filter((item, index, arr) => !!item && arr.indexOf(item) === index);
|
||
|
||
if (currentValue?.trim() && !values.includes(currentValue.trim())) {
|
||
values.push(currentValue.trim());
|
||
}
|
||
|
||
return values.map((value) => {
|
||
const matched = fallback.find((item) => item.value === value);
|
||
return {
|
||
label: matched?.label ?? value,
|
||
value
|
||
};
|
||
});
|
||
};
|
||
|
||
const formProjectTypeOptions = computed(() =>
|
||
buildChoiceOptions(
|
||
props.declareFormProjectTypes,
|
||
TZBCY_PROJECT_TYPE_OPTIONS,
|
||
form.projectType
|
||
)
|
||
);
|
||
const formProjectGroupOptions = computed(() =>
|
||
buildChoiceOptions(
|
||
props.declareFormProjectGroups,
|
||
TZBCY_PROJECT_GROUP_OPTIONS,
|
||
form.projectGroup
|
||
)
|
||
);
|
||
const publicProjectTypeOptions = computed(() =>
|
||
buildChoiceOptions(
|
||
props.declarePublicProjectTypes,
|
||
TZBCY_PROJECT_TYPE_OPTIONS,
|
||
form.publicProjectType
|
||
)
|
||
);
|
||
const publicProjectGroupOptions = computed(() =>
|
||
buildChoiceOptions(
|
||
props.declarePublicProjectGroups,
|
||
TZBCY_PROJECT_GROUP_OPTIONS,
|
||
form.publicProjectGroup
|
||
)
|
||
);
|
||
|
||
watch(
|
||
() => props.visible,
|
||
async (visible) => {
|
||
if (visible) {
|
||
try {
|
||
await loadCollegeOptions();
|
||
} catch (e: any) {
|
||
message.error(e.message || '下拉选项加载失败');
|
||
}
|
||
isUpdate.value = !!props.data?.id;
|
||
Object.assign(form, normalizeForm(props.data));
|
||
if (props.fixedYear) {
|
||
form.year = String(props.fixedYear);
|
||
}
|
||
} else {
|
||
formRef.value?.resetFields?.();
|
||
Object.assign(form, createDefaultForm());
|
||
}
|
||
activeTab.value = 'base';
|
||
}
|
||
);
|
||
|
||
const updateVisible = (value: boolean) => {
|
||
emit('update:visible', value);
|
||
};
|
||
|
||
const syncLeaderInfo = () => {
|
||
const firstMember = form.teamMembers?.find(
|
||
(item) => item.name?.trim() || item.phone?.trim()
|
||
);
|
||
form.leader = firstMember?.name?.trim() || '';
|
||
form.phone = firstMember?.phone?.trim() || '';
|
||
};
|
||
|
||
const save = () => {
|
||
syncLeaderInfo();
|
||
loading.value = true;
|
||
const saveOrUpdate = isUpdate.value ? updateTzbcyForm : addTzbcyForm;
|
||
saveOrUpdate({
|
||
...form,
|
||
year: props.fixedYear ? String(props.fixedYear) : form.year
|
||
})
|
||
.then((msg) => {
|
||
loading.value = false;
|
||
message.success(msg);
|
||
updateVisible(false);
|
||
emit('done');
|
||
})
|
||
.catch((e) => {
|
||
loading.value = false;
|
||
message.error(e.message);
|
||
});
|
||
};
|
||
|
||
const uploadTeamImage = (item) => {
|
||
const file = item.file as File;
|
||
if (!file.type.startsWith('image/')) {
|
||
message.error('请上传图片文件');
|
||
return;
|
||
}
|
||
uploadFile(file)
|
||
.then((data) => {
|
||
form.teamIntro = String(data.url || '');
|
||
message.success('图片上传成功');
|
||
})
|
||
.catch((e) => {
|
||
message.error(e.message);
|
||
});
|
||
};
|
||
|
||
const uploadPracticeVideo = (item) => {
|
||
const file = item.file as File;
|
||
if (!file.type.startsWith('video/')) {
|
||
message.error('请上传视频文件');
|
||
return;
|
||
}
|
||
uploadFile(file)
|
||
.then((data) => {
|
||
form.practiceLog = String(data.url || '');
|
||
message.success('视频上传成功');
|
||
})
|
||
.catch((e) => {
|
||
message.error(e.message);
|
||
});
|
||
};
|
||
</script>
|
||
|
||
<style lang="less" scoped>
|
||
@import '../../form-theme.less';
|
||
@import '../../tag-tabs.less';
|
||
|
||
.gxmu-field-theme();
|
||
.gxmu-tag-tabs();
|
||
|
||
.sheet-wrap {
|
||
border: 1px solid #d9d9d9;
|
||
padding: 12px;
|
||
background: #fff;
|
||
}
|
||
|
||
.sheet-header {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.sheet-tag {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.sheet-main-title {
|
||
font-size: 28px;
|
||
font-weight: 700;
|
||
text-align: center;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.sheet-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
table-layout: fixed;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.sheet-table td {
|
||
border: 1px solid #3b3b3b;
|
||
padding: 8px 6px;
|
||
font-size: 13px;
|
||
text-align: center;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
.sheet-label {
|
||
font-weight: 600;
|
||
text-align: center;
|
||
}
|
||
|
||
.sheet-note {
|
||
font-weight: 400;
|
||
font-size: 12px;
|
||
color: #444;
|
||
margin-top: 6px;
|
||
line-height: 1.8;
|
||
}
|
||
|
||
.sheet-value {
|
||
text-align: center;
|
||
}
|
||
|
||
.sheet-value.left {
|
||
text-align: left;
|
||
}
|
||
|
||
.sheet-table .sheet-value :deep(.ant-input),
|
||
.sheet-table .sheet-value :deep(.ant-select-selector),
|
||
.sheet-table .sheet-value :deep(.ant-radio-group),
|
||
.sheet-table .sheet-value :deep(.ant-input-textarea),
|
||
.sheet-table .sheet-value :deep(.ant-input-affix-wrapper) {
|
||
border: 0;
|
||
box-shadow: none;
|
||
padding: 0;
|
||
background: transparent;
|
||
}
|
||
|
||
.sheet-table .sheet-value :deep(.ant-input) {
|
||
text-align: center;
|
||
}
|
||
|
||
.sheet-table .sheet-value.left :deep(.ant-input),
|
||
.sheet-table .sheet-value.left :deep(.ant-input-textarea) {
|
||
text-align: left;
|
||
}
|
||
|
||
.sheet-table .sheet-value :deep(textarea.ant-input) {
|
||
resize: none;
|
||
}
|
||
|
||
.inline-radio :deep(.ant-radio) {
|
||
margin-right: 12px;
|
||
}
|
||
|
||
.group-radio {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 6px;
|
||
}
|
||
|
||
.media-upload-block {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
}
|
||
|
||
.media-preview-wrap {
|
||
width: 100%;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
background: #f5f7fa;
|
||
}
|
||
|
||
.media-preview-wrap--video {
|
||
background: #111827;
|
||
}
|
||
|
||
.media-image {
|
||
width: 100%;
|
||
max-height: 220px;
|
||
object-fit: cover;
|
||
display: block;
|
||
}
|
||
|
||
.media-video {
|
||
width: 100%;
|
||
max-height: 260px;
|
||
display: block;
|
||
}
|
||
|
||
.media-empty {
|
||
padding: 24px 12px;
|
||
border-radius: 8px;
|
||
background: #f5f7fa;
|
||
color: #909399;
|
||
text-align: center;
|
||
}
|
||
|
||
.media-actions {
|
||
display: flex;
|
||
gap: 12px;
|
||
align-items: center;
|
||
}
|
||
|
||
.public-title {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.public-tag {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.public-main-title {
|
||
font-size: 28px;
|
||
font-weight: 700;
|
||
text-align: center;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.drawer-footer {
|
||
position: absolute;
|
||
right: 0;
|
||
bottom: 0;
|
||
width: 100%;
|
||
border-top: 1px solid #f0f0f0;
|
||
padding: 12px 16px;
|
||
background: #fff;
|
||
text-align: right;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.sheet-main-title,
|
||
.public-main-title {
|
||
font-size: 16px;
|
||
}
|
||
}
|
||
</style>
|