You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

175 lines
12 KiB

import { defineComponent, computed, ref, reactive, unref, useSSRContext } from 'vue';
import { ssrRenderAttrs, ssrIncludeBooleanAttr, ssrRenderAttr, ssrLooseContain, ssrLooseEqual, ssrRenderList, ssrInterpolate, ssrRenderClass } from 'vue/server-renderer';
import { u as useApi } from './useApi-BNSkSrat.mjs';
import { u as useToast } from './useToast-MBvLaNjH.mjs';
import { a as useAuthStore } from './server.mjs';
import '../nitro/nitro.mjs';
import 'node:http';
import 'node:https';
import 'node:events';
import 'node:buffer';
import 'node:fs';
import 'node:path';
import 'node:crypto';
import 'node:url';
import '../routes/renderer.mjs';
import 'vue-bundle-renderer/runtime';
import 'unhead/server';
import 'devalue';
import 'unhead/utils';
import 'pinia';
import 'perfect-debounce';
const _sfc_main = /* @__PURE__ */ defineComponent({
__name: "settlements",
__ssrInlineRender: true,
setup(__props) {
useApi();
useToast();
const auth = useAuthStore();
const canManage = computed(() => auth.isAdmin);
const rows = ref([]);
const brands = ref([]);
const channels = ref([]);
const loading = ref(false);
const generating = ref(false);
const totals = reactive({ base: 0, brandNet: 0, channel: 0, platform: 0 });
const filters = reactive({ month: prevMonthStr(), brandid: 0, channelid: "", status: -1 });
const channelOptions = computed(
() => filters.brandid ? channels.value.filter((ch) => ch.brandid === filters.brandid) : channels.value
);
const summaryCards = computed(() => [
{ label: "结算基数(订单实付)", value: totals.base, cls: "text-slate-800" },
{ label: "品牌商实得", value: totals.brandNet, cls: "text-emerald-600" },
{ label: "渠道商分成", value: totals.channel, cls: "text-indigo-600" },
{ label: "平台留存", value: totals.platform, cls: "text-slate-600" }
]);
function prevMonthStr() {
const d = /* @__PURE__ */ new Date();
d.setDate(1);
d.setMonth(d.getMonth() - 1);
return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0");
}
function fmtPeriod(p) {
if (!p) return "-";
return Math.floor(p / 100) + "-" + String(p % 100).padStart(2, "0");
}
function fmtMoney(cents) {
return "¥" + ((Number(cents) || 0) / 100).toFixed(2);
}
function ratePct(rate) {
return ((Number(rate) || 0) / 100).toFixed(2) + "%";
}
function brandName(id) {
if (!id) return "未归属品牌商";
const b = brands.value.find((x) => x.id === id);
return b ? b.brand : "品牌商#" + Number(id).toString(16).toUpperCase();
}
function channelName(id) {
if (!id) return "未分配渠道";
const ch = channels.value.find((x) => x.id === id);
return ch ? ch.name + " (" + ch.id + ")" : id;
}
const STATUS_LABELS = { 0: "草稿", 1: "已确认", 2: "已支付" };
const STATUS_CLASS = { 0: "badge-ghost", 1: "badge-warning", 2: "badge-success" };
function statusLabel(s) {
return STATUS_LABELS[s] ?? String(s);
}
function statusClass(s) {
return STATUS_CLASS[s] ?? "badge-ghost";
}
return (_ctx, _push, _parent, _attrs) => {
_push(`<div${ssrRenderAttrs(_attrs)}><div class="flex items-center justify-between mb-5 flex-wrap gap-3"><h2 class="text-lg font-semibold text-slate-800"> 月结算<span class="text-xs text-slate-400 font-normal ml-2">按订单实付金额分成,渠道商从品牌商那份里再切</span></h2>`);
if (canManage.value) {
_push(`<div class="flex gap-2"><button class="btn btn-primary btn-sm text-white"${ssrIncludeBooleanAttr(generating.value) ? " disabled" : ""}>`);
if (generating.value) {
_push(`<span class="loading loading-spinner loading-xs"></span>`);
} else {
_push(`<!---->`);
}
_push(`生成 / 重算本月账 </button><button class="btn btn-ghost btn-sm"${ssrIncludeBooleanAttr(!rows.value.length) ? " disabled" : ""}>导出 CSV</button></div>`);
} else {
_push(`<!---->`);
}
_push(`</div><div class="bg-white rounded-xl shadow-sm border border-slate-100 p-4 mb-4"><div class="flex flex-wrap items-end gap-3"><div class="form-control"><label class="label py-1"><span class="label-text text-xs text-slate-500">结算月</span></label><input${ssrRenderAttr("value", filters.month)} type="month" class="input input-bordered input-sm w-44"></div>`);
if (!unref(auth).isBrandAccount && !unref(auth).isDealer) {
_push(`<div class="form-control"><label class="label py-1"><span class="label-text text-xs text-slate-500">品牌商</span></label><select class="select select-bordered select-sm w-48"><option${ssrRenderAttr("value", 0)}${ssrIncludeBooleanAttr(Array.isArray(filters.brandid) ? ssrLooseContain(filters.brandid, 0) : ssrLooseEqual(filters.brandid, 0)) ? " selected" : ""}>全部品牌商</option><!--[-->`);
ssrRenderList(brands.value, (b) => {
_push(`<option${ssrRenderAttr("value", b.id)}${ssrIncludeBooleanAttr(Array.isArray(filters.brandid) ? ssrLooseContain(filters.brandid, b.id) : ssrLooseEqual(filters.brandid, b.id)) ? " selected" : ""}>${ssrInterpolate(b.brand)}</option>`);
});
_push(`<!--]--></select></div>`);
} else {
_push(`<!---->`);
}
if (!unref(auth).isDealer) {
_push(`<div class="form-control"><label class="label py-1"><span class="label-text text-xs text-slate-500">渠道商</span></label><select class="select select-bordered select-sm w-52"><option value=""${ssrIncludeBooleanAttr(Array.isArray(filters.channelid) ? ssrLooseContain(filters.channelid, "") : ssrLooseEqual(filters.channelid, "")) ? " selected" : ""}>全部渠道商</option><!--[-->`);
ssrRenderList(channelOptions.value, (ch) => {
_push(`<option${ssrRenderAttr("value", ch.id)}${ssrIncludeBooleanAttr(Array.isArray(filters.channelid) ? ssrLooseContain(filters.channelid, ch.id) : ssrLooseEqual(filters.channelid, ch.id)) ? " selected" : ""}>${ssrInterpolate(ch.name)} (${ssrInterpolate(ch.id)})</option>`);
});
_push(`<!--]--></select></div>`);
} else {
_push(`<!---->`);
}
_push(`<div class="form-control"><label class="label py-1"><span class="label-text text-xs text-slate-500">状态</span></label><select class="select select-bordered select-sm w-32"><option${ssrRenderAttr("value", -1)}${ssrIncludeBooleanAttr(Array.isArray(filters.status) ? ssrLooseContain(filters.status, -1) : ssrLooseEqual(filters.status, -1)) ? " selected" : ""}>全部状态</option><option${ssrRenderAttr("value", 0)}${ssrIncludeBooleanAttr(Array.isArray(filters.status) ? ssrLooseContain(filters.status, 0) : ssrLooseEqual(filters.status, 0)) ? " selected" : ""}>草稿</option><option${ssrRenderAttr("value", 1)}${ssrIncludeBooleanAttr(Array.isArray(filters.status) ? ssrLooseContain(filters.status, 1) : ssrLooseEqual(filters.status, 1)) ? " selected" : ""}>已确认</option><option${ssrRenderAttr("value", 2)}${ssrIncludeBooleanAttr(Array.isArray(filters.status) ? ssrLooseContain(filters.status, 2) : ssrLooseEqual(filters.status, 2)) ? " selected" : ""}>已支付</option></select></div><button class="btn btn-sm btn-primary text-white">查询</button></div></div><div class="grid grid-cols-2 md:grid-cols-4 gap-3 mb-4"><!--[-->`);
ssrRenderList(summaryCards.value, (card) => {
_push(`<div class="bg-white rounded-xl shadow-sm border border-slate-100 p-4"><div class="text-xs text-slate-500">${ssrInterpolate(card.label)}</div><div class="${ssrRenderClass([card.cls, "text-xl font-semibold mt-1"])}">${ssrInterpolate(fmtMoney(card.value))}</div></div>`);
});
_push(`<!--]--></div><div class="bg-white rounded-xl shadow-sm border border-slate-100"><div class="overflow-x-auto"><table class="table table-zebra text-sm"><thead><tr><th>结算月</th><th>品牌商</th><th>渠道商</th><th class="text-right">订单数</th><th class="text-right">结算基数</th><th class="text-right">品牌比例</th><th class="text-right">品牌实得</th><th class="text-right">渠道比例</th><th class="text-right">渠道分成</th><th class="text-right">平台留存</th><th>状态</th>`);
if (canManage.value) {
_push(`<th>操作</th>`);
} else {
_push(`<!---->`);
}
_push(`</tr></thead><tbody>`);
if (loading.value) {
_push(`<tr><td${ssrRenderAttr("colspan", canManage.value ? 12 : 11)} class="text-center py-8"><span class="loading loading-spinner loading-sm"></span></td></tr>`);
} else if (!rows.value.length) {
_push(`<tr><td${ssrRenderAttr("colspan", canManage.value ? 12 : 11)} class="text-center text-slate-400 py-8">该月暂无结算数据</td></tr>`);
} else {
_push(`<!--[-->`);
ssrRenderList(rows.value, (r, i) => {
_push(`<tr><td class="font-mono">${ssrInterpolate(fmtPeriod(r.period))}</td><td>${ssrInterpolate(brandName(r.brandid))}</td><td>${ssrInterpolate(channelName(r.channelid))}</td><td class="text-right">${ssrInterpolate(r.order_count)}</td><td class="text-right font-medium">${ssrInterpolate(fmtMoney(r.base_amount))}</td><td class="text-right text-slate-500">${ssrInterpolate(ratePct(r.brand_rate))}</td><td class="text-right text-emerald-600 font-medium">${ssrInterpolate(fmtMoney(r.brand_net))}</td><td class="text-right text-slate-500">${ssrInterpolate(ratePct(r.channel_rate))}</td><td class="text-right text-indigo-600 font-medium">${ssrInterpolate(fmtMoney(r.channel_amount))}</td><td class="text-right text-slate-500">${ssrInterpolate(fmtMoney(r.platform_amount))}</td><td><span class="${ssrRenderClass([statusClass(r.status), "badge badge-sm"])}">${ssrInterpolate(statusLabel(r.status))}</span>`);
if (r.confirm_account) {
_push(`<div class="text-[11px] text-slate-400 mt-0.5">${ssrInterpolate(r.confirm_account)}</div>`);
} else {
_push(`<!---->`);
}
_push(`</td>`);
if (canManage.value) {
_push(`<td><div class="flex flex-wrap gap-1">`);
if (r.status === 0) {
_push(`<button class="btn btn-ghost btn-xs text-emerald-600">确认</button>`);
} else {
_push(`<!---->`);
}
if (r.status === 1) {
_push(`<button class="btn btn-ghost btn-xs text-indigo-600">标记已付</button>`);
} else {
_push(`<!---->`);
}
if (r.status > 0) {
_push(`<button class="btn btn-ghost btn-xs text-amber-600">退回草稿</button>`);
} else {
_push(`<!---->`);
}
_push(`</div></td>`);
} else {
_push(`<!---->`);
}
_push(`</tr>`);
});
_push(`<!--]-->`);
}
_push(`</tbody></table></div></div><p class="text-xs text-slate-400 mt-3 leading-relaxed"> 结算基数 = 该月<b>已支付</b>订单实付金额合计,订单按下单时冻结的「来源设备」归属到品牌商与渠道商。<br> 品牌商总提成 = 基数 × 品牌比例;渠道分成 = 品牌总提成 × 渠道比例;品牌实得 = 品牌总提成 − 渠道分成;平台留存 = 基数 − 品牌总提成。<br> 比例在生成结算单时快照冻结,之后调整比例不影响已生成的月份;<b>已确认</b>的行重算时会跳过,需先退回草稿才能重算。 </p></div>`);
};
}
});
const _sfc_setup = _sfc_main.setup;
_sfc_main.setup = (props, ctx) => {
const ssrContext = useSSRContext();
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("pages/settlements.vue");
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
};
export { _sfc_main as default };
//# sourceMappingURL=settlements-36wv6bGk.mjs.map