增加商机线索管理修复若干bug
This commit is contained in:
1 parent
b9cdabe045
commit
9c07af2b59
39 files changed
+6219
-42
No files matched your search
@@ -0,0 +1,258 @@
|
||||
<template>
|
||||
<div class="crm-page">
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h2>商机管理</h2>
|
||||
<p>推进商机阶段,达成后可转化为项目;转化后商机将锁定不可编辑</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<el-button :icon="Refresh" @click="fetchList">刷新</el-button>
|
||||
<el-button type="primary" :icon="Plus" @click="openCreate">新增商机</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="filter-bar">
|
||||
<el-form :inline="true" :model="filters" @submit.prevent>
|
||||
<el-form-item>
|
||||
<el-input
|
||||
v-model="filters.keyword"
|
||||
clearable
|
||||
placeholder="搜索商机名称 / 客户 / 对接人"
|
||||
:prefix-icon="Search"
|
||||
style="width: 260px"
|
||||
@keyup.enter="handleSearch"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="商机阶段">
|
||||
<el-select v-model="filters.stage" clearable placeholder="全部" style="width: 130px">
|
||||
<el-option v-for="i in BUSINESS_STAGE_OPTIONS" :key="i.value" :label="i.label" :value="i.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="级别">
|
||||
<el-select v-model="filters.level" clearable placeholder="全部" style="width: 110px">
|
||||
<el-option v-for="i in PIPELINE_LEVEL_OPTIONS" :key="i.value" :label="i.label" :value="i.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="filters.status" clearable placeholder="全部" style="width: 130px">
|
||||
<el-option v-for="i in BUSINESS_STATUS_OPTIONS" :key="i.value" :label="i.label" :value="i.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
|
||||
<el-button :icon="Refresh" @click="resetFilters">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<div class="table-container" v-loading="loading">
|
||||
<el-table :data="tableData" stripe border row-key="id">
|
||||
<el-table-column label="商机名称" min-width="170" show-overflow-tooltip fixed>
|
||||
<template #default="{ row }">
|
||||
<span class="name-link" @click="openDetail(row)">{{ row.business_name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="customer_name" label="客户名称" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column label="商机阶段" width="110" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="businessStageTag(row.stage)" size="small">{{ businessStageText(row.stage) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="级别" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="pipelineLevelTag(row.level)" size="small" effect="plain">
|
||||
{{ pipelineLevelText(row.level) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="预计金额" width="130" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.amount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="预计成交日期" width="130" align="center">
|
||||
<template #default="{ row }">{{ formatDateOnly(row.expect_deal_date) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="负责人" width="100">
|
||||
<template #default="{ row }">{{ row.owner_user_name || "-" }}</template>
|
||||
</el-table-column>
|
||||
<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="110" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="businessStatusTag(row.status)" size="small">{{ businessStatusText(row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" :disabled="row.locked === 1" @click="openEdit(row)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="warning"
|
||||
size="small"
|
||||
:disabled="row.locked === 1 || row.status === 2"
|
||||
@click="openConvert(row)"
|
||||
>
|
||||
转项目
|
||||
</el-button>
|
||||
<el-button link type="danger" size="small" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template #empty><el-empty description="暂无商机" :image-size="80" /></template>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSearch"
|
||||
@current-change="fetchList"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BusinessEdit v-model:visible="editVisible" :edit-data="currentRow" @success="fetchList" />
|
||||
<BusinessConvert v-model:visible="convertVisible" :business="currentRow" @success="handleConvertSuccess" />
|
||||
|
||||
<el-dialog v-model="detailVisible" :title="currentRow?.business_name || '商机详情'" width="720px">
|
||||
<el-descriptions v-if="currentRow" :column="2" border size="small">
|
||||
<el-descriptions-item label="商机名称" :span="2">{{ currentRow.business_name }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户名称">{{ currentRow.customer_name || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户来源">{{ clueSourceText(currentRow.source) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="商机阶段">
|
||||
<el-tag :type="businessStageTag(currentRow.stage)" size="small">{{ businessStageText(currentRow.stage) }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="级别">
|
||||
<el-tag :type="pipelineLevelTag(currentRow.level)" size="small">{{ pipelineLevelText(currentRow.level) }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="预计金额">{{ formatMoney(currentRow.amount) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="预计成交日期">{{ formatDateOnly(currentRow.expect_deal_date) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="负责人">{{ currentRow.owner_user_name || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="下次联系时间">{{ formatDateTime(currentRow.next_contact_time) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="对接人">{{ currentRow.contact_person || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="对接人职位">{{ currentRow.contact_position || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="对接人手机">{{ currentRow.contact_phone || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户地址" :span="2">{{ currentRow.address || "-" }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="businessStatusTag(currentRow.status)" size="small">{{ businessStatusText(currentRow.status) }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="转化时间">{{ formatDateTime(currentRow.convert_time) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="备注" :span="2">{{ currentRow.remark || "-" }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
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 BusinessEdit from "./components/edit.vue";
|
||||
import BusinessConvert from "./components/convert.vue";
|
||||
import {
|
||||
BUSINESS_STAGE_OPTIONS,
|
||||
BUSINESS_STATUS_OPTIONS,
|
||||
PIPELINE_LEVEL_OPTIONS,
|
||||
businessStageText,
|
||||
businessStageTag,
|
||||
businessStatusText,
|
||||
businessStatusTag,
|
||||
pipelineLevelText,
|
||||
pipelineLevelTag,
|
||||
clueSourceText,
|
||||
formatMoney,
|
||||
formatDateOnly,
|
||||
formatDateTime,
|
||||
} from "../dict";
|
||||
|
||||
const loading = ref(false);
|
||||
const tableData = ref([]);
|
||||
const editVisible = ref(false);
|
||||
const convertVisible = ref(false);
|
||||
const detailVisible = ref(false);
|
||||
const currentRow = ref(null);
|
||||
|
||||
const filters = reactive({ keyword: "", stage: "", level: "", status: "" });
|
||||
const pagination = reactive({ page: 1, pageSize: 20, total: 0 });
|
||||
|
||||
onMounted(() => {
|
||||
fetchList();
|
||||
});
|
||||
|
||||
async function fetchList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await getBusinessList({
|
||||
page: pagination.page,
|
||||
pageSize: pagination.pageSize,
|
||||
...filters,
|
||||
});
|
||||
tableData.value = res?.data?.list || [];
|
||||
pagination.total = res?.data?.total || 0;
|
||||
} catch (e) {
|
||||
tableData.value = [];
|
||||
pagination.total = 0;
|
||||
ElMessage.error(e.message || "查询失败");
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
pagination.page = 1;
|
||||
fetchList();
|
||||
}
|
||||
|
||||
function resetFilters() {
|
||||
filters.keyword = "";
|
||||
filters.stage = "";
|
||||
filters.level = "";
|
||||
filters.status = "";
|
||||
handleSearch();
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
currentRow.value = null;
|
||||
editVisible.value = true;
|
||||
}
|
||||
|
||||
function openEdit(row) {
|
||||
currentRow.value = { ...row };
|
||||
editVisible.value = true;
|
||||
}
|
||||
|
||||
function openConvert(row) {
|
||||
currentRow.value = { ...row };
|
||||
convertVisible.value = true;
|
||||
}
|
||||
|
||||
function openDetail(row) {
|
||||
currentRow.value = { ...row };
|
||||
detailVisible.value = true;
|
||||
}
|
||||
|
||||
function handleConvertSuccess() {
|
||||
fetchList();
|
||||
ElMessage.success("商机已转化为项目,可在项目管理中继续跟进");
|
||||
}
|
||||
|
||||
async function handleDelete(row) {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除商机「${row.business_name}」吗?删除后不可恢复。`, "删除确认", {
|
||||
type: "warning",
|
||||
});
|
||||
await deleteBusiness(row.id);
|
||||
ElMessage.success("删除成功");
|
||||
fetchList();
|
||||
} catch (e) {
|
||||
if (e !== "cancel") ElMessage.error(e.message || "删除失败");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped src="../styles/crm-page.less"></style>
|
||||
Reference in new issue
Block a user