更新若干功能
This commit is contained in:
1 parent
892ba5886d
commit
79d5ae6b66
45 files changed
+6755
-38
No files matched your search
@@ -7,11 +7,37 @@
|
||||
@update:model-value="handleClose"
|
||||
@opened="loadAll"
|
||||
>
|
||||
<!-- 标题 + 右上角阶段流转(与合同 / 项目详情一致) -->
|
||||
<!-- 标题 + 右上角状态 / 阶段流转(与合同 / 项目详情一致) -->
|
||||
<template #header>
|
||||
<div class="drawer-header">
|
||||
<span class="drawer-title">{{ business?.business_name || "商机详情" }}</span>
|
||||
<div v-if="business" class="drawer-actions">
|
||||
<!-- 状态流转:跟不下去的商机可废弃,废弃后可恢复为跟进中 -->
|
||||
<el-dropdown
|
||||
v-if="statusOptionsExcept(business.status).length"
|
||||
trigger="click"
|
||||
@command="(cmd) => handleChangeStatus(cmd)"
|
||||
>
|
||||
<el-button
|
||||
link
|
||||
type="info"
|
||||
size="small"
|
||||
:disabled="Number(business.locked) === 1 || Number(business.status) === 2"
|
||||
>
|
||||
状态流转<el-icon style="margin-left: 2px"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item
|
||||
v-for="i in statusOptionsExcept(business.status)"
|
||||
:key="i.value"
|
||||
:command="i.value"
|
||||
>
|
||||
{{ i.label }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<el-dropdown
|
||||
v-if="stageOptionsExcept(business.stage).length"
|
||||
trigger="click"
|
||||
@@ -21,7 +47,11 @@
|
||||
link
|
||||
type="warning"
|
||||
size="small"
|
||||
:disabled="Number(business.locked) === 1 || Number(business.status) === 2"
|
||||
:disabled="
|
||||
Number(business.locked) === 1 ||
|
||||
Number(business.status) === 2 ||
|
||||
Number(business.status) === 3
|
||||
"
|
||||
>
|
||||
阶段流转<el-icon style="margin-left: 2px"><ArrowDown /></el-icon>
|
||||
</el-button>
|
||||
@@ -42,6 +72,14 @@
|
||||
</template>
|
||||
|
||||
<div v-if="business" class="biz-detail">
|
||||
<el-alert
|
||||
v-if="Number(business.status) === 3"
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="该商机已废弃,可点击右上角「状态流转」恢复为「跟进中」后继续推进"
|
||||
style="margin-bottom: 12px"
|
||||
/>
|
||||
<el-tabs v-model="activeTab" tab-position="left" class="detail-tabs">
|
||||
<!-- 基本信息 -->
|
||||
<el-tab-pane label="基本信息" name="basic">
|
||||
@@ -98,8 +136,13 @@
|
||||
import { ref, reactive, watch } from "vue";
|
||||
import { ArrowDown } from "@element-plus/icons-vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { changeBusinessStage } from "@/api/crmPipeline";
|
||||
import { BUSINESS_STAGE_OPTIONS, businessStageText } from "../../dict";
|
||||
import { changeBusinessStage, changeBusinessStatus } from "@/api/crmPipeline";
|
||||
import {
|
||||
BUSINESS_STAGE_OPTIONS,
|
||||
BUSINESS_STATUS_OPTIONS,
|
||||
businessStageText,
|
||||
businessStatusText,
|
||||
} from "../../dict";
|
||||
import DetailBasic from "./detail_basic.vue";
|
||||
import DetailContact from "./detail_contact.vue";
|
||||
import DetailFollow from "./detail_follow.vue";
|
||||
@@ -139,6 +182,29 @@ function handleClose() {
|
||||
emit("update:visible", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 可流转的状态:排除当前状态与「已转化项目」。
|
||||
* 已转化必须走「转项目」流程(会锁定商机),不能只改状态。
|
||||
*/
|
||||
function statusOptionsExcept(cur) {
|
||||
return BUSINESS_STATUS_OPTIONS.filter(
|
||||
(i) => String(i.value) !== String(cur) && String(i.value) !== "2"
|
||||
);
|
||||
}
|
||||
|
||||
/** 状态流转:仅更新状态字段,成功后同步本地展示并通知列表刷新 */
|
||||
async function handleChangeStatus(status) {
|
||||
if (!props.business?.id) return;
|
||||
try {
|
||||
await changeBusinessStatus(props.business.id, Number(status));
|
||||
ElMessage.success(`状态已更新为「${businessStatusText(status)}」`);
|
||||
props.business.status = Number(status);
|
||||
emit("refresh");
|
||||
} catch (e) {
|
||||
ElMessage.error(e.message || "状态更新失败");
|
||||
}
|
||||
}
|
||||
|
||||
/** 可流转的阶段:排除当前阶段 */
|
||||
function stageOptionsExcept(cur) {
|
||||
return BUSINESS_STAGE_OPTIONS.filter((i) => String(i.value) !== String(cur));
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
<el-table-column label="下次联系时间" width="160" align="center">
|
||||
<template #default="{ row }">{{ formatDateTime(row.next_contact_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center" fixed="right">
|
||||
<el-table-column label="操作" width="280" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" :disabled="row.locked === 1" @click="openEdit(row)">
|
||||
编辑
|
||||
@@ -91,11 +91,31 @@
|
||||
link
|
||||
type="warning"
|
||||
size="small"
|
||||
:disabled="row.locked === 1 || row.status === 2"
|
||||
:disabled="row.locked === 1 || row.status === 2 || row.status === 3"
|
||||
@click="openConvert(row)"
|
||||
>
|
||||
转项目
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 3"
|
||||
link
|
||||
type="success"
|
||||
size="small"
|
||||
:disabled="row.locked === 1"
|
||||
@click="handleRestore(row)"
|
||||
>
|
||||
恢复
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
link
|
||||
type="info"
|
||||
size="small"
|
||||
:disabled="row.locked === 1 || row.status === 2"
|
||||
@click="handleDiscard(row)"
|
||||
>
|
||||
废弃
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
@@ -138,7 +158,7 @@
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { Plus, Search, Refresh } from "@element-plus/icons-vue";
|
||||
import { getBusinessList, deleteBusiness } from "@/api/crmPipeline";
|
||||
import { getBusinessList, deleteBusiness, changeBusinessStatus } from "@/api/crmPipeline";
|
||||
import BusinessEdit from "./components/edit.vue";
|
||||
import BusinessConvert from "./components/convert.vue";
|
||||
import BusinessDetail from "./components/detail.vue";
|
||||
@@ -228,6 +248,36 @@ function handleConvertSuccess() {
|
||||
ElMessage.success("商机已转化为项目,可在项目管理中继续跟进");
|
||||
}
|
||||
|
||||
/** 废弃商机:保留全部过程数据,仅把状态置为已废弃,可随时恢复 */
|
||||
async function handleDiscard(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定废弃商机「${row.business_name}」吗?废弃后可随时恢复为「跟进中」。`,
|
||||
"废弃确认",
|
||||
{ type: "warning" }
|
||||
);
|
||||
await changeBusinessStatus(row.id, 3);
|
||||
ElMessage.success("商机已废弃");
|
||||
fetchList();
|
||||
} catch (e) {
|
||||
if (e !== "cancel") ElMessage.error(e.message || "废弃失败");
|
||||
}
|
||||
}
|
||||
|
||||
/** 恢复商机:把已废弃的商机恢复为跟进中 */
|
||||
async function handleRestore(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定将商机「${row.business_name}」恢复为「跟进中」吗?`, "恢复确认", {
|
||||
type: "info",
|
||||
});
|
||||
await changeBusinessStatus(row.id, 1);
|
||||
ElMessage.success("商机已恢复为跟进中");
|
||||
fetchList();
|
||||
} catch (e) {
|
||||
if (e !== "cancel") ElMessage.error(e.message || "恢复失败");
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDelete(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除商机「${row.business_name}」吗?删除后不可恢复。`, "删除确认", {
|
||||
|
||||
@@ -63,6 +63,14 @@
|
||||
title="该线索已转化为商机并锁定,后续请在商机管理中操作;商机详情会按阶段展示线索 + 商机的联系人、跟进记录与附件"
|
||||
style="margin-bottom: 12px"
|
||||
/>
|
||||
<el-alert
|
||||
v-if="Number(clue.status) === 3"
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="该线索已废弃,可点击右上角「状态流转」恢复为「跟进中」后继续跟进"
|
||||
style="margin-bottom: 12px"
|
||||
/>
|
||||
<el-tabs v-model="activeTab" tab-position="left" class="detail-tabs">
|
||||
<!-- 基本信息 -->
|
||||
<el-tab-pane label="基本信息" name="basic">
|
||||
|
||||
@@ -84,18 +84,38 @@
|
||||
<el-table-column label="创建时间" width="160" align="center">
|
||||
<template #default="{ row }">{{ formatDateTime(row.create_time) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" align="center" fixed="right">
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<!-- 编辑 / 删除已收口到「线索详情」内,列表只保留转化 -->
|
||||
<!-- 编辑 / 删除已收口到「线索详情」内,列表保留转化 / 废弃 -->
|
||||
<el-button
|
||||
link
|
||||
type="warning"
|
||||
size="small"
|
||||
:disabled="row.locked === 1 || row.status === 2"
|
||||
:disabled="row.locked === 1 || row.status === 2 || row.status === 3"
|
||||
@click="openConvert(row)"
|
||||
>
|
||||
转化
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 3"
|
||||
link
|
||||
type="success"
|
||||
size="small"
|
||||
:disabled="row.locked === 1"
|
||||
@click="handleRestore(row)"
|
||||
>
|
||||
恢复
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
link
|
||||
type="info"
|
||||
size="small"
|
||||
:disabled="row.locked === 1 || row.status === 2"
|
||||
@click="handleDiscard(row)"
|
||||
>
|
||||
废弃
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty><el-empty description="暂无线索" :image-size="80" /></template>
|
||||
@@ -130,7 +150,7 @@
|
||||
import { ref, reactive, onMounted } from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import { Plus, Search, Refresh } from "@element-plus/icons-vue";
|
||||
import { getClueList, deleteClue } from "@/api/crmPipeline";
|
||||
import { getClueList, deleteClue, changeClueStatus } from "@/api/crmPipeline";
|
||||
import ClueEdit from "./components/edit.vue";
|
||||
import ClueConvert from "./components/convert.vue";
|
||||
import ClueDetail from "./components/detail.vue";
|
||||
@@ -218,6 +238,36 @@ function handleConvertSuccess() {
|
||||
ElMessage.success("线索已转化,可在商机管理中继续跟进");
|
||||
}
|
||||
|
||||
/** 废弃线索:保留全部过程数据,仅把状态置为已废弃,可随时恢复 */
|
||||
async function handleDiscard(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确定废弃线索「${row.clue_name}」吗?废弃后可随时恢复为「跟进中」。`,
|
||||
"废弃确认",
|
||||
{ type: "warning" }
|
||||
);
|
||||
await changeClueStatus(row.id, 3);
|
||||
ElMessage.success("线索已废弃");
|
||||
fetchList();
|
||||
} catch (e) {
|
||||
if (e !== "cancel") ElMessage.error(e.message || "废弃失败");
|
||||
}
|
||||
}
|
||||
|
||||
/** 恢复线索:把已废弃的线索恢复为跟进中 */
|
||||
async function handleRestore(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定将线索「${row.clue_name}」恢复为「跟进中」吗?`, "恢复确认", {
|
||||
type: "info",
|
||||
});
|
||||
await changeClueStatus(row.id, 1);
|
||||
ElMessage.success("线索已恢复为跟进中");
|
||||
fetchList();
|
||||
} catch (e) {
|
||||
if (e !== "cancel") ElMessage.error(e.message || "恢复失败");
|
||||
}
|
||||
}
|
||||
|
||||
/** 详情内编辑:收起详情后打开编辑弹窗(详情数据即当前行) */
|
||||
function handleDetailEdit() {
|
||||
detailVisible.value = false;
|
||||
|
||||
@@ -176,11 +176,11 @@ export const BUSINESS_STAGE_OPTIONS = [
|
||||
{ label: "输单", value: "6" },
|
||||
];
|
||||
|
||||
/** 商机状态 */
|
||||
/** 商机状态:跳过一半无法继续推进的商机可废弃(可恢复为跟进中) */
|
||||
export const BUSINESS_STATUS_OPTIONS = [
|
||||
{ label: "跟进中", value: "1" },
|
||||
{ label: "已转化项目", value: "2" },
|
||||
{ label: "已关闭", value: "3" },
|
||||
{ label: "已废弃", value: "3" },
|
||||
];
|
||||
|
||||
/** 项目状态 */
|
||||
|
||||
Reference in new issue
Block a user