case-data-admin/src/views/business/case-clinical-article/case-clinical-article-form.vue
2025-08-18 10:53:47 +08:00

982 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
* 病例库-临床-文章
*
* @Author: xing
* @Date: 2025-08-04 10:17:15
* @Copyright gdxz
-->
<template>
<a-modal
:title="form.articleId ? '编辑' : '添加'"
:width="'90%'"
:open="visibleFlag"
@cancel="onClose"
:maskClosable="false"
:destroyOnClose="true"
:style="{ maxWidth: '1200px', minWidth: '800px' }"
:bodyStyle="{ maxHeight: '70vh', overflow: 'auto' }"
>
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" >
<a-form-item label="标题" name="articleTitle">
<a-input style="width: 100%" v-model:value="form.articleTitle" placeholder="标题" />
</a-form-item>
<a-form-item label="状态" name="articleStatus">
<SmartEnumSelect
width="100%"
v-model:value="form.articleStatus"
enum-name="STATUS_ENUM"
placeholder=""
:disabled="!!form.articleId"
/>
</a-form-item>
<a-form-item label="发表时间" name="pushDate">
<a-date-picker
show-time
valueFormat="YYYY-MM-DD HH:mm:ss"
v-model:value="form.pushDate"
style="width: 100%"
placeholder="发表时间"
:disabled-date="disabledFutureDate"
:disabled-time="disabledFutureTime"
/>
</a-form-item>
<a-form-item label="是否外部链接" name="isLink">
<a-switch v-model:checked="isLinkChecked" @change="isLinkCheckedChange" :disabled="!!form.articleId" />
</a-form-item>
<a-form-item label="外部链接地址" name="isLinkUrl" v-if="isLinkChecked">
<a-input style="width: 100%" v-model:value="form.isLinkUrl" placeholder="外部链接地址" />
</a-form-item>
<a-form-item label="疾病标签" name="labelList">
<div class="label-container">
<!-- 标签选择器 -->
<div class="label-selector">
<a-select
v-model:value="selectedLabels[0]"
placeholder="请选择一级标签"
style="width: 200px; margin-right: 8px;"
:options="labelOptions[0]"
:field-names="{ label: 'labelName', value: 'appIden' }"
@change="onLabelChange(0)"
@dropdownVisibleChange="onLabelDropdownVisibleChange(0, $event)"
:loading="labelLoading[0]"
allowClear
/>
<a-select
v-model:value="selectedLabels[1]"
placeholder="请选择二级标签"
style="width: 200px; margin-right: 8px;"
:options="labelOptions[1]"
:field-names="{ label: 'labelName', value: 'appIden' }"
@change="onLabelChange(1)"
:loading="labelLoading[1]"
:disabled="!selectedLabels[0]"
allowClear
/>
<a-select
v-model:value="selectedLabels[2]"
placeholder="请选择三级标签"
style="width: 200px; margin-right: 8px;"
:options="labelOptions[2]"
:field-names="{ label: 'labelName', value: 'appIden' }"
@change="onLabelChange(2)"
:loading="labelLoading[2]"
:disabled="!selectedLabels[1]"
allowClear
/>
<a-button
type="primary"
@click="addSelectedLabel"
:disabled="!hasSelectedLabel"
style="margin-left: 8px;"
>
添加选中标签
</a-button>
</div>
<!-- 已选择的标签列表 -->
<div class="selected-labels" v-if="form.labelList && form.labelList.length > 0">
<div class="label-item" v-for="(label, index) in form.labelList" :key="index">
<span class="label-name">{{ label.labelName }}</span>
<a-button type="link" danger size="small" @click="removeLabel(index)">
<template #icon><DeleteOutlined /></template>
</a-button>
</div>
</div>
</div>
</a-form-item>
<a-form-item label="二维码" name="shareQrcode">
<div class="qrcode-container">
<div class="qrcode-image" v-if="form.shareQrcode && form.shareQrcode.trim()">
<img :src="form.shareQrcode" alt="分享二维码" style="width: 120px; height: 120px; border: 1px solid #d9d9d9; border-radius: 4px;" />
</div>
<div class="qrcode-placeholder" v-else style="width: 120px; height: 120px; border: 1px dashed #d9d9d9; border-radius: 4px; display: flex; align-items: center; justify-content: center; color: #999; font-size: 12px;">
暂无二维码
</div>
<a-button
v-if="!form.shareQrcode || !form.shareQrcode.trim()"
type="primary"
@click="generateQrcode"
:loading="qrcodeLoading"
style="margin-left: 12px;"
:disabled="!form.articleId"
>
生成二维码
</a-button>
</div>
</a-form-item>
<a-form-item label="作者" name="authorList">
<div class="author-container">
<!-- 作者列表 -->
<div class="author-list" v-if="form.authorList && form.authorList.length > 0">
<div class="author-item" v-for="(author, index) in form.authorList" :key="author.doctorId">
<div class="author-info">
<span class="author-name">{{ author.doctorName }}</span>
<span class="author-hospital">{{ author.hospitalName }}</span>
<span class="author-location">{{ author.hospitalProvince }} {{ author.hospitalCity }}</span>
</div>
<a-button type="link" danger size="small" @click="removeAuthor(index)">
<template #icon><DeleteOutlined /></template>
</a-button>
</div>
</div>
<!-- 添加作者按钮 -->
<a-button type="dashed" @click="showAuthorModal" style="width: 100%; margin-top: 8px;">
<template #icon><PlusOutlined /></template>
添加作者
</a-button>
</div>
</a-form-item>
<a-form-item label="内容" name="articleContent" v-if="!isLinkChecked">
<div class="editor-container">
<div class="editor-tip">请在此处编辑文章内容支持富文本格式图片上传表格等功能</div>
<!-- <UEditor v-model="form.articleContent" :id="'article_content'" /> -->
<SmartWangeditor ref="rubricRef" :modelValue="form.articleContent" :height="500" :toolbarConfig="rubricToolbarConfig"/>
</div>
</a-form-item>
</a-form>
<template #footer>
<a-space>
<a-button @click="onClose">取消</a-button>
<a-button type="primary" @click="onSubmit">保存</a-button>
</a-space>
</template>
</a-modal>
<!-- 作者选择模态框 -->
<a-modal
title="选择作者"
:open="authorModalVisible"
@cancel="closeAuthorModal"
@ok="confirmSelectAuthor"
:maskClosable="false"
:width="700"
:zIndex="1001"
:bodyStyle="{ maxHeight: '400px', overflow: 'auto' }"
>
<div class="author-search-container">
<a-input-search
v-model:value="authorSearchKeyword"
placeholder="搜索医生姓名或医院名称"
@search="searchAuthors"
style="margin-bottom: 12px;"
size="small"
/>
</div>
<a-table
:columns="authorColumns"
:dataSource="authorList"
:loading="authorLoading"
:pagination="false"
size="small"
rowKey="doctorId"
:scroll="{ y: 250 }"
:row-selection="{
selectedRowKeys: selectedAuthorIds,
onChange: onAuthorSelectChange,
getCheckboxProps: getAuthorCheckboxProps
}"
>
<template #bodyCell="{ text, record }">
<template v-if="record.doctorName">
<div class="author-table-info">
<div class="author-name">{{ record.doctorName }}</div>
<div class="author-hospital">{{ record.hospitalName }}</div>
<div class="author-location">{{ record.hospitalProvince }} {{ record.hospitalCity }}</div>
</div>
</template>
</template>
</a-table>
</a-modal>
</template>
<script setup>
import { reactive, ref, nextTick, computed } from 'vue';
import _ from 'lodash';
import { message, Modal } from 'ant-design-vue';
import { SmartLoading } from '/@/components/framework/smart-loading';
import { caseClinicalArticleApi } from '/@/api/business/case-clinical-article/case-clinical-article-api';
import { caseClinicalDoctorApi } from '/@/api/business/case-clinical-doctor/case-clinical-doctor-api';
import { smartSentry } from '/@/lib/smart-sentry';
import FileUpload from '/@/components/support/file-upload/index.vue';
import SmartEnumSelect from '/@/components/framework/smart-enum-select/index.vue';
//import UEditor from '/@/components/business/ueditor.vue';
import SmartWangeditor from '/@/components/framework/wangeditor/index.vue';
import { FILE_FOLDER_TYPE_ENUM } from '/@/constants/support/file-const';
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import dayjs from 'dayjs';
// ------------------------ 事件 ------------------------
const emits = defineEmits(['reloadList']);
// ------------------------ 显示与隐藏 ------------------------
// 是否显示
const visibleFlag = ref(false);
const rubricRef = ref();
const rubricToolbarConfig = {
toolbarKeys : ['bold', 'underline', 'italic', 'through', 'code', 'sub', 'sup', 'clearStyle', 'color', 'bgColor', 'fontSize', 'fontFamily', 'indent', 'delIndent', 'justifyLeft', 'justifyRight', 'justifyCenter', 'justifyJustify', 'lineHeight', 'insertImage', 'deleteImage', 'editImage', 'divider', 'insertLink', 'editLink', 'unLink', 'viewLink', 'codeBlock', 'blockquote', 'headerSelect', 'redo', 'undo', 'fullScreen', 'enter', 'bulletedList', 'numberedList','uploadImage' ]
}
async function show(rowData) {
// 重置表单数据
Object.assign(form, formDefault);
// 清空标签选择器数据
selectedLabels.value = ['', '', ''];
selectedLabelNames.value = ['', '', ''];
labelOptions.value = [[], [], []];
if (rowData && !_.isEmpty(rowData)) {
// 如果是编辑模式通过getDetail接口获取完整数据
if (rowData.articleId) {
try {
SmartLoading.show();
const result = await caseClinicalArticleApi.getDetail(rowData.articleId);
if (result.data) {
Object.assign(form, result.data);
// 处理作者数据,将 caseClinicalArticleAuthor 转换为 authorList
if (result.data.caseClinicalArticleAuthor && result.data.caseClinicalArticleAuthor.length > 0) {
form.authorList = result.data.caseClinicalArticleAuthor.map(author => ({
doctorId: author.caseClinicalDoctor?.doctorId,
doctorName: author.caseClinicalDoctor?.doctorName,
hospitalName: author.caseClinicalDoctor?.hospitalName,
hospitalProvince: author.caseClinicalDoctor?.hospitalProvince,
hospitalCity: author.caseClinicalDoctor?.hospitalCity
}));
}
// 确保二维码字段正确显示
if (result.data.shareQrcode) {
form.shareQrcode = result.data.shareQrcode;
console.log('二维码地址:', result.data.shareQrcode);
}
// 处理标签数据 - 从caseClinicalArticleLabel字段读取
if (result.data.caseClinicalArticleLabel && result.data.caseClinicalArticleLabel.length > 0) {
form.labelList = result.data.caseClinicalArticleLabel.map(label => ({
appIden: label.appIden,
labelName: label.labelName
}));
console.log('加载的标签数据:', form.labelList);
} else {
// 如果没有标签数据确保labelList为空数组
form.labelList = [];
}
}
} catch (error) {
smartSentry.captureError(error);
message.error('获取文章详情失败');
return;
} finally {
SmartLoading.hide();
}
} else {
// 如果是新增模式,直接使用传入的数据
Object.assign(form, rowData);
// 确保新增时articleId为空labelList和authorList为空数组
form.articleId = undefined;
form.labelList = [];
form.authorList = [];
}
} else {
// 如果没有传入数据确保articleId为空labelList和authorList为空数组
form.articleId = undefined;
form.labelList = [];
form.authorList = [];
}
// 设置开关状态
isLinkChecked.value = form.isLink === 1;
// 使用字典时把下面这注释修改成自己的字典字段 有多个字典字段就复制多份同理修改 不然打开表单时不显示字典初始值
// if (form.status && form.status.length > 0) {
// form.status = form.status.map((e) => e.valueCode);
// }
visibleFlag.value = true;
// 不自动加载标签,等用户点击下拉框时再加载
nextTick(() => {
formRef.value.clearValidate();
});
}
function onClose() {
Object.assign(form, formDefault);
isLinkChecked.value = false;
visibleFlag.value = false;
// 清空作者相关数据
authorList.value = [];
selectedAuthorIds.value = [];
selectedAuthors.value = [];
// 清空标签相关数据
selectedLabels.value = ['', '', ''];
selectedLabelNames.value = ['', '', ''];
labelOptions.value = [[], [], []];
// 确保labelList被清空
form.labelList = [];
}
// ------------------------ 表单 ------------------------
// 组件ref
const formRef = ref();
const formDefault = {
articleTitle: undefined, //标题
articleStatus: 1, //状态1:正常 2:禁用)- 默认为正常
pushDate: new Date().toISOString().slice(0, 19).replace('T', ' '), //发表时间,默认为当天
isLink: 0, //是否外部链接0:否 1:是)
isLinkUrl: undefined, //外部链接地址
shareQrcode: undefined, //分享二维码地址
articleContent: '', //内容
articleContentText: '', //纯文本内容
authorList: [], //作者列表
labelList: [], //标签列表
};
let form = reactive({ ...formDefault });
// 是否外部链接开关状态
const isLinkChecked = ref(false);
// 禁用未来日期
function disabledFutureDate(current) {
// 禁用今天之后的日期
return current && current > dayjs().endOf('day');
}
// 禁用未来时间
function disabledFutureTime(date) {
if (date) {
const today = dayjs();
const selectedDate = dayjs(date);
// 如果是今天,禁用未来时间
if (selectedDate.isSame(today, 'day')) {
return {
disabledHours: () => {
const hours = [];
for (let i = today.hour() + 1; i < 24; i++) {
hours.push(i);
}
return hours;
},
disabledMinutes: (hour) => {
if (hour === today.hour()) {
const minutes = [];
for (let i = today.minute() + 1; i < 60; i++) {
minutes.push(i);
}
return minutes;
}
return [];
},
disabledSeconds: (hour, minute) => {
if (hour === today.hour() && minute === today.minute()) {
const seconds = [];
for (let i = today.second() + 1; i < 60; i++) {
seconds.push(i);
}
return seconds;
}
return [];
}
};
}
}
return {};
}
// 二维码相关数据
const qrcodeLoading = ref(false);
// 疾病标签相关数据
const labelOptions = ref([[], [], []]); // 三级标签选项
const labelLoading = ref([false, false, false]); // 三级标签加载状态
const selectedLabels = ref(['', '', '']); // 三级标签选择值
const selectedLabelNames = ref(['', '', '']); // 三级标签选择名称
// 开关状态变化处理
function isLinkCheckedChange(checked) {
form.isLink = checked ? 1 : 0;
if (checked) {
// 切换到外部链接模式时,清空内容字段
form.articleContent = '';
form.articleContentText = '';
} else {
// 切换到非外部链接模式时,清空链接地址
form.isLinkUrl = undefined;
}
}
// 获取疾病标签数据
async function loadLabelOptions(level, pId = '0') {
labelLoading.value[level] = true;
try {
const result = await caseClinicalArticleApi.getCaseLabel(pId);
if (result.data) {
labelOptions.value[level] = result.data;
}
} catch (error) {
smartSentry.captureError(error);
message.error('获取标签数据失败');
} finally {
labelLoading.value[level] = false;
}
}
// 标签选择器下拉框显示事件 - 延迟加载一级标签
async function onLabelDropdownVisibleChange(level, visible) {
// 只有当下拉框显示、是第一级、没有数据且不在加载中时才请求
if (visible && level === 0 && labelOptions.value[0].length === 0 && !labelLoading.value[0]) {
await loadLabelOptions(0);
}
}
// 标签选择变化处理
async function onLabelChange(level) {
// 清空后续级别的选择
for (let i = level + 1; i < 3; i++) {
selectedLabels.value[i] = '';
selectedLabelNames.value[i] = '';
labelOptions.value[i] = [];
}
if (selectedLabels.value[level]) {
// 获取选中标签的名称
const selectedOption = labelOptions.value[level].find(option => option.appIden === selectedLabels.value[level]);
if (selectedOption) {
selectedLabelNames.value[level] = selectedOption.labelName;
// 如果选中的标签有子标签,加载下一级
if (selectedOption.isSub === 1 && level < 2) {
// 只有当下级没有数据且不在加载中时才请求
if (labelOptions.value[level + 1].length === 0 && !labelLoading.value[level + 1]) {
await loadLabelOptions(level + 1, selectedLabels.value[level]);
}
}
}
}
}
// 计算是否有选中的标签
const hasSelectedLabel = computed(() => {
return selectedLabels.value.some(label => label);
});
// 添加选中的标签
function addSelectedLabel() {
// 收集所有选中的标签(一级、二级、三级)
const labelsToAdd = [];
for (let i = 0; i < 3; i++) {
if (selectedLabels.value[i] && selectedLabelNames.value[i]) {
labelsToAdd.push({
appIden: selectedLabels.value[i],
labelName: selectedLabelNames.value[i]
});
}
}
if (labelsToAdd.length === 0) {
message.warning('请先选择标签');
return;
}
// 检查重复标签并添加新标签
let addedCount = 0;
let skippedCount = 0;
for (const label of labelsToAdd) {
// 检查是否已经添加过
const exists = form.labelList.some(existingLabel => existingLabel.appIden === label.appIden);
if (exists) {
skippedCount++;
continue;
}
// 添加到标签列表
form.labelList.push(label);
addedCount++;
}
// 显示添加结果
if (addedCount > 0) {
message.success(`成功添加 ${addedCount} 个标签`);
}
if (skippedCount > 0) {
message.warning(`跳过 ${skippedCount} 个重复标签`);
}
// 清空选择
selectedLabels.value = ['', '', ''];
selectedLabelNames.value = ['', '', ''];
labelOptions.value[1] = [];
labelOptions.value[2] = [];
}
// 移除标签
function removeLabel(index) {
form.labelList.splice(index, 1);
}
// 生成二维码
async function generateQrcode() {
if (!form.articleId) {
message.warning('请先保存文章后再生成二维码');
return;
}
// 显示确认弹窗
Modal.confirm({
title: '确认生成二维码',
content: '确定要为该文章生成分享二维码吗?',
okText: '确定',
cancelText: '取消',
onOk: async () => {
qrcodeLoading.value = true;
try {
await caseClinicalArticleApi.addUnlimitedQrcode(form.articleId);
message.success('二维码生成成功');
// 重新加载表单数据以获取最新的二维码地址
if (form.articleId) {
const result = await caseClinicalArticleApi.getDetail(form.articleId);
if (result.data) {
Object.assign(form, result.data);
// 重新处理作者数据
if (result.data.caseClinicalArticleAuthor && result.data.caseClinicalArticleAuthor.length > 0) {
form.authorList = result.data.caseClinicalArticleAuthor.map(author => ({
doctorId: author.caseClinicalDoctor?.doctorId,
doctorName: author.caseClinicalDoctor?.doctorName,
hospitalName: author.caseClinicalDoctor?.hospitalName,
hospitalProvince: author.caseClinicalDoctor?.hospitalProvince,
hospitalCity: author.caseClinicalDoctor?.hospitalCity
}));
}
// 重新处理标签数据
if (result.data.caseClinicalArticleLabel && result.data.caseClinicalArticleLabel.length > 0) {
form.labelList = result.data.caseClinicalArticleLabel.map(label => ({
appIden: label.appIden,
labelName: label.labelName
}));
}
}
}
} catch (error) {
smartSentry.captureError(error);
message.error('二维码生成失败');
} finally {
qrcodeLoading.value = false;
}
}
});
}
// ------------------------ 作者相关 ------------------------
// 作者选择模态框
const authorModalVisible = ref(false);
const authorList = ref([]);
const authorLoading = ref(false);
const authorSearchKeyword = ref('');
const selectedAuthorIds = ref([]);
const selectedAuthors = ref([]);
// 作者表格列定义
const authorColumns = [
{
title: '医生信息',
dataIndex: 'doctorName',
key: 'doctorName',
width: '100%',
}
];
// 显示作者选择模态框
function showAuthorModal() {
authorModalVisible.value = true;
authorSearchKeyword.value = '';
selectedAuthorIds.value = [];
selectedAuthors.value = [];
searchAuthors();
}
// 关闭作者选择模态框
function closeAuthorModal() {
authorModalVisible.value = false;
}
// 搜索作者
async function searchAuthors() {
authorLoading.value = true;
try {
const result = await caseClinicalDoctorApi.queryList({
keywords: authorSearchKeyword.value,
limit: 8
});
authorList.value = result.data || [];
} catch (error) {
smartSentry.captureError(error);
message.error('获取医生列表失败');
} finally {
authorLoading.value = false;
}
}
// 作者选择变化
function onAuthorSelectChange(selectedRowKeys, selectedRows) {
selectedAuthorIds.value = selectedRowKeys;
selectedAuthors.value = selectedRows;
}
// 获取复选框属性(已选择的作者不可重复选择)
function getAuthorCheckboxProps(record) {
const existingAuthorIds = form.authorList.map(author => author.doctorId);
return {
disabled: existingAuthorIds.includes(record.doctorId)
};
}
// 确认选择作者
function confirmSelectAuthor() {
if (selectedAuthors.value.length === 0) {
message.warning('请选择至少一个作者');
return;
}
// 转换为表单格式并添加到作者列表
const authorForms = selectedAuthors.value.map(author => ({
doctorId: author.doctorId,
doctorName: author.doctorName,
hospitalName: author.hospitalName,
hospitalProvince: author.hospitalProvince,
hospitalCity: author.hospitalCity
}));
form.authorList.push(...authorForms);
closeAuthorModal();
}
// 移除作者
function removeAuthor(index) {
form.authorList.splice(index, 1);
}
// 表单验证规则
const rules = computed(() => ({
articleTitle: [{ required: true, message: '标题 必填' }],
articleStatus: [{ required: true, message: '状态1:正常 2:禁用) 必填' }],
pushDate: [
{ required: true, message: '发表时间 必填' },
{
validator: (rule, value) => {
if (!value) {
return Promise.resolve();
}
const selectedDate = new Date(value);
const currentDate = new Date();
// 设置当前时间为当天的23:59:59允许选择当天
currentDate.setHours(23, 59, 59, 999);
if (selectedDate > currentDate) {
return Promise.reject('发表时间不能大于当前时间');
}
return Promise.resolve();
}
}
],
authorList: [
{
required: true,
message: '作者 必填',
validator: (rule, value) => {
if (!value || !Array.isArray(value) || value.length === 0) {
return Promise.reject('请至少选择一个作者');
}
return Promise.resolve();
}
}
],
isLinkUrl: [{
required: isLinkChecked.value,
message: '外部链接地址 必填',
validator: (rule, value) => {
if (!isLinkChecked.value) {
return Promise.resolve();
}
if (!value || value.trim() === '') {
return Promise.reject('外部链接地址 必填');
}
return Promise.resolve();
}
}],
articleContent: [{
required: !isLinkChecked.value,
message: '内容 必填',
validator: (rule, value) => {
if (isLinkChecked.value) {
return Promise.resolve();
}
if (!value || value.trim() === '') {
return Promise.reject('内容 必填');
}
return Promise.resolve();
}
}],
}));
// 点击确定,验证表单
async function onSubmit() {
// 只有在非外部链接模式下才获取编辑器内容
if (!isLinkChecked.value && rubricRef.value) {
form.articleContent = rubricRef.value.getHtml();
}
try {
// 只有在非外部链接模式下才获取内容
if (!isLinkChecked.value) {
// UEditor通过v-model自动同步不需要手动获取
// 如果需要纯文本可以从HTML中提取
if (form.articleContent) {
// 简单的HTML标签移除提取纯文本
form.articleContentText = form.articleContent.replace(/<[^>]*>/g, '');
}
}
await formRef.value.validateFields();
save();
} catch (err) {
console.error(err);
message.error('参数验证错误,请仔细填写表单数据!');
}
}
// 新建、编辑API
async function save() {
SmartLoading.show();
try {
if (form.articleId) {
await caseClinicalArticleApi.update(form);
} else {
await caseClinicalArticleApi.add(form);
}
message.success('操作成功');
emits('reloadList');
onClose();
} catch (err) {
smartSentry.captureError(err);
} finally {
SmartLoading.hide();
}
}
defineExpose({
show,
});
</script>
<style scoped>
.author-container {
width: 100%;
}
.author-list {
margin-bottom: 8px;
}
.author-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
border: 1px solid #d9d9d9;
border-radius: 6px;
margin-bottom: 8px;
background-color: #fafafa;
}
.author-info {
display: flex;
flex-direction: column;
gap: 4px;
}
.author-name {
font-weight: 500;
color: #262626;
}
.author-hospital {
color: #595959;
font-size: 12px;
}
.author-location {
color: #8c8c8c;
font-size: 12px;
}
.author-table-info {
display: flex;
flex-direction: column;
gap: 1px;
}
.author-table-info .author-name {
font-weight: 500;
color: #262626;
font-size: 13px;
}
.author-table-info .author-hospital {
color: #595959;
font-size: 11px;
}
.author-table-info .author-location {
color: #8c8c8c;
font-size: 11px;
}
/* 弹窗表格样式优化 */
:deep(.ant-table-tbody > tr > td) {
padding: 8px 12px;
}
:deep(.ant-table-thead > tr > th) {
padding: 8px 12px;
font-size: 12px;
}
/* 响应式样式 */
@media (max-width: 768px) {
:deep(.ant-modal) {
margin: 16px;
max-width: calc(100vw - 32px) !important;
}
:deep(.ant-form-item-label) {
text-align: left !important;
}
:deep(.ant-form-item-label > label) {
height: auto !important;
line-height: 1.5 !important;
}
}
@media (max-width: 480px) {
:deep(.ant-modal-body) {
padding: 12px !important;
}
.author-item {
flex-direction: column;
align-items: flex-start;
gap: 8px;
}
.author-info {
width: 100%;
}
}
.qrcode-container {
display: flex;
align-items: center;
gap: 12px;
}
.qrcode-image img {
transition: all 0.3s ease;
}
.qrcode-image img:hover {
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.label-container {
width: 100%;
}
.label-selector {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.selected-labels {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.label-item {
display: flex;
align-items: center;
padding: 4px 8px;
background-color: #f0f0f0;
border-radius: 4px;
border: 1px solid #d9d9d9;
}
.label-name {
margin-right: 4px;
font-size: 12px;
color: #333;
}
.editor-container {
position: relative;
border: 1px solid #d9d9d9;
border-radius: 4px;
padding: 10px;
background-color: #fafafa;
min-height: 200px; /* 确保编辑器有最小高度 */
}
.editor-tip {
position: absolute;
top: 10px;
left: 10px;
background-color: #fff;
padding: 5px 10px;
border-radius: 4px;
font-size: 12px;
color: #8c8c8c;
z-index: 1;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
</style>