|
|
|
|
@@ -3,6 +3,7 @@ const state = {
|
|
|
|
|
data: null,
|
|
|
|
|
opFilter: "all",
|
|
|
|
|
chart: null,
|
|
|
|
|
chart2: null,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const money = (value) => `${Number(value || 0).toLocaleString("zh-CN")} 万`;
|
|
|
|
|
@@ -143,10 +144,15 @@ function formHtml(fields, button) {
|
|
|
|
|
|
|
|
|
|
async function createResource(event, resource) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
const data = Object.fromEntries(new FormData(event.currentTarget).entries());
|
|
|
|
|
const form = event.currentTarget;
|
|
|
|
|
const data = Object.fromEntries(new FormData(form).entries());
|
|
|
|
|
try {
|
|
|
|
|
await api(`/api/${resource}`, { method: "POST", body: JSON.stringify({ data }) });
|
|
|
|
|
event.currentTarget.reset();
|
|
|
|
|
form.reset();
|
|
|
|
|
await load();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
alert("创建失败:" + error.message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.createSales = (event) => createResource(event, "sales");
|
|
|
|
|
@@ -161,11 +167,11 @@ function renderSales() {
|
|
|
|
|
const salesClicks = state.data.sales.map((x) => ({ resource: "sales", id: x.id }));
|
|
|
|
|
document.querySelector("#sales").innerHTML = `<div class="grid gap-4">
|
|
|
|
|
${card(formHtml([
|
|
|
|
|
{ label: "目标客户", input: `<input name="target_customer" required placeholder="客户名称">` },
|
|
|
|
|
{ label: "业务机会", input: `<input name="target_customer" required placeholder="客户名称">` },
|
|
|
|
|
{ label: "优先级", input: `<select name="priority"><option>P0</option><option selected>P1</option><option>P2</option><option>P3</option></select>` },
|
|
|
|
|
{ label: "状态", input: `<select name="status"><option>待跟进</option><option>跟进中</option><option>方案中</option><option>商务谈判</option><option>已签约</option><option>暂缓</option><option>已丢单</option></select>` },
|
|
|
|
|
], { handler: "createSales", text: `<i data-lucide="plus"></i>新增客户` }), "p-4")}
|
|
|
|
|
${renderTable(["目标客户", "优先级", "状态", "最新跟进记录"], rows, salesClicks)}
|
|
|
|
|
], { handler: "createSales", text: `<i data-lucide="plus"></i>新增业务机会` }), "p-4")}
|
|
|
|
|
${renderTable(["业务机会", "优先级", "状态", "最新跟进记录"], rows, salesClicks)}
|
|
|
|
|
</div>`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -245,7 +251,7 @@ function renderProducts() {
|
|
|
|
|
function renderFinance() {
|
|
|
|
|
const rows = state.data.finance.map((x) => [x.month, badge(x.record_type === "revenue" ? "收入" : "成本/费用"), x.category, money(x.amount), x.occurred_date, text(x.notes)]);
|
|
|
|
|
document.querySelector("#finance").innerHTML = `<div class="grid gap-4">
|
|
|
|
|
${card(`<h2 class="mb-4 text-lg font-bold">收入、毛利、成本/费用、净利月度曲线</h2><canvas id="financeChart2" height="105"></canvas>`, "p-5")}
|
|
|
|
|
${card(`<h2 class="mb-4 text-lg font-bold">收入、毛利、成本/费用、净利月度曲线</h2><div style="position:relative;height:300px"><canvas id="financeChart2"></canvas></div>`, "p-5")}
|
|
|
|
|
${card(formHtml([
|
|
|
|
|
{ label: "月份", input: `<input name="month" required placeholder="YYYY-MM" pattern="\\d{4}-\\d{2}">` },
|
|
|
|
|
{ label: "类型", input: `<select name="record_type"><option value="revenue">收入</option><option value="cost_expense">成本/费用</option></select>` },
|
|
|
|
|
@@ -261,7 +267,8 @@ function renderFinance() {
|
|
|
|
|
function renderChartOn(id, data) {
|
|
|
|
|
const canvas = document.querySelector(`#${id}`);
|
|
|
|
|
if (!canvas || !window.Chart) return;
|
|
|
|
|
new Chart(canvas, {
|
|
|
|
|
if (state.chart2) state.chart2.destroy();
|
|
|
|
|
state.chart2 = new Chart(canvas, {
|
|
|
|
|
type: "line",
|
|
|
|
|
data: {
|
|
|
|
|
labels: data.map((x) => x.month),
|
|
|
|
|
@@ -292,9 +299,9 @@ function openDrawer(resource, id) {
|
|
|
|
|
const item = list.find((x) => x.id === id);
|
|
|
|
|
const drawer = document.querySelector("#drawer");
|
|
|
|
|
const fields = resource === "sales"
|
|
|
|
|
? [["target_customer","目标客户"],["priority","优先级"],["status","状态"]]
|
|
|
|
|
? [["target_customer","业务机会"],["priority","优先级"],["status","状态"]]
|
|
|
|
|
: resource === "operations"
|
|
|
|
|
? [["project_name","项目名称"],["project_version","项目版本"],["project_status","项目状态"],["current_stage","当前阶段"],["target_customer","目标客户"],["customer_need","客户需求"],["expected_contract_amount","预计签约金额"],["expected_sign_date","预计签约时间"],["sign_probability","签约概率"],["sop_stage","SOP 阶段"],["execution_progress","执行进度"],["current_deliverable","当前交付物"],["risks","风险与阻塞"],["next_action","下一步动作"]]
|
|
|
|
|
? [["project_name","项目名称"],["project_version","项目版本"],["project_status","项目状态"],["current_stage","当前阶段"],["target_customer","业务机会"],["customer_need","客户需求"],["expected_contract_amount","预计签约金额"],["expected_sign_date","预计签约时间"],["sign_probability","签约概率"],["sop_stage","SOP 阶段"],["execution_progress","执行进度"],["current_deliverable","当前交付物"],["risks","风险与阻塞"],["next_action","下一步动作"]]
|
|
|
|
|
: resource === "proposals"
|
|
|
|
|
? [["customer_or_project_name","客户/项目"],["version","版本号"],["description","版本说明"],["created_date","创建日期"],["status","状态"]]
|
|
|
|
|
: [["product_name","产品名称"],["version","版本号"],["version_goal","版本目标"],["feature_list","核心功能清单"],["launch_date","上线日期"],["status","当前状态"],["notes","备注"]];
|
|
|
|
|
|