| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- <template>
- <el-drawer :model-value="modelValue" @update:model-value="val => $emit('update:modelValue', val)" size="80%" direction="rtl" destroy-on-close class="plan-detail-drawer" :with-header="false">
- <div class="drawer-header">
- <span class="header-title">拜访计划明细</span>
- <el-icon class="close-icon" @click="$emit('update:modelValue', false)"><Close /></el-icon>
- </div>
-
- <div class="drawer-body" v-loading="loading">
- <!-- 左侧主体内容 -->
- <div class="main-content">
- <div class="content-tabs">
- <div class="tab-item active">资料</div>
- </div>
-
- <div class="content-scroll">
- <!-- 基本信息 -->
- <div class="section-container">
- <div class="section-header-grey">
- <span class="title">基本信息</span>
- </div>
- <div class="info-grid-2">
- <div class="info-item"><span class="label">计划编号</span><span class="value">{{ detailData.planNo }}</span></div>
- <div class="info-item"><span class="label">拜访人</span><span class="value">{{ detailData.visitorName }}</span></div>
- <div class="info-item"><span class="label">开始时间</span><span class="value">{{ parseTime(detailData.startTime, '{y}-{m}-{d}') }}</span></div>
- <div class="info-item"><span class="label">结束时间</span><span class="value">{{ parseTime(detailData.endTime, '{y}-{m}-{d}') }}</span></div>
- <div class="info-item"><span class="label">状态</span>
- <span class="value">
- <template v-if="detailData.status === '0'">待审核</template>
- <template v-else-if="detailData.status === '1'">已审核</template>
- <template v-else-if="detailData.status === '2'">已驳回</template>
- </span>
- </div>
- </div>
- </div>
- <!-- 日程信息 -->
- <div class="section-container" style="margin-top: 20px;">
- <div class="section-header-grey" style="display: block; visibility: visible;">
- <span class="title" style="display: inline-block;">日程信息</span>
- </div>
- <el-table :data="scheduleData" border class="custom-table" style="margin-top: 15px;">
- <el-table-column label="拜访日期" align="center" prop="callDate" width="120" sortable>
- <template #default="scope">
- <span>{{ parseTime(scope.row.callDate, '{y}-{m}-{d}') }}</span>
- </template>
- </el-table-column>
- <el-table-column label="客户名称" align="center" prop="customerName" min-width="200" />
- <el-table-column label="关联对象" align="center" prop="objectName" min-width="120" />
- <el-table-column label="关联类型" align="center" prop="relevanceType" width="100">
- <template #default="scope">
- {{ scope.row.relevanceType === 0 ? '客户' : (scope.row.relevanceType === 1 ? '项目商机' : '年度入围') }}
- </template>
- </el-table-column>
- <el-table-column label="紧要程度" align="center" prop="importantLevel" width="100">
- <template #default="scope">
- {{ getUrgencyLabel(scope.row.importantLevel) }}
- </template>
- </el-table-column>
- <el-table-column label="拜访目的" align="center" prop="purposeVisit" min-width="150" show-overflow-tooltip />
- <el-table-column label="操作" align="center" width="100">
- <template #default="scope">
- <el-button link type="primary" @click="handleViewSchedule(scope.row)">查看</el-button>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </div>
- </div>
- <!-- 右侧侧边栏 (通用业务活动组件) -->
- <div class="side-panel">
- <BusinessActivity
- :business-id="props.id"
- business-type="plan"
- :info-data="detailData"
- >
- <template #management>
- <div class="admin-grid">
- <div class="admin-cell">
- <span class="label">创建日期</span>
- <span class="value">{{ parseTime(detailData.createTime || detailData.createDate, '{y}-{m}-{d}') || '--' }}</span>
- </div>
- <div class="admin-cell">
- <span class="label">创建人</span>
- <span class="value">{{ detailData.createByName || detailData.createUserName || detailData.nickName || detailData.createBy || '--' }}</span>
- </div>
- <div class="admin-cell">
- <span class="label">修改日期</span>
- <span class="value">{{ parseTime(detailData.updateTime || detailData.updateDate, '{y}-{m}-{d}') || '--' }}</span>
- </div>
- <div class="admin-cell">
- <span class="label">最后修改人</span>
- <span class="value">{{ detailData.updateByName || detailData.updateUserName || detailData.updateBy || '--' }}</span>
- </div>
- <div class="admin-cell" v-if="detailData.auditByName || detailData.auditBy">
- <span class="label">审核人</span>
- <span class="value">{{ detailData.auditByName || detailData.auditBy || '--' }}</span>
- </div>
- <div class="admin-cell" v-if="detailData.auditTime">
- <span class="label">审核时间</span>
- <span class="value">{{ parseTime(detailData.auditTime, '{y}-{m}-{d}') || '--' }}</span>
- </div>
- <div class="admin-cell" v-if="detailData.deptName">
- <span class="label">所属部门</span>
- <span class="value">{{ detailData.deptName || '--' }}</span>
- </div>
- </div>
- </template>
- </BusinessActivity>
- </div>
- </div>
- <!-- 查看日程对话框 -->
- <el-dialog v-if="viewScheduleOpen" v-model="viewScheduleOpen" width="750px" append-to-body destroy-on-close class="view-schedule-dialog">
- <template #header>
- <span class="custom-dialog-header">查看日程</span>
- </template>
- <el-form :model="currentSchedule" label-width="110px" disabled class="view-form">
- <el-form-item label="关联类型:">
- <el-radio-group v-model="currentSchedule.relevanceType">
- <el-radio :label="0">客户</el-radio>
- <el-radio :label="1">项目商机</el-radio>
- <el-radio :label="2">年度入围</el-radio>
- </el-radio-group>
- </el-form-item>
-
- <el-form-item label="客户:">
- <el-input v-model="currentSchedule.customerName" />
- </el-form-item>
- <el-row :gutter="20">
- <el-col :span="12">
- <el-form-item label="拜访日期:">
- <el-date-picker v-model="currentSchedule.callDate" type="date" style="width: 100%" disabled format="YYYY-MM-DD" value-format="YYYY-MM-DD" />
- </el-form-item>
- </el-col>
- <el-col :span="12">
- <el-form-item label="紧要程度:">
- <el-select v-model="currentSchedule.importantLevel" placeholder="请选择" disabled style="width: 100%">
- <el-option v-for="dict in urgencyOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-form-item label="随访人:">
- <el-input v-model="currentSchedule.followPeopleName" />
- </el-form-item>
- <el-form-item label="拜访目的:">
- <el-input v-model="currentSchedule.purposeVisit" type="textarea" :rows="5" disabled />
- </el-form-item>
- </el-form>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="viewScheduleOpen = false">确 定</el-button>
- </div>
- </template>
- </el-dialog>
- </el-drawer>
- </template>
- <script setup>
- import { ref, reactive, computed, watch, getCurrentInstance, onMounted, toRefs } from 'vue';
- import { Close, Search, Plus, UserFilled } from '@element-plus/icons-vue';
- import { getPlan } from "@/api/visit/plan";
- import { listOperateLog } from "@/api/visit/operateLog";
- import BusinessActivity from '../../common/businessActivity.vue';
- const props = defineProps({
- modelValue: Boolean,
- id: [String, Number]
- });
- const emit = defineEmits(['update:modelValue']);
- const proxy = getCurrentInstance().proxy;
- const { importance_level: urgencyOptions } = toRefs(reactive(proxy.useDict("importance_level")));
- const loading = ref(false);
- const detailData = ref({});
- const scheduleData = ref([]);
- const activeSideTab = ref('team');
- // 日程详情相关
- const viewScheduleOpen = ref(false);
- const currentSchedule = ref({
- relatedType: '客户',
- customerName: '',
- visitDate: '',
- urgency: '',
- accompanyPersons: '',
- purpose: ''
- });
- watch(() => props.modelValue, (val) => {
- if (val && props.id) {
- getDetail();
- }
- });
- const getDetail = () => {
- loading.value = true;
- getPlan(props.id).then(response => {
- detailData.value = response.data;
- scheduleData.value = response.data.detailList || [];
- loading.value = false;
- }).catch(() => {
- loading.value = false;
- });
- };
- const handleViewSchedule = (row) => {
- const data = JSON.parse(JSON.stringify(row));
- if (data.importantLevel !== undefined && data.importantLevel !== null) {
- data.importantLevel = String(data.importantLevel);
- }
- currentSchedule.value = data;
- viewScheduleOpen.value = true;
- };
- const getUrgencyLabel = (val) => {
- const found = urgencyOptions.value.find(item => String(item.value) === String(val));
- return found ? found.label : (val || '--');
- };
- const getOperateTypeText = (type) => {
- const map = { 1: '添加', 2: '编辑', 3: '删除', 4: '审核', 5: '转移', 6: '分析' };
- return map[String(type)] || '操作';
- };
- const translateLogTarget = (details) => {
- if (!details) return '拜访计划';
- if (details.includes('日程')) return '日程';
- return '拜访计划';
- };
- onMounted(() => {
- });
- </script>
- <style scoped lang="scss">
- /* 此处应包含原 index.vue 中 .plan-detail-drawer, .drawer-header, .drawer-body, .side-panel 等样式 */
- .plan-detail-drawer {
- :deep(.el-drawer__body) { padding: 0; overflow: hidden; }
- }
- .drawer-header {
- height: 50px; display: flex; justify-content: space-between; align-items: center;
- padding: 0 20px; border-bottom: 1px solid #f0f0f0; background-color: #fff;
- .header-title { font-size: 16px; font-weight: normal; color: #333; }
- .close-icon { cursor: pointer; color: #999; font-size: 18px; &:hover { color: #409eff; } }
- }
- .drawer-body { height: calc(100vh - 50px); display: flex; }
- .main-content {
- flex: 1; display: flex; flex-direction: column; background-color: #fff; border-right: 1px solid #f0f0f0;
- min-width: 0;
- .content-tabs {
- padding: 0 20px; border-bottom: 1px solid #f2f2f2; height: 48px;
- .tab-item {
- display: inline-block; height: 48px; line-height: 48px; margin-right: 30px; color: #409eff; font-size: 14px; cursor: pointer;
- &.active { color: #409eff; font-weight: normal; position: relative;
- &::after { content: ""; position: absolute; bottom: 0; left: 0; width: 100%; height: 2px; background-color: #409eff; }
- }
- }
- }
- .content-scroll { flex: 1; overflow: auto; padding: 20px; }
- }
- .side-panel {
- width: 30%; flex-shrink: 0; background-color: #fff; display: flex; flex-direction: column;
- :deep(.activity-container) {
- .el-tabs__header {
- margin-top: 0;
- margin-bottom: 0;
- height: 48px;
- .el-tabs__nav-wrap {
- height: 100%;
- display: flex;
- align-items: center;
- }
- .el-tabs__item {
- font-weight: normal !important;
- }
- }
- }
- .side-tabs-header {
- display: flex; border-bottom: 1px solid #f1f5f9;
- .side-tab-item {
- flex: 1; text-align: center; padding: 16px 8px; font-size: 13px; color: #1d2129; cursor: pointer;
- &.active { color: #409eff; font-weight: normal; position: relative;
- &::after { content: ''; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 32px; height: 3px; background: #409eff; }
- }
- }
- }
- .side-tab-content { flex: 1; overflow-y: auto; padding: 16px; }
- }
- .section-header-grey { background-color: #f5f7fa; padding: 10px 15px; margin-bottom: 5px; .title { font-size: 14px; font-weight: normal; color: #409eff; } }
- .info-grid-2 {
- display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px 40px; padding: 15px;
- .info-item { display: flex; font-size: 13px; .label { color: #8c8c8c; width: 80px; flex-shrink: 0; } .value { color: #262626; } }
- }
- .admin-grid {
- display: grid;
- grid-template-columns: repeat(2, 1fr);
- gap: 12px 8px;
- padding: 15px 5px;
- .admin-cell {
- display: flex;
- align-items: center;
- font-size: 13px;
- .label { color: #86909c; margin-right: 6px; flex-shrink: 0; }
- .value { color: #1d2129; word-break: break-all; }
- }
- }
- </style>
- <!-- 非作用域样式,用于覆盖 append-to-body 的弹窗 -->
- <style lang="scss">
- .view-schedule-dialog {
- .el-dialog__header {
- background-color: #fff !important;
- border-bottom: 1px solid #f0f0f0;
- .custom-dialog-header {
- height: 45px;
- line-height: 45px;
- padding-left: 20px;
- color: #333 !important;
- font-size: 16px;
- display: block;
- font-weight: normal !important;
- }
- .el-dialog__headerbtn {
- .el-dialog__close {
- color: #909399 !important;
- &:hover { color: #409eff !important; }
- }
- }
- }
- .el-dialog__body {
- padding: 25px 20px 10px;
- }
- .el-form-item__label, .el-input__inner, .el-textarea__inner, .el-radio__label {
- font-weight: normal !important;
- color: #333 !important;
- }
- /* 禁用状态文字颜色增强 */
- .el-input.is-disabled .el-input__inner,
- .el-textarea.is-disabled .el-textarea__inner {
- color: #606266 !important;
- -webkit-text-fill-color: #606266 !important;
- }
- }
- </style>
|