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.
 
 
 
 
 
 

199 lines
20 KiB

import { defineComponent, ref, reactive, computed, watch, unref, useSSRContext } from 'vue';
import { ssrRenderAttrs, ssrRenderStyle, ssrRenderList, ssrInterpolate, ssrRenderClass, ssrRenderAttr, ssrIncludeBooleanAttr, ssrLooseContain, ssrLooseEqual } from 'vue/server-renderer';
import { u as useApi } from './useApi-B-E5eLsI.mjs';
import { u as useToast } from './useToast-CS21XT61.mjs';
import { _ as _export_sfc, D as DEFAULT_ADMIN_ACCESS, M as MENU_GROUPS } from './server.mjs';
import './useLoading-D4zrSa2m.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: "accounts",
__ssrInlineRender: true,
setup(__props) {
useApi();
useToast();
const ROLE = { 1: "超管", 2: "管理员", 3: "品牌商", 4: "运营", 5: "渠道商" };
const ROLE_CLS = { 1: "badge-error", 2: "badge-primary", 3: "badge-warning", 4: "badge-info", 5: "badge-accent" };
const REGIONS = [["cn", "中国"], ["us", "美国"], ["ea", "东亚"], ["sea", "东南亚"], ["sa", "南亚"], ["me", "中东"], ["eu", "欧洲"], ["ru", "俄罗斯"], ["af", "非洲"], ["sam", "南美"], ["nam", "北美"], ["oc", "大洋洲"], ["br", "巴西"], ["in", "印度"]];
const view = ref("list");
const rows = ref([]);
const apps = ref([]);
const loading = ref(false);
const submitting = ref(false);
const editId = ref(0);
const form = reactive({
username: "",
password: "",
identity: 2,
enabled: "1",
remark: "",
brandid: 0,
channelid: ""
});
const channels = ref([]);
const accountChannelOptions = computed(
() => form.brandid ? channels.value.filter((ch) => ch.brandid === form.brandid) : []
);
const sel = reactive({
access: [],
apps: [],
regions: [],
products: []
});
const brands = ref([]);
const productGroups = ref([]);
const prodLoading = ref(false);
function fromCsv(s) {
return (s || "").split(",").map((x) => x.trim()).filter((x) => x);
}
function scopeParts(a) {
const parts = [];
if (a.apps) parts.push("应用:" + fromCsv(a.apps).length);
if (a.regions) parts.push("区域:" + fromCsv(a.regions).length);
if (a.products) parts.push("产品:" + fromCsv(a.products).length);
if (a.access) parts.push("页面:" + fromCsv(a.access).length);
return parts;
}
watch(() => form.identity, (idt) => {
if (idt === 2 && sel.access.length === 0) sel.access = DEFAULT_ADMIN_ACCESS.slice();
});
ref(null);
ref(0);
const topup = reactive({
name: "",
cur: "",
vipday: 0,
trademin: 0,
meetmin: 0
});
return (_ctx, _push, _parent, _attrs) => {
_push(`<div${ssrRenderAttrs(_attrs)} data-v-11e40be5><div style="${ssrRenderStyle(view.value === "list" ? null : { display: "none" })}" data-v-11e40be5><div class="flex items-center justify-between mb-4" data-v-11e40be5><div data-v-11e40be5><h2 class="text-lg font-bold text-slate-700" data-v-11e40be5>后台账号</h2><p class="text-xs text-slate-400 mt-0.5" data-v-11e40be5>超管 / 管理员 / 代理 / 运营。代理·运营可绑定应用·区域·产品,登录后仪表盘按绑定限制。</p></div><button class="btn btn-primary btn-sm text-white" data-v-11e40be5>+ 新建账号</button></div><div class="bg-white rounded-xl shadow-sm border border-slate-100 overflow-hidden" data-v-11e40be5><table class="table table-sm" data-v-11e40be5><thead data-v-11e40be5><tr class="text-slate-500" data-v-11e40be5><th data-v-11e40be5>ID</th><th data-v-11e40be5>用户名</th><th data-v-11e40be5>角色</th><th data-v-11e40be5>状态</th><th data-v-11e40be5>绑定作用域</th><th data-v-11e40be5>备注</th><th class="text-right" data-v-11e40be5>操作</th></tr></thead><tbody data-v-11e40be5>`);
if (loading.value) {
_push(`<tr data-v-11e40be5><td colspan="7" class="text-center text-slate-400 py-8" data-v-11e40be5>加载中...</td></tr>`);
} else if (!rows.value.length) {
_push(`<tr data-v-11e40be5><td colspan="7" class="text-center text-slate-400 py-8" data-v-11e40be5>暂无账号(引导超管不在此列)</td></tr>`);
} else {
_push(`<!---->`);
}
_push(`<!--[-->`);
ssrRenderList(rows.value, (a) => {
_push(`<tr data-v-11e40be5><td class="font-mono" data-v-11e40be5>${ssrInterpolate(a.id)}</td><td class="font-medium" data-v-11e40be5>${ssrInterpolate(a.username || "")}</td><td data-v-11e40be5><span class="${ssrRenderClass([ROLE_CLS[a.identity] || "", "badge badge-sm"])}" data-v-11e40be5>${ssrInterpolate(ROLE[a.identity] || a.identity)}</span></td><td data-v-11e40be5>`);
if (a.enabled) {
_push(`<span class="text-green-600 text-xs" data-v-11e40be5>启用</span>`);
} else {
_push(`<span class="text-slate-400 text-xs" data-v-11e40be5>停用</span>`);
}
_push(`</td><td data-v-11e40be5>`);
if (a.identity === 3 || a.identity === 4) {
_push(`<!--[-->`);
if (scopeParts(a).length) {
_push(`<span class="text-xs text-slate-500" data-v-11e40be5>${ssrInterpolate(scopeParts(a).join(" · "))}</span>`);
} else {
_push(`<span class="text-xs text-slate-300" data-v-11e40be5>未绑定(不限)</span>`);
}
_push(`<!--]-->`);
} else if (a.identity === 2) {
_push(`<!--[-->`);
if (a.access) {
_push(`<span class="text-xs text-slate-500" data-v-11e40be5>菜单:${ssrInterpolate(fromCsv(a.access).length)}</span>`);
} else {
_push(`<span class="text-xs text-slate-300" data-v-11e40be5>默认(除SaaS/系统管理)</span>`);
}
_push(`<!--]-->`);
} else {
_push(`<span class="text-xs text-slate-300" data-v-11e40be5>全部权限</span>`);
}
if (a.identity === 3) {
_push(`<div class="text-[11px] text-emerald-600 mt-0.5" data-v-11e40be5> 余额 VIP${ssrInterpolate(a.balance_vipday || 0)}天 · 翻译${ssrInterpolate(a.balance_trademin || 0)}分 · 会议${ssrInterpolate(a.balance_meetmin || 0)}分 </div>`);
} else {
_push(`<!---->`);
}
_push(`</td><td class="text-xs text-slate-500" data-v-11e40be5>${ssrInterpolate(a.remark || "")}</td><td data-v-11e40be5><div class="flex gap-1 justify-end" data-v-11e40be5>`);
if (a.identity === 3) {
_push(`<button class="btn btn-ghost btn-xs text-emerald-600" data-v-11e40be5>充值</button>`);
} else {
_push(`<!---->`);
}
_push(`<button class="btn btn-ghost btn-xs" data-v-11e40be5>编辑</button><button class="btn btn-ghost btn-xs text-amber-600" data-v-11e40be5>改密</button><button class="btn btn-ghost btn-xs text-red-500" data-v-11e40be5>删除</button></div></td></tr>`);
});
_push(`<!--]--></tbody></table></div></div><div style="${ssrRenderStyle(view.value === "form" ? null : { display: "none" })}" data-v-11e40be5><div class="flex items-center gap-3 mb-5" data-v-11e40be5><button class="btn btn-ghost btn-sm" data-v-11e40be5>← 返回列表</button><h2 class="text-lg font-semibold text-slate-800" data-v-11e40be5>${ssrInterpolate(editId.value ? "编辑账号 #" + editId.value : "新建账号")}</h2></div><div class="bg-white rounded-xl shadow-sm border border-slate-100 p-6 max-w-2xl" data-v-11e40be5><div class="grid grid-cols-2 gap-3" data-v-11e40be5><div data-v-11e40be5><label class="text-xs text-slate-500" data-v-11e40be5>用户名</label><input${ssrRenderAttr("value", form.username)}${ssrIncludeBooleanAttr(!!editId.value) ? " disabled" : ""} class="input input-bordered input-sm w-full" placeholder="登录用户名" data-v-11e40be5></div><div style="${ssrRenderStyle(!editId.value ? null : { display: "none" })}" data-v-11e40be5><label class="text-xs text-slate-500" data-v-11e40be5>密码</label><input${ssrRenderAttr("value", form.password)} type="password" class="input input-bordered input-sm w-full" placeholder="登录密码" data-v-11e40be5></div><div data-v-11e40be5><label class="text-xs text-slate-500" data-v-11e40be5>角色</label><select class="select select-bordered select-sm w-full" data-v-11e40be5><option${ssrRenderAttr("value", 2)} data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.identity) ? ssrLooseContain(form.identity, 2) : ssrLooseEqual(form.identity, 2)) ? " selected" : ""}>管理员(默认除 SaaS/系统管理外全部)</option><option${ssrRenderAttr("value", 3)} data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.identity) ? ssrLooseContain(form.identity, 3) : ssrLooseEqual(form.identity, 3)) ? " selected" : ""}>品牌商(绑定品牌商,见名下全部渠道商)</option><option${ssrRenderAttr("value", 5)} data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.identity) ? ssrLooseContain(form.identity, 5) : ssrLooseEqual(form.identity, 5)) ? " selected" : ""}>渠道商(绑定单个渠道商,只见自己数据)</option><option${ssrRenderAttr("value", 4)} data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.identity) ? ssrLooseContain(form.identity, 4) : ssrLooseEqual(form.identity, 4)) ? " selected" : ""}>运营(内部,按绑定限制)</option><option${ssrRenderAttr("value", 1)} data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.identity) ? ssrLooseContain(form.identity, 1) : ssrLooseEqual(form.identity, 1)) ? " selected" : ""}>超管(全部权限)</option></select></div><div data-v-11e40be5><label class="text-xs text-slate-500" data-v-11e40be5>状态</label><select class="select select-bordered select-sm w-full" data-v-11e40be5><option value="1" data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.enabled) ? ssrLooseContain(form.enabled, "1") : ssrLooseEqual(form.enabled, "1")) ? " selected" : ""}>启用</option><option value="0" data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.enabled) ? ssrLooseContain(form.enabled, "0") : ssrLooseEqual(form.enabled, "0")) ? " selected" : ""}>停用</option></select></div><div class="col-span-2" data-v-11e40be5><label class="text-xs text-slate-500" data-v-11e40be5>备注</label><input${ssrRenderAttr("value", form.remark)} class="input input-bordered input-sm w-full" placeholder="可选" data-v-11e40be5></div></div><div class="mt-4 border-t border-slate-100 pt-4" style="${ssrRenderStyle(form.identity !== 1 ? null : { display: "none" })}" data-v-11e40be5><div class="flex items-center justify-between mb-1" data-v-11e40be5><div class="text-sm font-semibold text-slate-600" data-v-11e40be5>菜单权限</div><div class="flex gap-1" data-v-11e40be5><button type="button" class="btn btn-ghost btn-xs" data-v-11e40be5>管理员默认</button><button type="button" class="btn btn-ghost btn-xs" data-v-11e40be5>全选</button><button type="button" class="btn btn-ghost btn-xs" data-v-11e40be5>清空</button></div></div><p class="text-xs text-slate-400 mb-3" data-v-11e40be5>管理员默认开放除「SaaS 管理 / 系统管理」以外的全部菜单(权限留空时按默认生效);代理/运营需显式勾选。</p><!--[-->`);
ssrRenderList(unref(MENU_GROUPS), (g) => {
_push(`<div class="mb-2.5" data-v-11e40be5><div class="text-xs text-slate-500 mb-1.5" data-v-11e40be5>${ssrInterpolate(g.label)}`);
if (g.restricted) {
_push(`<span class="text-amber-500 ml-1" data-v-11e40be5>(管理员默认不开放)</span>`);
} else {
_push(`<!---->`);
}
_push(`</div><div class="flex flex-wrap gap-2" data-v-11e40be5><!--[-->`);
ssrRenderList(g.items, (m) => {
_push(`<label class="chk" data-v-11e40be5><input${ssrIncludeBooleanAttr(Array.isArray(sel.access) ? ssrLooseContain(sel.access, m.id) : sel.access) ? " checked" : ""} type="checkbox"${ssrRenderAttr("value", m.id)} data-v-11e40be5>${ssrInterpolate(m.label)}</label>`);
});
_push(`<!--]--></div></div>`);
});
_push(`<!--]--></div><div class="mt-4 border-t border-slate-100 pt-4" style="${ssrRenderStyle(form.identity === 3 || form.identity === 5 ? null : { display: "none" })}" data-v-11e40be5><div class="text-sm font-semibold text-slate-600 mb-2" data-v-11e40be5> 归属绑定 <span class="text-xs text-slate-400 font-normal" data-v-11e40be5>(品牌商账号只绑品牌商;渠道商账号两者都要绑)</span></div><div class="grid grid-cols-2 gap-3" data-v-11e40be5><div data-v-11e40be5><label class="text-xs text-slate-500" data-v-11e40be5>所属品牌商 *</label><select class="select select-bordered select-sm w-full" data-v-11e40be5><option${ssrRenderAttr("value", 0)} data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.brandid) ? ssrLooseContain(form.brandid, 0) : ssrLooseEqual(form.brandid, 0)) ? " selected" : ""}>请选择品牌商</option><!--[-->`);
ssrRenderList(brands.value, (b) => {
_push(`<option${ssrRenderAttr("value", b.id)} data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.brandid) ? ssrLooseContain(form.brandid, b.id) : ssrLooseEqual(form.brandid, b.id)) ? " selected" : ""}>${ssrInterpolate(b.brand)}</option>`);
});
_push(`<!--]--></select></div><div style="${ssrRenderStyle(form.identity === 5 ? null : { display: "none" })}" data-v-11e40be5><label class="text-xs text-slate-500" data-v-11e40be5>所属渠道商 *</label><select class="select select-bordered select-sm w-full"${ssrIncludeBooleanAttr(!accountChannelOptions.value.length) ? " disabled" : ""} data-v-11e40be5><option value="" data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.channelid) ? ssrLooseContain(form.channelid, "") : ssrLooseEqual(form.channelid, "")) ? " selected" : ""}>${ssrInterpolate(form.brandid ? accountChannelOptions.value.length ? "请选择渠道商" : "该品牌商暂无渠道商" : "请先选择品牌商")}</option><!--[-->`);
ssrRenderList(accountChannelOptions.value, (ch) => {
_push(`<option${ssrRenderAttr("value", ch.id)} data-v-11e40be5${ssrIncludeBooleanAttr(Array.isArray(form.channelid) ? ssrLooseContain(form.channelid, ch.id) : ssrLooseEqual(form.channelid, ch.id)) ? " selected" : ""}>${ssrInterpolate(ch.name)} (${ssrInterpolate(ch.id)})</option>`);
});
_push(`<!--]--></select></div></div><p class="text-xs text-slate-400 mt-2" data-v-11e40be5> 数据隔离由后端强制:品牌商账号只能看到本品牌商及其名下渠道商的数据,渠道商账号只能看到自己渠道的数据。 </p></div><div class="mt-4 border-t border-slate-100 pt-4" style="${ssrRenderStyle(form.identity === 3 || form.identity === 4 ? null : { display: "none" })}" data-v-11e40be5><div class="text-sm font-semibold text-slate-600 mb-2" data-v-11e40be5>作用域绑定 <span class="text-xs text-slate-400 font-normal" data-v-11e40be5>(代理/运营生效;限制仪表盘数据范围)</span></div><div class="mb-3" data-v-11e40be5><div class="text-xs text-slate-500 mb-1.5" data-v-11e40be5>绑定应用 <span class="text-slate-300" data-v-11e40be5>(仪表盘只显示这些应用数据;不勾=不限)</span></div><div class="flex flex-wrap gap-2" data-v-11e40be5>`);
if (apps.value.length) {
_push(`<!--[-->`);
ssrRenderList(apps.value, (a) => {
_push(`<label class="chk" data-v-11e40be5><input${ssrIncludeBooleanAttr(Array.isArray(sel.apps) ? ssrLooseContain(sel.apps, a.name) : sel.apps) ? " checked" : ""} type="checkbox"${ssrRenderAttr("value", a.name)} data-v-11e40be5>${ssrInterpolate(a.name || "应用#" + a.id)}</label>`);
});
_push(`<!--]-->`);
} else {
_push(`<span class="text-xs text-slate-300" data-v-11e40be5>无注册应用</span>`);
}
_push(`</div></div><div class="mb-3" data-v-11e40be5><div class="text-xs text-slate-500 mb-1.5" data-v-11e40be5>绑定区域 <span class="text-slate-300" data-v-11e40be5>(不勾=不限)</span></div><div class="flex flex-wrap gap-2" data-v-11e40be5><!--[-->`);
ssrRenderList(REGIONS, (r) => {
_push(`<label class="chk" data-v-11e40be5><input${ssrIncludeBooleanAttr(Array.isArray(sel.regions) ? ssrLooseContain(sel.regions, r[0]) : sel.regions) ? " checked" : ""} type="checkbox"${ssrRenderAttr("value", r[0])} data-v-11e40be5>${ssrInterpolate(r[1])}</label>`);
});
_push(`<!--]--></div></div><div data-v-11e40be5><div class="text-xs text-slate-500 mb-1.5" data-v-11e40be5>绑定产品 <span class="text-slate-300" data-v-11e40be5>(按厂家分组;仪表盘只显示这些产品数据;不勾=不限)</span></div><div class="max-h-56 overflow-y-auto pr-1 border border-slate-100 rounded-lg p-2" data-v-11e40be5>`);
if (prodLoading.value) {
_push(`<span class="text-xs text-slate-300" data-v-11e40be5>加载产品中...</span>`);
} else if (!productGroups.value.length) {
_push(`<span class="text-xs text-slate-300" data-v-11e40be5>无产品</span>`);
} else {
_push(`<!--[-->`);
ssrRenderList(productGroups.value, (g) => {
_push(`<div class="mb-2 last:mb-0" data-v-11e40be5><div class="text-[11px] font-semibold text-slate-500 mb-1 sticky top-0 bg-white py-0.5" data-v-11e40be5>🏭 ${ssrInterpolate(g.label)}</div><div class="flex flex-wrap gap-2" data-v-11e40be5><!--[-->`);
ssrRenderList(g.products, (p) => {
_push(`<label class="chk" data-v-11e40be5><input${ssrIncludeBooleanAttr(Array.isArray(sel.products) ? ssrLooseContain(sel.products, String(p.id)) : sel.products) ? " checked" : ""} type="checkbox"${ssrRenderAttr("value", String(p.id))} data-v-11e40be5>${ssrInterpolate((p.devicename || "产品") + " #" + p.id)}</label>`);
});
_push(`<!--]--></div></div>`);
});
_push(`<!--]-->`);
}
_push(`</div></div></div><div class="flex gap-3 justify-end mt-6" data-v-11e40be5><button class="btn btn-ghost btn-sm" data-v-11e40be5>取消</button><button class="btn btn-primary btn-sm text-white"${ssrIncludeBooleanAttr(submitting.value) ? " disabled" : ""} data-v-11e40be5>保存</button></div></div></div><dialog class="modal" data-v-11e40be5><div class="modal-box max-w-md" data-v-11e40be5><h3 class="font-bold text-lg mb-1" data-v-11e40be5>充值 / 调整资源点</h3><p class="text-xs text-slate-400 mb-3" data-v-11e40be5>代理:<span class="font-medium text-slate-600" data-v-11e40be5>${ssrInterpolate(topup.name)}</span>。填增量(可填负数下调),当前余额:<span class="text-emerald-600" data-v-11e40be5>${ssrInterpolate(topup.cur)}</span></p><div class="grid grid-cols-3 gap-3" data-v-11e40be5><div data-v-11e40be5><label class="text-xs text-slate-500" data-v-11e40be5>VIP天数</label><input${ssrRenderAttr("value", topup.vipday)} type="number" class="input input-bordered input-sm w-full" data-v-11e40be5></div><div data-v-11e40be5><label class="text-xs text-slate-500" data-v-11e40be5>翻译分钟</label><input${ssrRenderAttr("value", topup.trademin)} type="number" class="input input-bordered input-sm w-full" data-v-11e40be5></div><div data-v-11e40be5><label class="text-xs text-slate-500" data-v-11e40be5>会议分钟</label><input${ssrRenderAttr("value", topup.meetmin)} type="number" class="input input-bordered input-sm w-full" data-v-11e40be5></div></div><div class="modal-action" data-v-11e40be5><button class="btn btn-ghost btn-sm" data-v-11e40be5>取消</button><button class="btn btn-primary btn-sm text-white" data-v-11e40be5>确认</button></div></div><form method="dialog" class="modal-backdrop" data-v-11e40be5><button data-v-11e40be5>close</button></form></dialog></div>`);
};
}
});
const _sfc_setup = _sfc_main.setup;
_sfc_main.setup = (props, ctx) => {
const ssrContext = useSSRContext();
(ssrContext.modules || (ssrContext.modules = /* @__PURE__ */ new Set())).add("pages/accounts.vue");
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
};
const accounts = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-11e40be5"]]);
export { accounts as default };
//# sourceMappingURL=accounts-C1hb7WMW.mjs.map