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.
304 lines
36 KiB
304 lines
36 KiB
import { defineComponent, computed, ref, reactive, mergeProps, useSSRContext } from 'vue';
|
|
import { ssrRenderAttrs, ssrRenderClass, ssrRenderStyle, ssrRenderAttr, ssrIncludeBooleanAttr, ssrLooseContain, ssrLooseEqual, ssrRenderList, ssrInterpolate } 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: "device",
|
|
__ssrInlineRender: true,
|
|
setup(__props) {
|
|
useApi();
|
|
useToast();
|
|
const auth = useAuthStore();
|
|
const isSuperAdmin = computed(() => auth.identity === 1);
|
|
const canCreate = computed(() => auth.identity > 0 && auth.identity <= 2);
|
|
const tab = ref("codes");
|
|
const brands = ref([]);
|
|
const channels = ref([]);
|
|
const products = ref([]);
|
|
const allProducts = ref([]);
|
|
const notes = ref([]);
|
|
const devices = ref([]);
|
|
const devTotal = ref(0);
|
|
const devPage = ref(0);
|
|
const devPageSize = ref(200);
|
|
const filterBrand = ref(0);
|
|
const filterChannel = ref("");
|
|
const filterProduct = ref(0);
|
|
const filterStart = ref("");
|
|
const filterEnd = ref("");
|
|
const statBatch = ref("-");
|
|
const statDevices = ref("-");
|
|
const statLast = ref("-");
|
|
const notesCountText = ref("");
|
|
const notesLoading = ref(false);
|
|
const notesError = ref("");
|
|
const codeStatus = ref("0");
|
|
const codeSort = ref("createtime");
|
|
const codeBatch = ref("");
|
|
const codeCode = ref("");
|
|
const codeMac = ref("");
|
|
const codeUid = ref("");
|
|
const codePageSizeSel = ref("200");
|
|
const codePageSizeCustom = ref(null);
|
|
const devicesError = ref("");
|
|
const selectAll = ref(false);
|
|
const selectedCodes = ref([]);
|
|
const selectedCount = computed(() => selectedCodes.value.length);
|
|
ref(null);
|
|
ref(null);
|
|
ref(null);
|
|
const createMode = ref("production");
|
|
const cBrand = ref(0);
|
|
const cChannel = ref("");
|
|
const cProduct = ref(0);
|
|
const cBindmac = ref(false);
|
|
const cNumber = ref(null);
|
|
const cMacaddresses = ref("");
|
|
const cRemark = ref("");
|
|
const submitting = ref(false);
|
|
const previewLoading = ref(false);
|
|
const preview = ref(null);
|
|
ref(null);
|
|
const csvFileName = ref("");
|
|
ref(null);
|
|
const emailSending = ref(false);
|
|
const email = reactive({ to: "", cc: "", subject: "", content: "" });
|
|
ref(null);
|
|
const revokeCtx = ref(null);
|
|
const revokeConfirmInput = ref("");
|
|
const revokeError = ref("");
|
|
const revokeSubmitting = ref(false);
|
|
const revokeConfirmTarget = computed(() => revokeCtx.value ? revokeCtx.value.batchno : "");
|
|
const revokeConfirmOk = computed(() => !!revokeCtx.value && revokeConfirmInput.value.trim() === revokeConfirmTarget.value);
|
|
const totalPages = computed(() => Math.max(1, Math.ceil(devTotal.value / devPageSize.value)));
|
|
const pgInfoText = computed(() => filterProduct.value ? "第 " + (devPage.value + 1) + " / " + totalPages.value + " 页" : "-");
|
|
const filterProductOptions = computed(() => {
|
|
return filterBrand.value ? products.value.filter((p) => p.brandid === filterBrand.value) : products.value;
|
|
});
|
|
const filterChannelOptions = computed(() => {
|
|
return filterBrand.value ? channels.value.filter((ch) => ch.brandid === filterBrand.value) : channels.value;
|
|
});
|
|
const createChannelOptions = computed(() => {
|
|
return cBrand.value ? channels.value.filter((ch) => ch.brandid === cBrand.value && ch.status === 1) : [];
|
|
});
|
|
const createProductOptions = computed(() => {
|
|
return cBrand.value ? products.value.filter((p) => p.brandid === cBrand.value) : [];
|
|
});
|
|
const createProductInfo = computed(() => {
|
|
const p = allProducts.value.find((x) => x.id === cProduct.value);
|
|
const codeCount = p?.devicecodecount && p.devicecodecount > 0 ? p.devicecodecount : 1;
|
|
return { isClassicBT: p?.devicetype === 1, codeCount };
|
|
});
|
|
const createFinalTotal = computed(() => (Number(cNumber.value) || 0) * createProductInfo.value.codeCount);
|
|
const importMacCount = computed(() => cMacaddresses.value.split(",").map((s) => s.trim()).filter(Boolean).length);
|
|
const previewCid = computed(() => {
|
|
if (!preview.value) return "N/A";
|
|
const b = brands.value.find((x) => x.id === preview.value.brandid);
|
|
return b && b.providerid != null ? Number(b.providerid).toString(16).padStart(4, "0").toUpperCase() : "N/A";
|
|
});
|
|
function fmtTime(ts) {
|
|
if (!ts) return "-";
|
|
const d = new Date(ts * 1e3);
|
|
return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0") + " " + String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0");
|
|
}
|
|
function nameOfBrand(id) {
|
|
const b = brands.value.find((x) => x.id === id);
|
|
return b ? b.brand : String(id || "");
|
|
}
|
|
function nameOfChannel(id) {
|
|
if (!id) return "未分配";
|
|
const ch = channels.value.find((x) => x.id === id);
|
|
return ch ? ch.name + " (" + ch.id + ")" : id;
|
|
}
|
|
function nameOfProduct(id) {
|
|
const p = allProducts.value.find((x) => x.id === id);
|
|
return p ? p.devicename : String(id || "");
|
|
}
|
|
function hexId(id) {
|
|
return id ? Number(id).toString(16).toUpperCase() : "";
|
|
}
|
|
function serialRange(n) {
|
|
const a = n.serialstart != null && n.serialstart !== "" ? String(n.serialstart) : "";
|
|
const b = n.serialend != null && n.serialend !== "" ? String(n.serialend) : "";
|
|
if (!a && !b) return "-";
|
|
return a + " - " + b;
|
|
}
|
|
function codeState(d) {
|
|
if (d.disabled !== 0) return { label: "已禁用", dot: "bg-red-500", text: "text-red-600" };
|
|
if (d.status === 1) return { label: "已激活", dot: "bg-emerald-500", text: "text-emerald-600" };
|
|
if (d.status === 2) return { label: "已过期", dot: "bg-amber-500", text: "text-amber-600" };
|
|
return { label: "未使用", dot: "bg-slate-300", text: "text-slate-500" };
|
|
}
|
|
return (_ctx, _push, _parent, _attrs) => {
|
|
_push(`<div${ssrRenderAttrs(mergeProps({ class: "space-y-5" }, _attrs))}><div class="flex items-center justify-between flex-wrap gap-3"><div class="tabs tabs-boxed bg-slate-100 inline-flex"><a class="${ssrRenderClass([{ "tab-active": tab.value === "codes" }, "tab"])}">授权码查询</a><a class="${ssrRenderClass([{ "tab-active": tab.value === "batches" }, "tab"])}">生产记录</a>`);
|
|
if (canCreate.value) {
|
|
_push(`<a class="${ssrRenderClass([{ "tab-active": tab.value === "produce" }, "tab"])}">生产授权码</a>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div>`);
|
|
if (tab.value !== "produce") {
|
|
_push(`<div class="flex items-end gap-2 flex-wrap"><select class="select select-bordered select-sm" style="${ssrRenderStyle({ "min-width": "150px" })}"><option${ssrRenderAttr("value", 0)}${ssrIncludeBooleanAttr(Array.isArray(filterBrand.value) ? ssrLooseContain(filterBrand.value, 0) : ssrLooseEqual(filterBrand.value, 0)) ? " selected" : ""}>全部品牌商</option><!--[-->`);
|
|
ssrRenderList(brands.value, (b) => {
|
|
_push(`<option${ssrRenderAttr("value", b.id)}${ssrIncludeBooleanAttr(Array.isArray(filterBrand.value) ? ssrLooseContain(filterBrand.value, b.id) : ssrLooseEqual(filterBrand.value, b.id)) ? " selected" : ""}>${ssrInterpolate(b.brand || "")}</option>`);
|
|
});
|
|
_push(`<!--]--></select><select class="select select-bordered select-sm" style="${ssrRenderStyle({ "min-width": "160px" })}"><option value=""${ssrIncludeBooleanAttr(Array.isArray(filterChannel.value) ? ssrLooseContain(filterChannel.value, "") : ssrLooseEqual(filterChannel.value, "")) ? " selected" : ""}>全部渠道商</option><!--[-->`);
|
|
ssrRenderList(filterChannelOptions.value, (ch) => {
|
|
_push(`<option${ssrRenderAttr("value", ch.id)}${ssrIncludeBooleanAttr(Array.isArray(filterChannel.value) ? ssrLooseContain(filterChannel.value, ch.id) : ssrLooseEqual(filterChannel.value, ch.id)) ? " selected" : ""}>${ssrInterpolate(ch.name)} (${ssrInterpolate(ch.id)})</option>`);
|
|
});
|
|
_push(`<!--]--></select><select class="select select-bordered select-sm" style="${ssrRenderStyle({ "min-width": "180px" })}"><option${ssrRenderAttr("value", 0)}${ssrIncludeBooleanAttr(Array.isArray(filterProduct.value) ? ssrLooseContain(filterProduct.value, 0) : ssrLooseEqual(filterProduct.value, 0)) ? " selected" : ""}>请选择产品</option><!--[-->`);
|
|
ssrRenderList(filterProductOptions.value, (p) => {
|
|
_push(`<option${ssrRenderAttr("value", p.id)}${ssrIncludeBooleanAttr(Array.isArray(filterProduct.value) ? ssrLooseContain(filterProduct.value, p.id) : ssrLooseEqual(filterProduct.value, p.id)) ? " selected" : ""}>${ssrInterpolate(p.devicename || "")}</option>`);
|
|
});
|
|
_push(`<!--]--></select></div>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div><div class="bg-white rounded-xl shadow-sm border border-slate-100" style="${ssrRenderStyle(tab.value === "codes" ? null : { display: "none" })}"><div class="flex items-center justify-between px-5 py-3 border-b border-slate-100 flex-wrap gap-2"><h3 class="text-sm font-semibold text-slate-700">授权码记录<span class="text-xs text-slate-400 font-normal ml-2">默认按生产时间倒序</span></h3><div class="flex items-end gap-2 flex-wrap"><div class="form-control"><label class="label py-0"><span class="label-text text-xs">状态</span></label><select class="select select-bordered select-xs"><option value="0"${ssrIncludeBooleanAttr(Array.isArray(codeStatus.value) ? ssrLooseContain(codeStatus.value, "0") : ssrLooseEqual(codeStatus.value, "0")) ? " selected" : ""}>全部</option><option value="-1"${ssrIncludeBooleanAttr(Array.isArray(codeStatus.value) ? ssrLooseContain(codeStatus.value, "-1") : ssrLooseEqual(codeStatus.value, "-1")) ? " selected" : ""}>未使用</option><option value="1"${ssrIncludeBooleanAttr(Array.isArray(codeStatus.value) ? ssrLooseContain(codeStatus.value, "1") : ssrLooseEqual(codeStatus.value, "1")) ? " selected" : ""}>已激活</option><option value="2"${ssrIncludeBooleanAttr(Array.isArray(codeStatus.value) ? ssrLooseContain(codeStatus.value, "2") : ssrLooseEqual(codeStatus.value, "2")) ? " selected" : ""}>已过期</option></select></div><div class="form-control"><label class="label py-0"><span class="label-text text-xs">排序</span></label><select class="select select-bordered select-xs"><option value="createtime"${ssrIncludeBooleanAttr(Array.isArray(codeSort.value) ? ssrLooseContain(codeSort.value, "createtime") : ssrLooseEqual(codeSort.value, "createtime")) ? " selected" : ""}>生产时间</option><option value="usedtime"${ssrIncludeBooleanAttr(Array.isArray(codeSort.value) ? ssrLooseContain(codeSort.value, "usedtime") : ssrLooseEqual(codeSort.value, "usedtime")) ? " selected" : ""}>激活时间</option></select></div><div class="form-control"><label class="label py-0"><span class="label-text text-xs">批次</span></label><input${ssrRenderAttr("value", codeBatch.value)} type="text" class="input input-bordered input-xs font-mono" placeholder="批次号" style="${ssrRenderStyle({ "width": "90px" })}"></div><div class="form-control"><label class="label py-0"><span class="label-text text-xs">授权码</span></label><input${ssrRenderAttr("value", codeCode.value)} type="text" class="input input-bordered input-xs" placeholder="授权码"></div><div class="form-control"><label class="label py-0"><span class="label-text text-xs">MAC</span></label><input${ssrRenderAttr("value", codeMac.value)} type="text" class="input input-bordered input-xs" placeholder="MAC"></div><div class="form-control"><label class="label py-0"><span class="label-text text-xs">用户UID</span></label><input${ssrRenderAttr("value", codeUid.value)} type="text" class="input input-bordered input-xs" placeholder="UID"></div><div class="form-control"><label class="label py-0"><span class="label-text text-xs">每页数量</span></label><select class="select select-bordered select-xs"><option value="20"${ssrIncludeBooleanAttr(Array.isArray(codePageSizeSel.value) ? ssrLooseContain(codePageSizeSel.value, "20") : ssrLooseEqual(codePageSizeSel.value, "20")) ? " selected" : ""}>20</option><option value="50"${ssrIncludeBooleanAttr(Array.isArray(codePageSizeSel.value) ? ssrLooseContain(codePageSizeSel.value, "50") : ssrLooseEqual(codePageSizeSel.value, "50")) ? " selected" : ""}>50</option><option value="100"${ssrIncludeBooleanAttr(Array.isArray(codePageSizeSel.value) ? ssrLooseContain(codePageSizeSel.value, "100") : ssrLooseEqual(codePageSizeSel.value, "100")) ? " selected" : ""}>100</option><option value="200"${ssrIncludeBooleanAttr(Array.isArray(codePageSizeSel.value) ? ssrLooseContain(codePageSizeSel.value, "200") : ssrLooseEqual(codePageSizeSel.value, "200")) ? " selected" : ""}>200</option><option value="500"${ssrIncludeBooleanAttr(Array.isArray(codePageSizeSel.value) ? ssrLooseContain(codePageSizeSel.value, "500") : ssrLooseEqual(codePageSizeSel.value, "500")) ? " selected" : ""}>500</option><option value="custom"${ssrIncludeBooleanAttr(Array.isArray(codePageSizeSel.value) ? ssrLooseContain(codePageSizeSel.value, "custom") : ssrLooseEqual(codePageSizeSel.value, "custom")) ? " selected" : ""}>自定义</option></select></div><div class="form-control" style="${ssrRenderStyle(codePageSizeSel.value === "custom" ? null : { display: "none" })}"><label class="label py-0"><span class="label-text text-xs">自定义</span></label><input${ssrRenderAttr("value", codePageSizeCustom.value)} type="number" min="1" max="2000" class="input input-bordered input-xs" placeholder="1-2000" style="${ssrRenderStyle({ "width": "90px" })}"></div><button class="btn btn-primary btn-xs text-white">搜索</button><button class="btn btn-error btn-xs text-white"${ssrIncludeBooleanAttr(selectedCount.value === 0) ? " disabled" : ""}>批量禁用</button><button class="btn btn-warning btn-xs text-white"${ssrIncludeBooleanAttr(selectedCount.value === 0) ? " disabled" : ""}>批量恢复</button><button class="btn btn-ghost btn-xs"${ssrIncludeBooleanAttr(!devices.value.length) ? " disabled" : ""}>导出</button><button class="btn btn-ghost btn-xs"${ssrIncludeBooleanAttr(!devices.value.length) ? " disabled" : ""}>发邮件</button></div></div><div class="overflow-x-auto"><table class="table table-zebra text-sm"><thead><tr><th class="w-8"><input${ssrIncludeBooleanAttr(Array.isArray(selectAll.value) ? ssrLooseContain(selectAll.value, null) : selectAll.value) ? " checked" : ""} type="checkbox" class="checkbox checkbox-xs"></th><th>授权码</th><th>批次</th><th>MAC地址</th><th>用户UID</th><th>激活时间</th><th>状态</th><th>操作</th></tr></thead><tbody>`);
|
|
if (!filterProduct.value) {
|
|
_push(`<tr><td colspan="8" class="text-center text-slate-400 py-8">请先选择产品</td></tr>`);
|
|
} else if (devicesError.value) {
|
|
_push(`<tr><td colspan="8" class="text-center text-red-400 py-8">查询失败: ${ssrInterpolate(devicesError.value)}</td></tr>`);
|
|
} else if (!devices.value.length) {
|
|
_push(`<tr><td colspan="8" class="text-center text-slate-400 py-8">暂无数据</td></tr>`);
|
|
} else {
|
|
_push(`<!--[-->`);
|
|
ssrRenderList(devices.value, (d, i) => {
|
|
_push(`<tr><td><input${ssrIncludeBooleanAttr(Array.isArray(selectedCodes.value) ? ssrLooseContain(selectedCodes.value, d.code || "") : selectedCodes.value) ? " checked" : ""} type="checkbox" class="checkbox checkbox-xs"${ssrRenderAttr("value", d.code || "")}></td><td class="font-mono text-xs">${ssrInterpolate(d.code || "")}</td><td class="font-mono text-xs">${ssrInterpolate(d.batchno || "")}</td><td class="font-mono text-xs">${ssrInterpolate(d.devicemac || "-")}</td><td class="text-xs">${ssrInterpolate(d.uid || "-")}</td><td class="text-xs text-slate-500">${ssrInterpolate(d.usedtime ? fmtTime(d.usedtime) : "-")}</td><td><span class="${ssrRenderClass([codeState(d).text, "inline-flex items-center gap-1.5 text-xs font-medium whitespace-nowrap"])}"><span class="${ssrRenderClass([codeState(d).dot, "h-1.5 w-1.5 rounded-full shrink-0"])}"></span>${ssrInterpolate(codeState(d).label)}</span></td><td><div class="flex gap-1">`);
|
|
if (d.disabled !== 0) {
|
|
_push(`<button class="btn btn-ghost btn-xs text-warning">恢复</button>`);
|
|
} else {
|
|
_push(`<button class="btn btn-ghost btn-xs text-error">禁用</button>`);
|
|
}
|
|
if (d.status !== 0) {
|
|
_push(`<button class="btn btn-ghost btn-xs text-orange-500">重置</button>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div></td></tr>`);
|
|
});
|
|
_push(`<!--]-->`);
|
|
}
|
|
_push(`</tbody></table></div><div class="flex items-center justify-between px-5 py-3 border-t border-slate-100"><span class="text-xs text-slate-500">${ssrInterpolate(filterProduct.value ? "共 " + devTotal.value + " 条" : "-")}</span><div class="flex items-center gap-2"><button class="btn btn-ghost btn-xs"${ssrIncludeBooleanAttr(devPage.value <= 0 || !filterProduct.value) ? " disabled" : ""}>上一页</button><span class="text-xs text-slate-500">${ssrInterpolate(pgInfoText.value)}</span><button class="btn btn-ghost btn-xs"${ssrIncludeBooleanAttr(!filterProduct.value || devPage.value + 1 >= totalPages.value) ? " disabled" : ""}>下一页</button></div></div></div><div style="${ssrRenderStyle(tab.value === "batches" ? null : { display: "none" })}"><div class="grid grid-cols-3 gap-4 mb-5"><div class="bg-white rounded-xl shadow-sm border border-slate-100 p-5"><div class="text-xs text-slate-400 mb-1">命中批次数</div><div class="text-2xl font-bold text-slate-800">${ssrInterpolate(statBatch.value)}</div></div><div class="bg-white rounded-xl shadow-sm border border-slate-100 p-5"><div class="text-xs text-slate-400 mb-1">生产授权码总数</div><div class="text-2xl font-bold text-indigo-600">${ssrInterpolate(statDevices.value)}</div></div><div class="bg-white rounded-xl shadow-sm border border-slate-100 p-5"><div class="text-xs text-slate-400 mb-1">最近一次生产时间</div><div class="text-base font-semibold text-slate-700">${ssrInterpolate(statLast.value)}</div></div></div><div class="bg-white rounded-xl shadow-sm border border-slate-100"><div class="flex items-center justify-between px-5 py-3 border-b border-slate-100 flex-wrap gap-2"><h3 class="text-sm font-semibold text-slate-700">生产记录(按批次)<span class="text-xs text-slate-400 font-normal ml-2">点击记录查看该批次授权码</span></h3><div class="flex items-end gap-2 flex-wrap"><div class="form-control"><label class="label py-0"><span class="label-text text-xs">起始时间</span></label><input${ssrRenderAttr("value", filterStart.value)} type="date" class="input input-bordered input-xs"></div><div class="form-control"><label class="label py-0"><span class="label-text text-xs">结束时间</span></label><input${ssrRenderAttr("value", filterEnd.value)} type="date" class="input input-bordered input-xs"></div><button class="btn btn-primary btn-xs text-white">查询</button><span class="text-xs text-slate-400">${ssrInterpolate(notesCountText.value)}</span><button class="btn btn-ghost btn-xs">导出CSV</button></div></div><div class="overflow-x-auto" style="${ssrRenderStyle({ "max-height": "480px" })}"><table class="table table-pin-rows text-sm"><thead><tr><th class="w-40">生产时间</th><th>品牌商</th><th>渠道商</th><th>产品</th><th>批次号</th><th>序号区间</th><th>起始MAC</th><th>结束MAC</th><th class="text-right">数量</th><th>操作</th></tr></thead><tbody>`);
|
|
if (notesLoading.value) {
|
|
_push(`<tr><td colspan="10" class="text-center text-slate-400 py-8">加载中…</td></tr>`);
|
|
} else if (notesError.value) {
|
|
_push(`<tr><td colspan="10" class="text-center text-red-400 py-8">查询失败: ${ssrInterpolate(notesError.value)}</td></tr>`);
|
|
} else if (!notes.value.length) {
|
|
_push(`<tr><td colspan="10" class="text-center text-slate-400 py-8">暂无数据</td></tr>`);
|
|
} else {
|
|
_push(`<!--[-->`);
|
|
ssrRenderList(notes.value, (n, i) => {
|
|
_push(`<tr class="hover cursor-pointer"><td class="text-xs text-slate-500 whitespace-nowrap">${ssrInterpolate(fmtTime(n.ts))}</td><td class="text-xs">${ssrInterpolate(nameOfBrand(n.brandid))}</td><td class="text-xs">${ssrInterpolate(nameOfChannel(n.channelid))}</td><td class="text-xs">${ssrInterpolate(nameOfProduct(n.productid))}</td><td class="font-mono text-xs font-medium text-indigo-600">${ssrInterpolate(n.batchno || "")}</td><td class="font-mono text-xs">${ssrInterpolate(serialRange(n))}</td><td class="font-mono text-xs">${ssrInterpolate(n.startmac || "")}</td><td class="font-mono text-xs">${ssrInterpolate(n.endmac || "")}</td><td class="text-right font-medium">${ssrInterpolate(n.devicenum || 0)}</td><td><div class="flex gap-1"><button class="btn btn-ghost btn-xs text-indigo-500">查看授权码</button>`);
|
|
if (isSuperAdmin.value) {
|
|
_push(`<button class="btn btn-ghost btn-xs text-red-500">撤销</button>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div></td></tr>`);
|
|
});
|
|
_push(`<!--]-->`);
|
|
}
|
|
_push(`</tbody></table></div></div></div><div class="bg-white rounded-xl shadow-sm border border-slate-100 p-8 max-w-3xl" style="${ssrRenderStyle(tab.value === "produce" ? null : { display: "none" })}"><h3 class="text-base font-semibold text-slate-800 mb-2">生产授权码</h3><p class="text-sm text-slate-500 leading-relaxed mb-1"> 生产流程:填写生产表单 → 系统按产品类型计算最终授权码数量并预分配批次号 → <b>二次确认生产方案</b>(品牌商 / 产品ID / 批次号 / 数量 / MAC区间)→ 提交服务端生产 → 发送生产通知邮件。 </p><ul class="text-xs text-slate-400 list-disc list-inside mb-6 space-y-0.5"><li>经典蓝牙耳机产品生成<b>设备码</b>(每个码绑定 MAC 地址);其余产品生成<b>授权码</b>。</li><li>产品配置了「每副份数」时,最终生成数量 = 生产数量 × 每副份数。</li><li>导入模式按上传的 MAC 地址列表逐条生成设备码。</li></ul><button class="btn btn-primary text-white">+ 开始生产</button></div><dialog class="modal"><div class="modal-box max-w-2xl"><h3 class="font-bold text-lg mb-4">生产授权码</h3><form><div class="grid grid-cols-2 gap-4 mb-4"><div class="form-control"><label class="label"><span class="label-text font-medium">品牌商 *</span></label><select class="select select-bordered select-sm w-full" required><option${ssrRenderAttr("value", 0)}${ssrIncludeBooleanAttr(Array.isArray(cBrand.value) ? ssrLooseContain(cBrand.value, 0) : ssrLooseEqual(cBrand.value, 0)) ? " selected" : ""}>请选择品牌商</option><!--[-->`);
|
|
ssrRenderList(brands.value, (b) => {
|
|
_push(`<option${ssrRenderAttr("value", b.id)}${ssrIncludeBooleanAttr(Array.isArray(cBrand.value) ? ssrLooseContain(cBrand.value, b.id) : ssrLooseEqual(cBrand.value, b.id)) ? " selected" : ""}>${ssrInterpolate((b.brand || "") + " (" + hexId(b.id) + ")")}</option>`);
|
|
});
|
|
_push(`<!--]--></select></div><div class="form-control"><label class="label"><span class="label-text font-medium">渠道商 *</span></label><select class="select select-bordered select-sm w-full" required${ssrIncludeBooleanAttr(!createChannelOptions.value.length) ? " disabled" : ""}><option value=""${ssrIncludeBooleanAttr(Array.isArray(cChannel.value) ? ssrLooseContain(cChannel.value, "") : ssrLooseEqual(cChannel.value, "")) ? " selected" : ""}>${ssrInterpolate(cBrand.value ? createChannelOptions.value.length ? "请选择渠道商" : "该品牌商暂无已启用渠道商" : "请先选择品牌商")}</option><!--[-->`);
|
|
ssrRenderList(createChannelOptions.value, (ch) => {
|
|
_push(`<option${ssrRenderAttr("value", ch.id)}${ssrIncludeBooleanAttr(Array.isArray(cChannel.value) ? ssrLooseContain(cChannel.value, ch.id) : ssrLooseEqual(cChannel.value, ch.id)) ? " selected" : ""}>${ssrInterpolate(ch.name + " (" + ch.id + ")")}</option>`);
|
|
});
|
|
_push(`<!--]--></select></div><div class="form-control"><label class="label"><span class="label-text font-medium">产品 *</span></label><select class="select select-bordered select-sm w-full" required${ssrIncludeBooleanAttr(!createProductOptions.value.length) ? " disabled" : ""}><option${ssrRenderAttr("value", 0)}${ssrIncludeBooleanAttr(Array.isArray(cProduct.value) ? ssrLooseContain(cProduct.value, 0) : ssrLooseEqual(cProduct.value, 0)) ? " selected" : ""}>${ssrInterpolate(cBrand.value ? "请选择产品" : "请先选择品牌商")}</option><!--[-->`);
|
|
ssrRenderList(createProductOptions.value, (p) => {
|
|
_push(`<option${ssrRenderAttr("value", p.id)}${ssrIncludeBooleanAttr(Array.isArray(cProduct.value) ? ssrLooseContain(cProduct.value, p.id) : ssrLooseEqual(cProduct.value, p.id)) ? " selected" : ""}>${ssrInterpolate((p.devicename || "") + " (" + hexId(p.id) + ")")}</option>`);
|
|
});
|
|
_push(`<!--]--></select></div></div><div class="tabs tabs-boxed mb-4 bg-slate-100 inline-flex"><a class="${ssrRenderClass([{ "tab-active": createMode.value === "production" }, "tab tab-sm"])}">生产</a><a class="${ssrRenderClass([{ "tab-active": createMode.value === "import" }, "tab tab-sm"])}">导入</a></div><div class="grid grid-cols-2 gap-4 mb-1" style="${ssrRenderStyle(createMode.value === "production" ? null : { display: "none" })}"><div class="form-control"><label class="label"><span class="label-text font-medium">生产数量 *</span></label><input${ssrRenderAttr("value", cNumber.value)} type="number" class="input input-bordered input-sm w-full" min="1" max="10000" placeholder="生产数量(副)"${ssrIncludeBooleanAttr(createMode.value === "production") ? " required" : ""}></div><div class="form-control"><label class="label"><span class="label-text font-medium">绑定MAC地址</span></label><input${ssrIncludeBooleanAttr(Array.isArray(cBindmac.value) ? ssrLooseContain(cBindmac.value, null) : cBindmac.value) ? " checked" : ""} type="checkbox" class="toggle toggle-primary"></div></div><div style="${ssrRenderStyle(createMode.value === "import" ? null : { display: "none" })}"><div class="form-control mb-2"><label class="label"><span class="label-text font-medium">上传 CSV 文件</span></label><input type="file" class="file-input file-input-bordered file-input-sm w-full" accept=".csv"><p class="text-xs text-slate-400 mt-1">上传 CSV 文件,系统将读取第一列作为 MAC 地址</p></div><div class="form-control mb-1"><label class="label"><span class="label-text font-medium">MAC 地址列表 *</span></label><textarea class="textarea textarea-bordered w-full" rows="4" placeholder="MAC 地址以逗号分隔,可手动输入或通过CSV导入">${ssrInterpolate(cMacaddresses.value)}</textarea></div></div>`);
|
|
if (cProduct.value) {
|
|
_push(`<div class="rounded-lg bg-indigo-50 border border-indigo-100 px-4 py-3 text-sm text-slate-700 mt-3 mb-3"><div class="flex flex-wrap gap-x-6 gap-y-1"><span>产品类型:<b>${ssrInterpolate(createProductInfo.value.isClassicBT ? "经典蓝牙耳机(设备码,绑定MAC)" : "通用产品(授权码)")}</b></span><span>每副份数:<b>${ssrInterpolate(createProductInfo.value.codeCount)}</b></span>`);
|
|
if (createMode.value === "production") {
|
|
_push(`<span>最终生成:<b class="text-indigo-600">${ssrInterpolate(createFinalTotal.value)}</b> 个${ssrInterpolate(createProductInfo.value.isClassicBT ? "设备码" : "授权码")} `);
|
|
if (createProductInfo.value.codeCount > 1) {
|
|
_push(`<!--[-->(${ssrInterpolate(cNumber.value || 0)} 副 × ${ssrInterpolate(createProductInfo.value.codeCount)} 份)<!--]-->`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</span>`);
|
|
} else {
|
|
_push(`<span>最终生成:<b class="text-indigo-600">${ssrInterpolate(importMacCount.value)}</b> 个设备码(按 MAC 条数)</span>`);
|
|
}
|
|
_push(`</div></div>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`<div class="form-control mb-4"><label class="label"><span class="label-text font-medium">备注</span></label><input${ssrRenderAttr("value", cRemark.value)} type="text" class="input input-bordered input-sm w-full" placeholder="批次备注(选填)"></div><div class="modal-action"><button type="button" class="btn btn-ghost btn-sm">取消</button><button type="submit" class="btn btn-primary btn-sm text-white"${ssrIncludeBooleanAttr(previewLoading.value) ? " disabled" : ""}>`);
|
|
if (previewLoading.value) {
|
|
_push(`<span class="loading loading-spinner loading-xs"></span>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`下一步:确认生产方案 </button></div></form></div><form method="dialog" class="modal-backdrop"><button>close</button></form></dialog><dialog class="modal"><div class="modal-box max-w-lg"><h3 class="font-bold text-lg mb-3">确认生产方案</h3><div class="bg-amber-50 border border-amber-200 rounded-lg p-3 text-xs text-amber-700 mb-4"> 请核对以下生产方案。确认后立即提交服务端生产,批次一经生成只能整批撤销、不可修改。 </div>`);
|
|
if (preview.value) {
|
|
_push(`<div class="rounded-lg border border-slate-200 bg-slate-50 px-4 py-3 font-mono text-sm leading-7 mb-4"><div>生产批次(BatchNo):<b class="text-indigo-600">${ssrInterpolate(preview.value.batchno || "生产时分配")}</b></div><div>品牌商:${ssrInterpolate(preview.value.brandname)}</div><div>渠道商:${ssrInterpolate(preview.value.channelname)}(${ssrInterpolate(preview.value.channelid)})</div><div>服务ID(CID):0x${ssrInterpolate(previewCid.value)}</div><div>品牌ID(BID):0x${ssrInterpolate(hexId(preview.value.brandid).padStart(4, "0"))}</div><div>产品ID(PID):0x${ssrInterpolate(hexId(preview.value.productid).padStart(4, "0"))}</div><div>产品名称:${ssrInterpolate(preview.value.productname)}</div><div>授权码类型:${ssrInterpolate(preview.value.codetype)}</div><div>生产数量:<b class="text-indigo-600">${ssrInterpolate(preview.value.total)}</b> 个`);
|
|
if (preview.value.codecount > 1) {
|
|
_push(`<!--[-->(每副 ${ssrInterpolate(preview.value.codecount)} 份)<!--]-->`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div><div>序号区间:${ssrInterpolate(preview.value.serialstart)} - ${ssrInterpolate(preview.value.serialend)}</div>`);
|
|
if (preview.value.startmac) {
|
|
_push(`<div>MAC地址区间:${ssrInterpolate(preview.value.startmac)} - ${ssrInterpolate(preview.value.endmac)}</div>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`</div>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`<div class="modal-action"><button type="button" class="btn btn-ghost btn-sm">返回修改</button><button type="button" class="btn btn-primary btn-sm text-white"${ssrIncludeBooleanAttr(submitting.value) ? " disabled" : ""}>`);
|
|
if (submitting.value) {
|
|
_push(`<span class="loading loading-spinner loading-xs"></span>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`确认生产 </button></div></div><form method="dialog" class="modal-backdrop"><button>close</button></form></dialog><dialog class="modal"><div class="modal-box w-11/12 max-w-2xl"><h3 class="font-bold text-lg mb-4 flex items-center gap-2"><svg class="h-5 w-5 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path></svg> 发送邮件通知 </h3><form><div class="grid grid-cols-2 gap-4 mb-3"><div class="form-control"><label class="label"><span class="label-text text-xs">收件人 *</span></label><input${ssrRenderAttr("value", email.to)} type="email" class="input input-bordered input-sm w-full" required></div><div class="form-control"><label class="label"><span class="label-text text-xs">抄送</span></label><input${ssrRenderAttr("value", email.cc)} type="text" class="input input-bordered input-sm w-full" placeholder="多个邮箱用逗号分隔"></div></div><div class="form-control mb-3"><label class="label"><span class="label-text text-xs">主题 *</span></label><input${ssrRenderAttr("value", email.subject)} type="text" class="input input-bordered input-sm w-full" required></div><div class="form-control mb-3"><label class="label"><span class="label-text text-xs">内容 *</span></label><textarea class="textarea textarea-bordered w-full" rows="10" required>${ssrInterpolate(email.content)}</textarea></div><div class="form-control mb-4"><label class="label"><span class="label-text text-xs">附件</span></label><div class="text-sm text-slate-500">${ssrInterpolate(csvFileName.value ? "📎 " + csvFileName.value : "无附件")}</div></div><div class="modal-action"><button type="button" class="btn btn-ghost btn-sm">取消</button><button type="submit" class="btn btn-primary btn-sm text-white"${ssrIncludeBooleanAttr(emailSending.value) ? " disabled" : ""}>`);
|
|
if (emailSending.value) {
|
|
_push(`<span class="loading loading-spinner loading-xs"></span>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`发送邮件 </button></div></form></div><form method="dialog" class="modal-backdrop"><button>close</button></form></dialog><dialog class="modal"><div class="modal-box max-w-md"><h3 class="font-bold text-lg mb-3 flex items-center gap-2 text-red-600"><svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01M4.93 19h14.14a2 2 0 001.74-3L13.74 4a2 2 0 00-3.48 0L3.19 16a2 2 0 001.74 3z"></path></svg> 撤销生产批次 </h3><div class="bg-red-50 border border-red-200 rounded-lg p-3 text-sm text-red-700 mb-4"> 此操作将<strong>删除该批次的全部授权码</strong>以及对应的生产出货记录,<strong>不可恢复</strong>。<br> 若该批次中已有任意授权码被激活/绑定,撤销会被拒绝。 </div><div class="text-sm space-y-1 mb-4"><div><span class="text-slate-500">品牌商:</span><span class="font-medium">${ssrInterpolate(revokeCtx.value ? nameOfBrand(revokeCtx.value.brandid) : "")}</span></div><div><span class="text-slate-500">产品:</span><span class="font-medium">${ssrInterpolate(revokeCtx.value ? nameOfProduct(revokeCtx.value.productid) : "")}</span></div><div><span class="text-slate-500">批次号:</span><span class="font-mono font-medium text-red-600">${ssrInterpolate(revokeConfirmTarget.value)}</span></div><div><span class="text-slate-500">授权码数量:</span><span class="font-medium">${ssrInterpolate(revokeCtx.value ? revokeCtx.value.devicenum : "")}</span></div></div><div class="form-control mb-2"><label class="label"><span class="label-text text-xs">请输入批次号 <span class="font-mono text-red-600">${ssrInterpolate(revokeConfirmTarget.value)}</span> 以确认撤销</span></label><input${ssrRenderAttr("value", revokeConfirmInput.value)} type="text" class="input input-bordered input-sm w-full" autocomplete="off"></div><p class="text-xs text-red-500 min-h-[1em] mb-2">${ssrInterpolate(revokeError.value)}</p><div class="modal-action"><button type="button" class="btn btn-ghost btn-sm">取消</button><button type="button" class="btn btn-error btn-sm text-white"${ssrIncludeBooleanAttr(!revokeConfirmOk.value || revokeSubmitting.value) ? " disabled" : ""}>`);
|
|
if (revokeSubmitting.value) {
|
|
_push(`<span class="loading loading-spinner loading-xs"></span>`);
|
|
} else {
|
|
_push(`<!---->`);
|
|
}
|
|
_push(`确认撤销 </button></div></div><form method="dialog" class="modal-backdrop"><button>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/device.vue");
|
|
return _sfc_setup ? _sfc_setup(props, ctx) : void 0;
|
|
};
|
|
|
|
export { _sfc_main as default };
|
|
//# sourceMappingURL=device-DzDhira5.mjs.map
|
|
|