| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- 页面标题 --> |
| | | <div class="page-header"> |
| | | <h2>会议申请</h2> |
| | | </div> |
| | | |
| | | <!-- 申请类型选择 --> |
| | | <el-card class="type-card"> |
| | | <div class="type-selector"> |
| | | <div |
| | | v-for="type in applicationTypes" |
| | | :key="type.value" |
| | | class="type-item" |
| | | :class="{ active: currentType === type.value }" |
| | | @click="changeType(type.value)" |
| | | > |
| | | <div class="type-icon"> |
| | | <el-icon :size="24"><component :is="type.icon"/></el-icon> |
| | | </div> |
| | | <div class="type-info"> |
| | | <div class="type-name">{{ type.name }}</div> |
| | | <div class="type-desc">{{ type.desc }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 会议申请表单 --> |
| | | <el-card> |
| | | <div class="form-header"> |
| | | <h3>{{ getCurrentTypeName() }}申请</h3> |
| | | </div> |
| | | |
| | | <el-form |
| | | ref="meetingFormRef" |
| | | :model="meetingForm" |
| | | :rules="rules" |
| | | label-width="100px" |
| | | > |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="会议主题" prop="title"> |
| | | <el-input v-model="meetingForm.title" placeholder="请输入会议主题"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="会议室" prop="roomId"> |
| | | <el-select v-model="meetingForm.roomId" placeholder="请选择会议室" style="width: 100%"> |
| | | <el-option |
| | | v-for="room in meetingRooms" |
| | | :key="room.id" |
| | | :label="`${room.name} (${room.location})`" |
| | | :value="room.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="主持人" prop="host"> |
| | | <el-input v-model="meetingForm.host" placeholder="请输入主持人姓名"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="会议日期" prop="meetingDate"> |
| | | <el-date-picker |
| | | v-model="meetingForm.meetingDate" |
| | | type="date" |
| | | placeholder="请选择会议日期" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | :disabled-date="disabledDate" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <!-- 空列,保持布局 --> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="开始时间" prop="startTime"> |
| | | <el-select |
| | | v-model="meetingForm.startTime" |
| | | placeholder="请选择开始时间" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="time in timeOptions" |
| | | :key="time.value" |
| | | :label="time.label" |
| | | :value="time.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="结束时间" prop="endTime"> |
| | | <el-select |
| | | v-model="meetingForm.endTime" |
| | | placeholder="请选择结束时间" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="time in timeOptions" |
| | | :key="time.value" |
| | | :label="time.label" |
| | | :value="time.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-form-item label="参会人员" prop="participants"> |
| | | <el-select |
| | | v-model="meetingForm.participants" |
| | | multiple |
| | | filterable |
| | | placeholder="请选择参会人员" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="person in employees" |
| | | :key="person.id" |
| | | :label="`${person.staffName} (${person.postJob})`" |
| | | :value="person.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="会议说明" prop="description"> |
| | | <el-input |
| | | v-model="meetingForm.description" |
| | | type="textarea" |
| | | :rows="4" |
| | | placeholder="请输入会议说明" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="form-footer"> |
| | | <el-button @click="resetForm">重置</el-button> |
| | | <el-button type="primary" @click="submitForm">提交</el-button> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | <div> |
| | | |
| | | <!-- 申请类型选择 --> |
| | | <el-card class="type-card"> |
| | | <div class="type-selector"> |
| | | <div |
| | | v-for="type in applicationTypes" |
| | | :key="type.value" |
| | | class="type-item" |
| | | :class="{ active: currentType === type.value }" |
| | | @click="changeType(type.value)" |
| | | > |
| | | <div class="type-icon"> |
| | | <el-icon :size="24"><component :is="type.icon"/></el-icon> |
| | | </div> |
| | | <div class="type-info"> |
| | | <div class="type-name">{{ type.name }}</div> |
| | | <div class="type-desc">{{ type.desc }}</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 会议申请表单 --> |
| | | <el-card> |
| | | <div class="form-header"> |
| | | <h3>{{ getCurrentTypeName() }}申请</h3> |
| | | </div> |
| | | |
| | | <el-form |
| | | ref="meetingFormRef" |
| | | :model="meetingForm" |
| | | :rules="rules" |
| | | label-width="100px" |
| | | > |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="会议主题" prop="title"> |
| | | <el-input v-model="meetingForm.title" placeholder="请输入会议主题"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="会议室" prop="roomId"> |
| | | <el-select v-model="meetingForm.roomId" placeholder="请选择会议室" style="width: 100%"> |
| | | <el-option |
| | | v-for="room in meetingRooms" |
| | | :key="room.id" |
| | | :label="`${room.name} (${room.location})`" |
| | | :value="room.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="主持人" prop="host"> |
| | | <el-input v-model="meetingForm.host" placeholder="请输入主持人姓名"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="会议日期" prop="meetingDate"> |
| | | <el-date-picker |
| | | v-model="meetingForm.meetingDate" |
| | | type="date" |
| | | placeholder="请选择会议日期" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | :disabled-date="disabledDate" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <!-- 空列,保持布局 --> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="开始时间" prop="startTime"> |
| | | <el-time-picker |
| | | v-model="meetingForm.startTime" |
| | | placeholder="请选择开始时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | :disabled-hours="disabledStartHours" |
| | | :disabled-minutes="disabledStartMinutes" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="结束时间" prop="endTime"> |
| | | <el-time-picker |
| | | v-model="meetingForm.endTime" |
| | | placeholder="请选择结束时间" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | :disabled-hours="disabledEndHours" |
| | | :disabled-minutes="disabledEndMinutes" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-form-item label="参会人员" prop="participants"> |
| | | <el-select |
| | | v-model="meetingForm.participants" |
| | | multiple |
| | | filterable |
| | | placeholder="请选择参会人员" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="person in employees" |
| | | :key="person.id" |
| | | :label="`${person.staffName}${person.postName ? ` (${person.postName})` : ''}`" |
| | | :value="person.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="会议说明" prop="description"> |
| | | <el-input |
| | | v-model="meetingForm.description" |
| | | type="textarea" |
| | | :rows="4" |
| | | placeholder="请输入会议说明" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="form-footer"> |
| | | <el-button @click="resetForm">重置</el-button> |
| | | <el-button type="primary" @click="submitForm">提交</el-button> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, reactive, onMounted} from 'vue' |
| | | import {ref, reactive, onMounted, computed, watch} from 'vue' |
| | | import {ElMessage} from 'element-plus' |
| | | import {Plus, Document, Promotion, Bell} from '@element-plus/icons-vue' |
| | | import {getRoomEnum, saveMeetingApplication} from '@/api/collaborativeApproval/meeting.js' |
| | | import {getStaffOnJob} from "@/api/personnelManagement/onboarding.js"; |
| | | import {staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js"; |
| | | |
| | | // 当前申请类型 |
| | | const currentType = ref('department') // approval: 审批流程, department: 部门级, notification: 通知发布 |
| | | |
| | | // 申请类型选项 |
| | | const applicationTypes = ref([ |
| | | { |
| | | value: 'approval', |
| | | name: '审批流程会议', |
| | | desc: '需要经过多级审批的会议申请', |
| | | icon: Document |
| | | }, |
| | | { |
| | | value: 'department', |
| | | name: '部门级会议', |
| | | desc: '部门内部会议申请流程', |
| | | icon: Promotion |
| | | }, |
| | | { |
| | | value: 'notification', |
| | | name: '会议通知', |
| | | desc: '无需审批直接发布的会议通知', |
| | | icon: Bell |
| | | } |
| | | { |
| | | value: 'approval', |
| | | name: '审批流程会议', |
| | | desc: '需要经过多级审批的会议申请', |
| | | icon: Document |
| | | }, |
| | | { |
| | | value: 'department', |
| | | name: '部门级会议', |
| | | desc: '部门内部会议申请流程', |
| | | icon: Promotion |
| | | }, |
| | | { |
| | | value: 'notification', |
| | | name: '会议通知', |
| | | desc: '无需审批直接发布的会议通知', |
| | | icon: Bell |
| | | } |
| | | ]) |
| | | |
| | | // 表单数据 |
| | | const meetingForm = reactive({ |
| | | title: '', |
| | | type: '', |
| | | roomId: '', |
| | | host: '', |
| | | meetingDate: '', |
| | | startTime: '', |
| | | endTime: '', |
| | | participants: [], |
| | | description: '' |
| | | title: '', |
| | | type: '', |
| | | roomId: '', |
| | | host: '', |
| | | meetingDate: '', |
| | | startTime: '', |
| | | endTime: '', |
| | | participants: [], |
| | | description: '' |
| | | }) |
| | | |
| | | // 表单校验规则 |
| | | const rules = { |
| | | title: [{required: true, message: '请输入会议主题', trigger: 'blur'}], |
| | | roomId: [{required: true, message: '请选择会议室', trigger: 'change'}], |
| | | host: [{required: true, message: '请输入主持人', trigger: 'blur'}], |
| | | meetingDate: [{required: true, message: '请选择会议日期', trigger: 'change'}], |
| | | startTime: [{required: true, message: '请选择开始时间', trigger: 'change'}], |
| | | endTime: [{required: true, message: '请选择结束时间', trigger: 'change'}], |
| | | participants: [{required: true, message: '请选择参会人员', trigger: 'change'}] |
| | | } |
| | | |
| | | // 表单引用 |
| | | const meetingFormRef = ref(null) |
| | |
| | | // 员工列表 |
| | | const employees = ref([]) |
| | | |
| | | // 时间选项(以半小时为间隔) |
| | | const timeOptions = ref([]) |
| | | |
| | | // 初始化时间选项 |
| | | const initTimeOptions = () => { |
| | | const options = [] |
| | | for (let hour = 8; hour <= 18; hour++) { |
| | | // 每个小时添加两个选项:整点和半点 |
| | | options.push({ |
| | | value: `${hour.toString().padStart(2, '0')}:00`, |
| | | label: `${hour.toString().padStart(2, '0')}:00` |
| | | }) |
| | | |
| | | if (hour < 18) { // 18:00之后没有半点选项 |
| | | options.push({ |
| | | value: `${hour.toString().padStart(2, '0')}:30`, |
| | | label: `${hour.toString().padStart(2, '0')}:30` |
| | | }) |
| | | } |
| | | } |
| | | timeOptions.value = options |
| | | const getTimeInMinutes = (time) => { |
| | | if (!time) return -1 |
| | | const [hour, minute] = time.split(':').map(Number) |
| | | return hour * 60 + minute |
| | | } |
| | | |
| | | const isToday = (dateText) => { |
| | | if (!dateText) return false |
| | | const [year, month, day] = dateText.split('-').map(Number) |
| | | const now = new Date() |
| | | return year === now.getFullYear() && month === now.getMonth() + 1 && day === now.getDate() |
| | | } |
| | | |
| | | const validateStartTime = (_rule, value, callback) => { |
| | | if (!value) { |
| | | callback() |
| | | return |
| | | } |
| | | callback() |
| | | } |
| | | |
| | | const validateEndTime = (_rule, value, callback) => { |
| | | if (!value || !meetingForm.startTime) { |
| | | callback() |
| | | return |
| | | } |
| | | if (getTimeInMinutes(value) <= getTimeInMinutes(meetingForm.startTime)) { |
| | | callback(new Error('结束时间必须大于开始时间')) |
| | | return |
| | | } |
| | | callback() |
| | | } |
| | | |
| | | const rules = { |
| | | title: [{required: true, message: '请输入会议主题', trigger: 'blur'}], |
| | | roomId: [{required: true, message: '请选择会议室', trigger: 'change'}], |
| | | host: [{required: true, message: '请输入主持人', trigger: 'blur'}], |
| | | meetingDate: [{required: true, message: '请选择会议日期', trigger: 'change'}], |
| | | startTime: [ |
| | | {required: true, message: '请选择开始时间', trigger: 'change'}, |
| | | {validator: validateStartTime, trigger: 'change'} |
| | | ], |
| | | endTime: [ |
| | | {required: true, message: '请选择结束时间', trigger: 'change'}, |
| | | {validator: validateEndTime, trigger: 'change'} |
| | | ], |
| | | participants: [{required: true, message: '请选择参会人员', trigger: 'change'}] |
| | | } |
| | | |
| | | // 时间选择器禁用逻辑 |
| | | const disabledStartHours = () => { |
| | | const hours = [] |
| | | for (let h = 0; h < 24; h++) { |
| | | if (h < 8 || h > 18) hours.push(h) |
| | | } |
| | | if (isToday(meetingForm.meetingDate)) { |
| | | const now = new Date() |
| | | for (let h = 8; h < now.getHours(); h++) { |
| | | if (!hours.includes(h)) hours.push(h) |
| | | } |
| | | } |
| | | return hours |
| | | } |
| | | |
| | | const disabledStartMinutes = (hour) => { |
| | | const minutes = [] |
| | | for (let m = 0; m < 60; m++) { |
| | | if (m !== 0 && m !== 30) minutes.push(m) |
| | | } |
| | | if (isToday(meetingForm.meetingDate)) { |
| | | const now = new Date() |
| | | if (hour === now.getHours()) { |
| | | if (now.getMinutes() >= 30) { |
| | | minutes.push(0) |
| | | } |
| | | } |
| | | } |
| | | return minutes |
| | | } |
| | | |
| | | const disabledEndHours = () => { |
| | | const hours = [] |
| | | for (let h = 0; h < 24; h++) { |
| | | if (h < 8 || h > 18) hours.push(h) |
| | | } |
| | | if (meetingForm.startTime) { |
| | | const startHour = parseInt(meetingForm.startTime.split(':')[0]) |
| | | for (let h = 8; h < startHour; h++) { |
| | | if (!hours.includes(h)) hours.push(h) |
| | | } |
| | | } |
| | | return hours |
| | | } |
| | | |
| | | const disabledEndMinutes = (hour) => { |
| | | const minutes = [] |
| | | for (let m = 0; m < 60; m++) { |
| | | if (m !== 0 && m !== 30) minutes.push(m) |
| | | } |
| | | if (meetingForm.startTime) { |
| | | const startHour = parseInt(meetingForm.startTime.split(':')[0]) |
| | | const startMinute = parseInt(meetingForm.startTime.split(':')[1]) |
| | | if (hour === startHour) { |
| | | if (startMinute >= 0) minutes.push(0) |
| | | if (startMinute >= 30) minutes.push(30) |
| | | // only keep minutes > startMinute |
| | | for (let m = 0; m <= startMinute; m++) { |
| | | if (!minutes.includes(m)) minutes.push(m) |
| | | } |
| | | } |
| | | } |
| | | return minutes |
| | | } |
| | | |
| | | watch(() => meetingForm.startTime, () => { |
| | | if (meetingForm.endTime && getTimeInMinutes(meetingForm.endTime) <= getTimeInMinutes(meetingForm.startTime)) { |
| | | meetingForm.endTime = '' |
| | | } |
| | | if (meetingForm.endTime) { |
| | | meetingFormRef.value?.validateField('endTime') |
| | | } |
| | | |
| | | }) |
| | | |
| | | // 禁用日期(禁用今天之前的日期) |
| | | const disabledDate = (time) => { |
| | | // 禁用今天之前的日期 |
| | | return time.getTime() < Date.now() - 86400000 |
| | | // 禁用今天之前的日期 |
| | | return time.getTime() < Date.now() - 86400000 |
| | | } |
| | | |
| | | // 切换申请类型 |
| | | const changeType = (type) => { |
| | | currentType.value = type |
| | | currentType.value = type |
| | | } |
| | | |
| | | // 获取当前类型名称 |
| | | const getCurrentTypeName = () => { |
| | | const type = applicationTypes.value.find(t => t.value === currentType.value) |
| | | return type ? type.name : '' |
| | | const type = applicationTypes.value.find(t => t.value === currentType.value) |
| | | return type ? type.name : '' |
| | | } |
| | | |
| | | // 重置表单 |
| | | const resetForm = () => { |
| | | meetingFormRef.value?.resetFields() |
| | | meetingFormRef.value?.resetFields() |
| | | } |
| | | |
| | | // 提交表单 |
| | | const submitForm = () => { |
| | | meetingFormRef.value?.validate((valid) => { |
| | | if (valid) { |
| | | |
| | | let formData = {...meetingForm} |
| | | formData.applicationType = currentType.value |
| | | formData.startTime = `${meetingForm.meetingDate} ${meetingForm.startTime}:00` |
| | | formData.endTime = `${meetingForm.meetingDate} ${meetingForm.endTime}:00` |
| | | formData.participants = JSON.stringify(formData.participants) |
| | | console.log(formData) |
| | | saveMeetingApplication(formData).then(() => { |
| | | |
| | | // 模拟提交操作 |
| | | ElMessage.success(`${getCurrentTypeName()}提交成功`) |
| | | |
| | | // 根据不同类型执行不同操作 |
| | | switch (currentType.value) { |
| | | case 'approval': |
| | | ElMessage.info('会议已提交审批流程') |
| | | break |
| | | case 'department': |
| | | ElMessage.info('部门级会议申请已提交') |
| | | break |
| | | case 'notification': |
| | | ElMessage.info('会议通知已发布') |
| | | break |
| | | } |
| | | resetForm() |
| | | }) |
| | | |
| | | } |
| | | }) |
| | | meetingFormRef.value?.validate((valid) => { |
| | | if (valid) { |
| | | |
| | | let formData = {...meetingForm} |
| | | formData.applicationType = currentType.value |
| | | formData.startTime = `${meetingForm.meetingDate} ${meetingForm.startTime}:00` |
| | | formData.endTime = `${meetingForm.meetingDate} ${meetingForm.endTime}:00` |
| | | formData.participants = JSON.stringify(formData.participants) |
| | | console.log(formData) |
| | | saveMeetingApplication(formData).then(() => { |
| | | |
| | | // 模拟提交操作 |
| | | ElMessage.success(`${getCurrentTypeName()}提交成功`) |
| | | resetForm() |
| | | }) |
| | | |
| | | } |
| | | }) |
| | | } |
| | | |
| | | // 页面加载时初始化 |
| | | onMounted(() => { |
| | | initTimeOptions() |
| | | getRoomEnum().then(res => { |
| | | meetingRooms.value = res.data |
| | | }) |
| | | getStaffOnJob().then(res => { |
| | | employees.value = res.data.sort((a, b) => a.postJob.localeCompare(b.postJob)) |
| | | }) |
| | | getRoomEnum().then(res => { |
| | | meetingRooms.value = res.data |
| | | }) |
| | | staffOnJobListPage({ |
| | | current: -1, |
| | | size: -1, |
| | | staffState: 1 |
| | | }).then(res => { |
| | | employees.value = res.data.records.sort((a, b) => (a.postName || '').localeCompare(b.postName || '')) |
| | | }) |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .app-container { |
| | | padding: 20px; |
| | | padding: 20px; |
| | | } |
| | | |
| | | .page-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .page-header h2 { |
| | | margin: 0; |
| | | color: #303133; |
| | | margin: 0; |
| | | color: #303133; |
| | | } |
| | | |
| | | .type-card { |
| | | margin-bottom: 20px; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .type-selector { |
| | | display: flex; |
| | | gap: 20px; |
| | | display: flex; |
| | | gap: 20px; |
| | | } |
| | | |
| | | .type-item { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 20px; |
| | | border: 1px solid #ebeef5; |
| | | border-radius: 8px; |
| | | cursor: pointer; |
| | | transition: all 0.3s; |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 20px; |
| | | border: 1px solid #ebeef5; |
| | | border-radius: 8px; |
| | | cursor: pointer; |
| | | transition: all 0.3s; |
| | | } |
| | | |
| | | .type-item:hover { |
| | | border-color: #409eff; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | border-color: #409eff; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .type-item.active { |
| | | border-color: #409eff; |
| | | background-color: #ecf5ff; |
| | | border-color: #409eff; |
| | | background-color: #ecf5ff; |
| | | } |
| | | |
| | | .type-icon { |
| | | margin-right: 15px; |
| | | color: #409eff; |
| | | margin-right: 15px; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .type-name { |
| | | font-size: 16px; |
| | | font-weight: 500; |
| | | color: #303133; |
| | | margin-bottom: 5px; |
| | | font-size: 16px; |
| | | font-weight: 500; |
| | | color: #303133; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .type-desc { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .form-header { |
| | | margin-bottom: 20px; |
| | | padding-bottom: 15px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | margin-bottom: 20px; |
| | | padding-bottom: 15px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .form-header h3 { |
| | | margin: 0; |
| | | color: #303133; |
| | | margin: 0; |
| | | color: #303133; |
| | | } |
| | | |
| | | .form-footer { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 10px; |
| | | margin-top: 30px; |
| | | padding-top: 20px; |
| | | border-top: 1px solid #ebeef5; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 10px; |
| | | margin-top: 30px; |
| | | padding-top: 20px; |
| | | border-top: 1px solid #ebeef5; |
| | | } |
| | | </style> |