docs: annotate payment, host operations and shared components
This commit is contained in:
1 parent
d37ce57d09
commit
dc32a74d7a
17 files changed
+100
No files matched your search
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 监听 Nuxt 版本清单与分块加载失败,提示用户保存表单后确认刷新,不自动打断操作。 */
|
||||||
import "~/assets/styles/BuildUpdateNotice.CuqdqvlF.css";
|
import "~/assets/styles/BuildUpdateNotice.CuqdqvlF.css";
|
||||||
import { reloadNuxtApp as y } from "#app";
|
import { reloadNuxtApp as y } from "#app";
|
||||||
import { useNuxtApp } from "#app";
|
import { useNuxtApp } from "#app";
|
||||||
@@ -45,6 +46,7 @@ var b = {
|
|||||||
((C.value = !0), (h.value = !0));
|
((C.value = !0), (h.value = !0));
|
||||||
});
|
});
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
// hook 返回取消注册函数;卸载后必须解绑,避免重复提示。
|
||||||
(T(), E());
|
(T(), E());
|
||||||
});
|
});
|
||||||
function D() {
|
function D() {
|
||||||
@@ -54,6 +56,7 @@ var b = {
|
|||||||
v.value = !0;
|
v.value = !0;
|
||||||
}
|
}
|
||||||
function k() {
|
function k() {
|
||||||
|
// 确认后强制完整刷新且不持久化 Nuxt 状态,避免新版本继续使用旧内存状态。
|
||||||
!S.value &&
|
!S.value &&
|
||||||
v.value &&
|
v.value &&
|
||||||
((S.value = !0),
|
((S.value = !0),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
/** 共用折线图容器:父级负责 option/数据,组件补充主题、可见尺寸和卸载清理。 */
|
||||||
import { computed, onMounted, onBeforeUnmount, ref } from "vue";
|
import { computed, onMounted, onBeforeUnmount, ref } from "vue";
|
||||||
import { use } from "echarts/core";
|
import { use } from "echarts/core";
|
||||||
import { CanvasRenderer } from "echarts/renderers";
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
@@ -13,6 +14,7 @@ import { t as useTheme } from "~/lib/useTheme.js";
|
|||||||
import "~/assets/styles/ChartBox.CYP_mhat.css";
|
import "~/assets/styles/ChartBox.CYP_mhat.css";
|
||||||
|
|
||||||
use([
|
use([
|
||||||
|
// 仅注册实际使用的折线图、Canvas 和基础组件;新增图表类型时须同步显式注册。
|
||||||
CanvasRenderer,
|
CanvasRenderer,
|
||||||
LineChart,
|
LineChart,
|
||||||
GridComponent,
|
GridComponent,
|
||||||
@@ -29,6 +31,7 @@ const container = ref(null);
|
|||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
let observer;
|
let observer;
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
// 折叠面板初始尺寸可能为零;等容器可测量后创建图表,避免 ECharts 零宽初始化。
|
||||||
observer = new ResizeObserver(([entry]) => {
|
observer = new ResizeObserver(([entry]) => {
|
||||||
if (entry?.contentRect.width > 0 && entry.contentRect.height > 0)
|
if (entry?.contentRect.width > 0 && entry.contentRect.height > 0)
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
@@ -37,6 +40,7 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
onBeforeUnmount(() => observer?.disconnect());
|
onBeforeUnmount(() => observer?.disconnect());
|
||||||
const themedOption = computed(() => {
|
const themedOption = computed(() => {
|
||||||
|
// 在不修改父级 option 的前提下合成坐标轴主题,兼容单个轴与多轴数组。
|
||||||
const dark = theme.isDark.value;
|
const dark = theme.isDark.value;
|
||||||
const color = dark ? "#a1a1aa" : "#94a3b8";
|
const color = dark ? "#a1a1aa" : "#94a3b8";
|
||||||
const grid = dark ? "rgba(255,255,255,.08)" : "rgba(0,0,0,.06)";
|
const grid = dark ? "rgba(255,255,255,.08)" : "rgba(0,0,0,.06)";
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 控制台固定备案页脚;运营主体、备案号及许可号为展示内容,更新需先核实实际登记信息。 */
|
||||||
import "~/assets/styles/ConsoleLegalFooter.DAYWmXIB.css";
|
import "~/assets/styles/ConsoleLegalFooter.DAYWmXIB.css";
|
||||||
import { createElementBlock } from "vue";
|
import { createElementBlock } from "vue";
|
||||||
import { createElementVNode } from "vue";
|
import { createElementVNode } from "vue";
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/**
|
||||||
|
* 服务器列表的共享业务组件,供云服务器、独立服务器及动态后台菜单复用。
|
||||||
|
* modules/menuId 决定数据范围,title/tabs/tabParams 决定列表展示与筛选映射;
|
||||||
|
* 页面自身负责列表、按模块补充状态/流量、备注、批量电源操作及批量续费。
|
||||||
|
* 恢复后的短变量名仍与渲染树对应,修改时重点保持身份代次、分页快照及模块接口契约。
|
||||||
|
*/
|
||||||
import "~/assets/styles/PaymentDialog.BNFKQF1U.css";
|
import "~/assets/styles/PaymentDialog.BNFKQF1U.css";
|
||||||
import "~/assets/styles/OsIcon.CAi4Iz2S.css";
|
import "~/assets/styles/OsIcon.CAi4Iz2S.css";
|
||||||
import "~/assets/styles/HostList.B3U15sJm.css";
|
import "~/assets/styles/HostList.B3U15sJm.css";
|
||||||
@@ -72,6 +78,7 @@ import { n as renewal_quote_n } from "~/lib/renewal-quote.js";
|
|||||||
import { r as renewal_quote_r } from "~/lib/renewal-quote.js";
|
import { r as renewal_quote_r } from "~/lib/renewal-quote.js";
|
||||||
import { t as renewal_quote_t } from "~/lib/renewal-quote.js";
|
import { t as renewal_quote_t } from "~/lib/renewal-quote.js";
|
||||||
var T = new WeakMap();
|
var T = new WeakMap();
|
||||||
|
// 列表筛选快照按 auth 实例和菜单/模块分别保存;切换 token 时清空,避免串用账号状态。
|
||||||
function We(e, t) {
|
function We(e, t) {
|
||||||
let n = T.get(e);
|
let n = T.get(e);
|
||||||
if (!n) {
|
if (!n) {
|
||||||
@@ -114,6 +121,7 @@ function We(e, t) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
function Ge(e, t) {
|
function Ge(e, t) {
|
||||||
|
// 机电状态查询器:每轮重建请求队列,最多三个并发,并用身份/版本/请求号拒绝过期响应。
|
||||||
let n = ref({}),
|
let n = ref({}),
|
||||||
r = 0,
|
r = 0,
|
||||||
i = !1,
|
i = !1,
|
||||||
@@ -132,6 +140,7 @@ function Ge(e, t) {
|
|||||||
(r++, (d = []), l.clear(), (n.value = {}));
|
(r++, (d = []), l.clear(), (n.value = {}));
|
||||||
}
|
}
|
||||||
function m(e) {
|
function m(e) {
|
||||||
|
// 实例必须仍在当前列表且为 Active,才能将异步返回的电源状态写回。
|
||||||
return (
|
return (
|
||||||
!i &&
|
!i &&
|
||||||
e.version === r &&
|
e.version === r &&
|
||||||
@@ -217,6 +226,7 @@ function Ge(e, t) {
|
|||||||
g();
|
g();
|
||||||
}
|
}
|
||||||
function _(e) {
|
function _(e) {
|
||||||
|
// 电源操作成功后优先刷新对应实例,并先显示 operating,不能假定指令已执行完成。
|
||||||
if (i || t.loading.value || t.error.value) return;
|
if (i || t.loading.value || t.error.value) return;
|
||||||
let a = new Set(e);
|
let a = new Set(e);
|
||||||
d = d.filter((e) => !a.has(e.id));
|
d = d.filter((e) => !a.has(e.id));
|
||||||
@@ -294,12 +304,14 @@ for (let e of [
|
|||||||
actions: D,
|
actions: D,
|
||||||
};
|
};
|
||||||
function Ke(e) {
|
function Ke(e) {
|
||||||
|
// 不同模块支持的批量动作不同;列表中的 re 前缀模块仍使用对应接口能力映射。
|
||||||
return O[e] || O[`re${e}`];
|
return O[e] || O[`re${e}`];
|
||||||
}
|
}
|
||||||
function qe(e) {
|
function qe(e) {
|
||||||
return typeof e == `string` ? O[e] : void 0;
|
return typeof e == `string` ? O[e] : void 0;
|
||||||
}
|
}
|
||||||
function Je(e, t) {
|
function Je(e, t) {
|
||||||
|
// 每个请求 ID 必须恰好得到一项明确结果;缺失、重复或非 200 响应一律不能算成功。
|
||||||
let n = Array.isArray(e) ? e : [];
|
let n = Array.isArray(e) ? e : [];
|
||||||
return t.map((e) => {
|
return t.map((e) => {
|
||||||
let t = n.filter((t) => t && typeof t == `object` && Number(t.id) === e),
|
let t = n.filter((t) => t && typeof t == `object` && Number(t.id) === e),
|
||||||
@@ -512,6 +524,7 @@ var Ye = {
|
|||||||
tabParams: {},
|
tabParams: {},
|
||||||
},
|
},
|
||||||
setup(c) {
|
setup(c) {
|
||||||
|
// 共享列表适配器负责分页和缓存,本组件补充菜单字段配置及实例业务操作。
|
||||||
let m = c,
|
let m = c,
|
||||||
b = useApi(),
|
b = useApi(),
|
||||||
w = useAuth(),
|
w = useAuth(),
|
||||||
@@ -522,6 +535,7 @@ var Ye = {
|
|||||||
D = ref(null),
|
D = ref(null),
|
||||||
O = 0;
|
O = 0;
|
||||||
async function rn(e) {
|
async function rn(e) {
|
||||||
|
// 异步返回的动态列只属于当前请求与当前账号,不能覆盖切换后的菜单字段。
|
||||||
let t = ++O,
|
let t = ++O,
|
||||||
n = w.token,
|
n = w.token,
|
||||||
r = await E(e);
|
r = await E(e);
|
||||||
@@ -554,6 +568,7 @@ var Ye = {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
function on(e, t) {
|
function on(e, t) {
|
||||||
|
// 动态自定义列仅展示标量;密码字段始终遮盖,不因表格刷新而暴露原值。
|
||||||
let n = e.self_defined_field?.[t.id];
|
let n = e.self_defined_field?.[t.id];
|
||||||
return n == null || n === ``
|
return n == null || n === ``
|
||||||
? `—`
|
? `—`
|
||||||
@@ -675,6 +690,7 @@ var Ye = {
|
|||||||
wn = Cn.statusOf,
|
wn = Cn.statusOf,
|
||||||
Tn = T?.scrollY ?? null;
|
Tn = T?.scrollY ?? null;
|
||||||
function En() {
|
function En() {
|
||||||
|
// 离开详情前保存筛选、分页及滚动位置;快照仅存在当前账号的内存中。
|
||||||
Oe.save({
|
Oe.save({
|
||||||
tab: A.value,
|
tab: A.value,
|
||||||
keywords: j.value,
|
keywords: j.value,
|
||||||
@@ -742,6 +758,7 @@ var Ye = {
|
|||||||
},
|
},
|
||||||
));
|
));
|
||||||
function Dn() {
|
function Dn() {
|
||||||
|
// 业务操作后的强刷新同时失效列表、状态和流量补充数据,防止混合新旧快照。
|
||||||
return (
|
return (
|
||||||
Cn.reset(),
|
Cn.reset(),
|
||||||
E.invalidate(!0),
|
E.invalidate(!0),
|
||||||
@@ -800,6 +817,7 @@ var Ye = {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
async function Rn(e, t = !1) {
|
async function Rn(e, t = !1) {
|
||||||
|
// 快快云流量单独取数:同一实例合并在途请求,以刷新版本阻止旧数据回写。
|
||||||
if (
|
if (
|
||||||
e.module !== `kky_ecs` ||
|
e.module !== `kky_ecs` ||
|
||||||
e.status === `Unpaid` ||
|
e.status === `Unpaid` ||
|
||||||
@@ -882,6 +900,8 @@ var Ye = {
|
|||||||
: n;
|
: n;
|
||||||
}
|
}
|
||||||
async function Bn(e) {
|
async function Bn(e) {
|
||||||
|
// 按实例真实模块补齐系统与流量信息;列表缺少 module 时先查询 host/view。
|
||||||
|
// 不同财务模块的配置结构并不相同,不能把此处接口路径直接统一成一种格式。
|
||||||
let t = R;
|
let t = R;
|
||||||
if (!(Fn.value[e.id]?.version === t || In.has(e.id))) {
|
if (!(Fn.value[e.id]?.version === t || In.has(e.id))) {
|
||||||
In.set(e.id, t);
|
In.set(e.id, t);
|
||||||
@@ -962,6 +982,7 @@ var Ye = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function Vn(e) {
|
async function Vn(e) {
|
||||||
|
// 附加数据按三路工作队列加载;翻页或卸载推进代次,不再继续启动旧队列任务。
|
||||||
let t = ++Ln;
|
let t = ++Ln;
|
||||||
if (dn.value) return;
|
if (dn.value) return;
|
||||||
async function n(n) {
|
async function n(n) {
|
||||||
@@ -1009,6 +1030,7 @@ var Ye = {
|
|||||||
W.value || ((U.value = null), (G.value = ``));
|
W.value || ((U.value = null), (G.value = ``));
|
||||||
}
|
}
|
||||||
async function qn() {
|
async function qn() {
|
||||||
|
// 单条备注保存绑定提交时身份,成功后刷新列表,避免仅本地乐观更新留下旧缓存。
|
||||||
let e = U.value;
|
let e = U.value;
|
||||||
if (!e || W.value) return;
|
if (!e || W.value) return;
|
||||||
let t = Wn.value,
|
let t = Wn.value,
|
||||||
@@ -1130,6 +1152,7 @@ var Ye = {
|
|||||||
Q.value || (er.value = null);
|
Q.value || (er.value = null);
|
||||||
}
|
}
|
||||||
async function sr() {
|
async function sr() {
|
||||||
|
// 批量备注要求成功/失败/总数与所选 ID 严格对齐,结果不完整时回读列表而不报全成功。
|
||||||
let e = er.value;
|
let e = er.value;
|
||||||
if (!e || Q.value || X || e.token !== w.token || e.epoch !== Y)
|
if (!e || Q.value || X || e.token !== w.token || e.epoch !== Y)
|
||||||
return;
|
return;
|
||||||
@@ -1225,6 +1248,8 @@ var Ye = {
|
|||||||
(cr(), vn(e));
|
(cr(), vn(e));
|
||||||
}
|
}
|
||||||
async function hr() {
|
async function hr() {
|
||||||
|
// 批量电源操作先逐台核对真实管理模块,再按接口分组提交,保留失败实例供重试。
|
||||||
|
// 请求过程绑定 token 与操作代次;“指令下发”不等于已开关机,完成后另刷电源状态。
|
||||||
let e = J.value;
|
let e = J.value;
|
||||||
if (
|
if (
|
||||||
!e ||
|
!e ||
|
||||||
@@ -1333,6 +1358,7 @@ var Ye = {
|
|||||||
_r.value.filter((e) => e.renew_forbidden !== 1),
|
_r.value.filter((e) => e.renew_forbidden !== 1),
|
||||||
);
|
);
|
||||||
async function Dr() {
|
async function Dr() {
|
||||||
|
// 批量续费先取可用周期和报价,所选实例改变、弹窗关闭或卸载后放弃旧报价。
|
||||||
if (xr.value || Tr) return;
|
if (xr.value || Tr) return;
|
||||||
let e = ++wr,
|
let e = ++wr,
|
||||||
t = K.value.map((e) => e.id),
|
t = K.value.map((e) => e.id),
|
||||||
@@ -1385,6 +1411,7 @@ var Ye = {
|
|||||||
),
|
),
|
||||||
Ar = ref(null);
|
Ar = ref(null);
|
||||||
async function jr() {
|
async function jr() {
|
||||||
|
// 只提交允许续费的实例、周期及非空优惠码;未支付订单交给 PaymentDialog 接续处理。
|
||||||
if (Er.value.length) {
|
if (Er.value.length) {
|
||||||
((xr.value = !0), (Sr.value = ``), (Cr.value = ``));
|
((xr.value = !0), (Sr.value = ``), (Cr.value = ``));
|
||||||
try {
|
try {
|
||||||
@@ -1435,6 +1462,7 @@ var Ye = {
|
|||||||
e && Ar.value && (Pr.value = Ar.value.id);
|
e && Ar.value && (Pr.value = Ar.value.id);
|
||||||
}),
|
}),
|
||||||
(e, r) => {
|
(e, r) => {
|
||||||
|
// 渲染区域依次包含筛选表格、备注/批量操作弹窗、续费报价及共用支付面板。
|
||||||
let a = ListSegments,
|
let a = ListSegments,
|
||||||
s = inputtext,
|
s = inputtext,
|
||||||
u = button,
|
u = button,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 无数据状态的展示组件;icon/title/description 由父级提供,默认插槽可放置创建或重试操作。 */
|
||||||
import { toDisplayString } from "vue";
|
import { toDisplayString } from "vue";
|
||||||
import { normalizeClass } from "vue";
|
import { normalizeClass } from "vue";
|
||||||
import { renderSlot } from "vue";
|
import { renderSlot } from "vue";
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 列表分段筛选器:options 使用 label/value,点击只更新 v-model,由父级决定何时请求数据。 */
|
||||||
import { toDisplayString } from "vue";
|
import { toDisplayString } from "vue";
|
||||||
import { renderList } from "vue";
|
import { renderList } from "vue";
|
||||||
import { normalizeClass } from "vue";
|
import { normalizeClass } from "vue";
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 根据站点强制安全方式决定是否渲染操作密码插槽;实际密码校验仍由提交接口负责。 */
|
||||||
import { onMounted } from "vue";
|
import { onMounted } from "vue";
|
||||||
import { renderSlot } from "vue";
|
import { renderSlot } from "vue";
|
||||||
import { createCommentVNode } from "vue";
|
import { createCommentVNode } from "vue";
|
||||||
@@ -11,6 +12,7 @@ var s = Object.assign(
|
|||||||
__name: `OperatePasswordGate`,
|
__name: `OperatePasswordGate`,
|
||||||
setup(a) {
|
setup(a) {
|
||||||
let { config: s, load: c } = useSiteConfig_t(),
|
let { config: s, load: c } = useSiteConfig_t(),
|
||||||
|
// 配置未加载或未开启 operate_password 时不显示,不自行推测站点策略。
|
||||||
l = computed(
|
l = computed(
|
||||||
() =>
|
() =>
|
||||||
Array.isArray(s.value?.home_enforce_safe_method) &&
|
Array.isArray(s.value?.home_enforce_safe_method) &&
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 将父级 message/severity/details 转交给 operations 通知组;默认插槽仍正常渲染。 */
|
||||||
import { onMounted } from "vue";
|
import { onMounted } from "vue";
|
||||||
import { renderSlot } from "vue";
|
import { renderSlot } from "vue";
|
||||||
import { watch } from "vue";
|
import { watch } from "vue";
|
||||||
@@ -20,6 +21,7 @@ var a = Object.assign(
|
|||||||
let a = r,
|
let a = r,
|
||||||
o = useToast();
|
o = useToast();
|
||||||
function s() {
|
function s() {
|
||||||
|
// 有逐项结果时不自动消失,便于用户检查;普通成功/失败通知按不同寿命自动关闭。
|
||||||
a.message.trim() &&
|
a.message.trim() &&
|
||||||
o.add({
|
o.add({
|
||||||
group: `operations`,
|
group: `operations`,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** operations 通知组的统一展示层,最多显示三条,批量操作明细通过可展开区域呈现。 */
|
||||||
import "~/assets/styles/OperationToasts.DfA_b8om.css";
|
import "~/assets/styles/OperationToasts.DfA_b8om.css";
|
||||||
import { toDisplayString } from "vue";
|
import { toDisplayString } from "vue";
|
||||||
import { renderList } from "vue";
|
import { renderList } from "vue";
|
||||||
@@ -29,6 +30,7 @@ var h = {
|
|||||||
let _ = useToast(),
|
let _ = useToast(),
|
||||||
v = useAuth();
|
v = useAuth();
|
||||||
watch(
|
watch(
|
||||||
|
// 账号改变即移除旧通知,避免下一位用户看到上一账号的操作结果。
|
||||||
() => v.token,
|
() => v.token,
|
||||||
() => _.removeGroup(`operations`),
|
() => _.removeGroup(`operations`),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 页面静态说明容器:内容来自默认插槽,使用 note 而非实时警报,避免反复朗读。 */
|
||||||
import "~/assets/styles/PageInfoNotice._16xRFrB.css";
|
import "~/assets/styles/PageInfoNotice._16xRFrB.css";
|
||||||
import { renderSlot } from "vue";
|
import { renderSlot } from "vue";
|
||||||
import { createBlock } from "vue";
|
import { createBlock } from "vue";
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 只读步骤条:steps 为文案数组,current 从 1 开始;小于当前步骤的项显示完成标记。 */
|
||||||
import "~/assets/styles/PageSteps.B5K7G9zF.css";
|
import "~/assets/styles/PageSteps.B5K7G9zF.css";
|
||||||
import { toDisplayString } from "vue";
|
import { toDisplayString } from "vue";
|
||||||
import { renderList } from "vue";
|
import { renderList } from "vue";
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/**
|
||||||
|
* 订单支付面板:支持弹窗与内嵌两种展示,共用同一套订单、余额及代金券状态。
|
||||||
|
* 父级传入 orderId/amount,以 modelValue 控制可见性;success 表示服务端已确认支付,
|
||||||
|
* updated 用于通知父级刷新抵扣后的订单。amount 仅作初始展示,支付前会重新读取订单。
|
||||||
|
* 本文件保留恢复后的渲染函数与短变量名;金额换算和异步代次是维护时的关键约束。
|
||||||
|
*/
|
||||||
import "~/assets/styles/PaymentDialog.BNFKQF1U.css";
|
import "~/assets/styles/PaymentDialog.BNFKQF1U.css";
|
||||||
import { toDisplayString } from "vue";
|
import { toDisplayString } from "vue";
|
||||||
import { renderList } from "vue";
|
import { renderList } from "vue";
|
||||||
@@ -295,6 +301,7 @@ var ue = {
|
|||||||
),
|
),
|
||||||
emits: mergeModels([`success`, `updated`], [`update:modelValue`]),
|
emits: mergeModels([`success`, `updated`], [`update:modelValue`]),
|
||||||
setup(i, { emit: _ }) {
|
setup(i, { emit: _ }) {
|
||||||
|
// C 为支付步骤,O 为已支付标记;余额和订单金额在内部统一使用整数分。
|
||||||
let b = useModel(i, `modelValue`),
|
let b = useModel(i, `modelValue`),
|
||||||
x = i,
|
x = i,
|
||||||
Et = _,
|
Et = _,
|
||||||
@@ -358,6 +365,7 @@ var ue = {
|
|||||||
: `可用余额 ¥0.00`,
|
: `可用余额 ¥0.00`,
|
||||||
);
|
);
|
||||||
function H(e) {
|
function H(e) {
|
||||||
|
// 后端金额以元返回;拒绝空值、负值及超出安全整数范围的金额,避免错误抵扣。
|
||||||
if (e == null || String(e).trim() === ``) return null;
|
if (e == null || String(e).trim() === ``) return null;
|
||||||
let t = Number(e),
|
let t = Number(e),
|
||||||
n = Math.round(t * 100);
|
n = Math.round(t * 100);
|
||||||
@@ -366,6 +374,7 @@ var ue = {
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
function U(e) {
|
function U(e) {
|
||||||
|
// 仅在展示及接口金额文本边界将分转换回两位小数的元。
|
||||||
return (e / 100).toFixed(2);
|
return (e / 100).toFixed(2);
|
||||||
}
|
}
|
||||||
let W = ref([]),
|
let W = ref([]),
|
||||||
@@ -384,6 +393,7 @@ var ue = {
|
|||||||
paymentPoll = null,
|
paymentPoll = null,
|
||||||
Z = (e, t) => e === X && b.value && String(x.orderId) === String(t);
|
Z = (e, t) => e === X && b.value && String(x.orderId) === String(t);
|
||||||
function stopPaymentPolling() {
|
function stopPaymentPolling() {
|
||||||
|
// 一个支付面板只保留一个轮询会话,同时取消周期任务和绝对截止定时器。
|
||||||
const session = paymentPoll;
|
const session = paymentPoll;
|
||||||
paymentPoll = null;
|
paymentPoll = null;
|
||||||
if (!session) return;
|
if (!session) return;
|
||||||
@@ -391,6 +401,7 @@ var ue = {
|
|||||||
clearTimeout(session.deadlineTimer);
|
clearTimeout(session.deadlineTimer);
|
||||||
}
|
}
|
||||||
function It() {
|
function It() {
|
||||||
|
// 支付成功只通知一次;刷新账户概览失败不能反向撤销服务端支付结果。
|
||||||
O.value ||
|
O.value ||
|
||||||
(stopPaymentPolling(),
|
(stopPaymentPolling(),
|
||||||
(O.value = !0),
|
(O.value = !0),
|
||||||
@@ -398,6 +409,7 @@ var ue = {
|
|||||||
Et(`success`));
|
Et(`success`));
|
||||||
}
|
}
|
||||||
async function $(e = X, t = x.orderId, n = !1) {
|
async function $(e = X, t = x.orderId, n = !1) {
|
||||||
|
// 以订单 ID 和面板代次验证响应归属,关闭弹窗或切换订单后丢弃旧结果。
|
||||||
if (!t) return !1;
|
if (!t) return !1;
|
||||||
let r = await S.get(`/order/${t}`);
|
let r = await S.get(`/order/${t}`);
|
||||||
if (!Z(e, t)) return !1;
|
if (!Z(e, t)) return !1;
|
||||||
@@ -425,6 +437,7 @@ var ue = {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
async function Lt(e = X, t = x.orderId) {
|
async function Lt(e = X, t = x.orderId) {
|
||||||
|
// 余额读取失败保留“不可用”状态,而不是把未知余额当作可支付的零余额。
|
||||||
if (t) {
|
if (t) {
|
||||||
M.value = ``;
|
M.value = ``;
|
||||||
try {
|
try {
|
||||||
@@ -444,6 +457,7 @@ var ue = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function Rt(e = X, t = x.orderId) {
|
async function Rt(e = X, t = x.orderId) {
|
||||||
|
// credit 由独立余额开关管理;只有唯一外部支付渠道时才自动选中该渠道。
|
||||||
if (t)
|
if (t)
|
||||||
try {
|
try {
|
||||||
let n = await S.get(`/gateway`);
|
let n = await S.get(`/gateway`);
|
||||||
@@ -458,6 +472,7 @@ var ue = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function zt(e = X, t = x.orderId, n = !0) {
|
async function zt(e = X, t = x.orderId, n = !0) {
|
||||||
|
// 代金券可用列表与已使用状态都以服务端为准,不能在前端自行扣减订单金额。
|
||||||
if (t) {
|
if (t) {
|
||||||
(n && (J.value = !0), (Y.value = ``));
|
(n && (J.value = !0), (Y.value = ``));
|
||||||
try {
|
try {
|
||||||
@@ -493,6 +508,7 @@ var ue = {
|
|||||||
return t === null ? `` : t > 0 ? `满 ¥${U(t)} 可用` : `无金额门槛`;
|
return t === null ? `` : t > 0 ? `满 ¥${U(t)} 可用` : `无金额门槛`;
|
||||||
}
|
}
|
||||||
async function Ht() {
|
async function Ht() {
|
||||||
|
// 打开支付面板时并行读取订单、账户余额与渠道;订单类型决定是否再加载代金券。
|
||||||
// A visible dialog can outlive session invalidation until route teardown.
|
// A visible dialog can outlive session invalidation until route teardown.
|
||||||
if (!Dt.isLoggedIn) return;
|
if (!Dt.isLoggedIn) return;
|
||||||
let e = x.orderId,
|
let e = x.orderId,
|
||||||
@@ -543,6 +559,7 @@ var ue = {
|
|||||||
((T.value = e), (k.value = ``)));
|
((T.value = e), (k.value = ``)));
|
||||||
}
|
}
|
||||||
async function Kt(e) {
|
async function Kt(e) {
|
||||||
|
// 切换代金券后重新获取订单;失败时也回读券状态,覆盖服务端可能已完成的更新。
|
||||||
let t = x.orderId,
|
let t = x.orderId,
|
||||||
n = X;
|
n = X;
|
||||||
if (!(!t || D.value || A.value || J.value)) {
|
if (!(!t || D.value || A.value || J.value)) {
|
||||||
@@ -576,6 +593,7 @@ var ue = {
|
|||||||
Kt(e.value ?? null);
|
Kt(e.value ?? null);
|
||||||
}
|
}
|
||||||
(watch(
|
(watch(
|
||||||
|
// 可见性、订单或登录身份任一变化都会推进代次,使此前请求和轮询立即失效。
|
||||||
[b, () => x.orderId, () => Dt.token],
|
[b, () => x.orderId, () => Dt.token],
|
||||||
() => {
|
() => {
|
||||||
(X++,
|
(X++,
|
||||||
@@ -614,6 +632,8 @@ var ue = {
|
|||||||
(X++, stopPaymentPolling());
|
(X++, stopPaymentPolling());
|
||||||
}));
|
}));
|
||||||
async function Jt() {
|
async function Jt() {
|
||||||
|
// 真正发起支付前再次确认订单状态、金额和余额,防止用户依据过期快照付款。
|
||||||
|
// 组合支付先提交余额抵扣,再让 /pay 处理剩余款项;Paid 必须来自后端确认。
|
||||||
if (D.value || A.value || J.value || !b.value || !x.orderId) return;
|
if (D.value || A.value || J.value || !b.value || !x.orderId) return;
|
||||||
if (!Mt.value) {
|
if (!Mt.value) {
|
||||||
k.value = I.value
|
k.value = I.value
|
||||||
@@ -688,6 +708,8 @@ var ue = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function startPaymentPolling(generation, orderId) {
|
function startPaymentPolling(generation, orderId) {
|
||||||
|
// 轮询绑定面板代次、订单和 JWT;最多五分钟,且同一时刻只允许一个查询在途。
|
||||||
|
// 单次请求的超时不超过会话剩余寿命,切换账号或卸载后不会继续报告旧订单成功。
|
||||||
stopPaymentPolling();
|
stopPaymentPolling();
|
||||||
const session = {
|
const session = {
|
||||||
identity: S.identity(),
|
identity: S.identity(),
|
||||||
@@ -749,6 +771,7 @@ var ue = {
|
|||||||
session.interval = setInterval(pollStatus, 2000);
|
session.interval = setInterval(pollStatus, 2000);
|
||||||
}
|
}
|
||||||
return (n, a) => {
|
return (n, a) => {
|
||||||
|
// 内嵌与弹窗仅展示外壳不同,支付选择、错误提示及下一步动作复用上面的状态。
|
||||||
let o = NuxtLink,
|
let o = NuxtLink,
|
||||||
c = button,
|
c = button,
|
||||||
d = select,
|
d = select,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 分类订购说明:兼容被 HTML 实体编码的文本,清理富文本后仅在存在可见内容时展示。 */
|
||||||
import "~/assets/styles/ProductCategoryNotice.CwaR3eXN.css";
|
import "~/assets/styles/ProductCategoryNotice.CwaR3eXN.css";
|
||||||
import { normalizeClass } from "vue";
|
import { normalizeClass } from "vue";
|
||||||
import { createCommentVNode } from "vue";
|
import { createCommentVNode } from "vue";
|
||||||
@@ -28,6 +29,7 @@ var u = {
|
|||||||
setup(o) {
|
setup(o) {
|
||||||
let c = o,
|
let c = o,
|
||||||
f = computed(() => {
|
f = computed(() => {
|
||||||
|
// 最多解码两轮纯文本包装,随后统一消毒;图片也算有效内容,空白占位不显示。
|
||||||
let e = typeof c.description == `string` ? c.description : ``;
|
let e = typeof c.description == `string` ? c.description : ``;
|
||||||
for (let t = 0; t < 2; t++) {
|
for (let t = 0; t < 2; t++) {
|
||||||
let t = new DOMParser().parseFromString(e, `text/html`);
|
let t = new DOMParser().parseFromString(e, `text/html`);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 商品分组标题:约定名称中首个 -N 后的非空文本作为徽标,其余情况完整显示原名称。 */
|
||||||
import "~/assets/styles/ProductGroupLabel.B1kWpFA-.css";
|
import "~/assets/styles/ProductGroupLabel.B1kWpFA-.css";
|
||||||
import { toDisplayString } from "vue";
|
import { toDisplayString } from "vue";
|
||||||
import { createCommentVNode } from "vue";
|
import { createCommentVNode } from "vue";
|
||||||
@@ -10,6 +11,7 @@ import { defineComponent } from "vue";
|
|||||||
import { openBlock } from "vue";
|
import { openBlock } from "vue";
|
||||||
import { t as _plugin_vue_export_helper_t } from "~/lib/_plugin-vue_export-helper.js";
|
import { t as _plugin_vue_export_helper_t } from "~/lib/_plugin-vue_export-helper.js";
|
||||||
function l(e) {
|
function l(e) {
|
||||||
|
// 只在名称和徽标两部分均存在时拆分;导出的 n 也被其他商品展示逻辑复用。
|
||||||
let t = typeof e == `string` ? e.trim() : ``,
|
let t = typeof e == `string` ? e.trim() : ``,
|
||||||
n = t.indexOf(`-N`);
|
n = t.indexOf(`-N`);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/**
|
||||||
|
* 敏感文本展示器:按 kind 掩码手机号、邮箱、姓名、证件或普通文本。
|
||||||
|
* 仅当父级确实传入未掩码原文时提供“显示”按钮;它是界面保护,不替代后端访问控制。
|
||||||
|
*/
|
||||||
import "~/assets/styles/SensitiveValue.BSZlaRHT.css";
|
import "~/assets/styles/SensitiveValue.BSZlaRHT.css";
|
||||||
import { toDisplayString } from "vue";
|
import { toDisplayString } from "vue";
|
||||||
import { normalizeClass } from "vue";
|
import { normalizeClass } from "vue";
|
||||||
@@ -14,12 +18,14 @@ import { openBlock } from "vue";
|
|||||||
import { useRoute } from "#app";
|
import { useRoute } from "#app";
|
||||||
import { t as _plugin_vue_export_helper_t } from "~/lib/_plugin-vue_export-helper.js";
|
import { t as _plugin_vue_export_helper_t } from "~/lib/_plugin-vue_export-helper.js";
|
||||||
function p(e) {
|
function p(e) {
|
||||||
|
// 已由后端掩码的值不可在浏览器恢复;识别常见星号和圆点,避免误显示切换按钮。
|
||||||
return /[**•●]/u.test(e ?? ``);
|
return /[**•●]/u.test(e ?? ``);
|
||||||
}
|
}
|
||||||
function m(e) {
|
function m(e) {
|
||||||
return !!e?.trim() && !p(e);
|
return !!e?.trim() && !p(e);
|
||||||
}
|
}
|
||||||
function h(e, t, n) {
|
function h(e, t, n) {
|
||||||
|
// Array.from 按 Unicode 码点截取,短文本全部隐藏,避免前后保留区重叠泄漏原文。
|
||||||
let r = Array.from(e);
|
let r = Array.from(e);
|
||||||
return r.length <= t + n
|
return r.length <= t + n
|
||||||
? `*`.repeat(Math.max(r.length, 1))
|
? `*`.repeat(Math.max(r.length, 1))
|
||||||
@@ -102,6 +108,7 @@ var _ = {
|
|||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
watch(
|
watch(
|
||||||
|
// 数据、身份重置键或路由改变时恢复隐藏,不能延续上一条记录的展开状态。
|
||||||
[
|
[
|
||||||
() => f.value,
|
() => f.value,
|
||||||
() => f.kind,
|
() => f.kind,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/** 加载 /ticket/config 中启用的工单通知;失败可手动重试,富文本经过统一清理后展示。 */
|
||||||
import { toDisplayString } from "vue";
|
import { toDisplayString } from "vue";
|
||||||
import { onMounted } from "vue";
|
import { onMounted } from "vue";
|
||||||
import { onBeforeUnmount } from "vue";
|
import { onBeforeUnmount } from "vue";
|
||||||
@@ -27,6 +28,7 @@ var _ = [`innerHTML`],
|
|||||||
x = ref(!1),
|
x = ref(!1),
|
||||||
S = !1;
|
S = !1;
|
||||||
async function C() {
|
async function C() {
|
||||||
|
// loading 防止重复请求,S 标记卸载,异步响应不应写入已离开的页面。
|
||||||
if (!x.value) {
|
if (!x.value) {
|
||||||
((x.value = !0), (b.value = ``));
|
((x.value = !0), (b.value = ``));
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
<script>
|
<script>
|
||||||
|
/**
|
||||||
|
* 同源远程控制台:父级提供实例、模块及操作密码,通过 update:visible 关闭面板。
|
||||||
|
* 浏览器只向 /remote-console/sessions 申请短期会话,再以服务端返回的同源路径连接 noVNC。
|
||||||
|
* 这里不直连供应商 VNC 地址;部署时 HTTP 与 WebSocket 路径都需要网关反向代理。
|
||||||
|
*/
|
||||||
import "~/assets/styles/RemoteConsole.DLmX5UZu.css";
|
import "~/assets/styles/RemoteConsole.DLmX5UZu.css";
|
||||||
import { toDisplayString } from "vue";
|
import { toDisplayString } from "vue";
|
||||||
import { onMounted } from "vue";
|
import { onMounted } from "vue";
|
||||||
@@ -27,6 +32,7 @@ import { t as _plugin_vue_export_helper_t } from "~/lib/_plugin-vue_export-helpe
|
|||||||
import inputtext from "primevue/inputtext";
|
import inputtext from "primevue/inputtext";
|
||||||
var T = /^[a-f0-9]{64}$/;
|
var T = /^[a-f0-9]{64}$/;
|
||||||
function E(e, n) {
|
function E(e, n) {
|
||||||
|
// 独立连接状态机;d 是连接代次,h 保存需要删除的网关会话,g 是当前 RFB 客户端。
|
||||||
let r = useAuth(),
|
let r = useAuth(),
|
||||||
o = ref(`idle`),
|
o = ref(`idle`),
|
||||||
c = ref(``),
|
c = ref(``),
|
||||||
@@ -43,6 +49,7 @@ function E(e, n) {
|
|||||||
(m !== null && clearTimeout(m), (m = null));
|
(m !== null && clearTimeout(m), (m = null));
|
||||||
}
|
}
|
||||||
async function y(e, t) {
|
async function y(e, t) {
|
||||||
|
// 使用创建会话时的 token 做尽力释放;keepalive 允许页面离开时仍发送清理请求。
|
||||||
if (T.test(e))
|
if (T.test(e))
|
||||||
try {
|
try {
|
||||||
await fetch(`/remote-console/sessions/${e}`, {
|
await fetch(`/remote-console/sessions/${e}`, {
|
||||||
@@ -57,6 +64,7 @@ function E(e, n) {
|
|||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
|
// 统一释放入口先推进代次,再中止请求、断开 RFB、移除事件并删除远端会话。
|
||||||
if ((d++, p?.abort(), (p = null), v(), g)) {
|
if ((d++, p?.abort(), (p = null), v(), g)) {
|
||||||
for (let [e, t] of _) g.removeEventListener(e, t);
|
for (let [e, t] of _) g.removeEventListener(e, t);
|
||||||
try {
|
try {
|
||||||
@@ -76,12 +84,14 @@ function E(e, n) {
|
|||||||
(S(), (c.value = e), (o.value = `error`));
|
(S(), (c.value = e), (o.value = `error`));
|
||||||
}
|
}
|
||||||
function E(e) {
|
function E(e) {
|
||||||
|
// 建立连接或提交凭据后均有 45 秒上限,旧连接定时器不能终止新的连接。
|
||||||
(v(),
|
(v(),
|
||||||
(m = setTimeout(() => {
|
(m = setTimeout(() => {
|
||||||
e === d && !f && w(`连接超时,请重新连接。`);
|
e === d && !f && w(`连接超时,请重新连接。`);
|
||||||
}, 45e3)));
|
}, 45e3)));
|
||||||
}
|
}
|
||||||
function D(e, t) {
|
function D(e, t) {
|
||||||
|
// 仅展示有限长度的中文网关错误,避免把供应商地址、凭据或内部异常原样暴露。
|
||||||
if (t === 401) return `登录已失效,请重新登录后打开控制台。`;
|
if (t === 401) return `登录已失效,请重新登录后打开控制台。`;
|
||||||
if (t === 403) return `暂时无法访问此实例的控制台,请核对账号后重试。`;
|
if (t === 403) return `暂时无法访问此实例的控制台,请核对账号后重试。`;
|
||||||
let n = e && typeof e == `object` && `error` in e ? e.error : null;
|
let n = e && typeof e == `object` && `error` in e ? e.error : null;
|
||||||
@@ -91,6 +101,7 @@ function E(e, n) {
|
|||||||
: `控制台暂时无法连接,请稍后重试。`;
|
: `控制台暂时无法连接,请稍后重试。`;
|
||||||
}
|
}
|
||||||
async function O() {
|
async function O() {
|
||||||
|
// 登录状态、实例、模块和挂载节点共同构成连接身份;异步阶段每次回写前都重新核对。
|
||||||
if ((S(), (c.value = ``), f || !n.visible() || !e.value)) {
|
if ((S(), (c.value = ``), f || !n.visible() || !e.value)) {
|
||||||
o.value = `idle`;
|
o.value = `idle`;
|
||||||
return;
|
return;
|
||||||
@@ -146,6 +157,7 @@ function E(e, n) {
|
|||||||
? r.sessionId
|
? r.sessionId
|
||||||
: ``;
|
: ``;
|
||||||
if (!x()) {
|
if (!x()) {
|
||||||
|
// 创建成功但用户已关闭或切换实例时,仍要回收刚生成的服务端会话。
|
||||||
d && y(d, t);
|
d && y(d, t);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -165,6 +177,7 @@ function E(e, n) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let { default: f } = await loadModule(
|
let { default: f } = await loadModule(
|
||||||
|
// 只在实际连接时加载 noVNC,避免把远控依赖放进所有页面的首屏执行路径。
|
||||||
async () => {
|
async () => {
|
||||||
let { default: e } = await import("@novnc/novnc");
|
let { default: e } = await import("@novnc/novnc");
|
||||||
return {
|
return {
|
||||||
@@ -226,6 +239,7 @@ function E(e, n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function k(e) {
|
function k(e) {
|
||||||
|
// 只提交服务器明确要求的完整凭据;密码仅保留当前面板内存,不写入持久化存储。
|
||||||
if (!g || o.value !== `credentials` || u.value.some((t) => !e[t]))
|
if (!g || o.value !== `credentials` || u.value.some((t) => !e[t]))
|
||||||
return !1;
|
return !1;
|
||||||
try {
|
try {
|
||||||
@@ -273,6 +287,7 @@ function E(e, n) {
|
|||||||
},
|
},
|
||||||
));
|
));
|
||||||
function j(e) {
|
function j(e) {
|
||||||
|
// 其他标签页退出或更换账号时立即断开,不能等用户下一次远控操作才识别身份变化。
|
||||||
(e.key === `jwt` || e.key === null) &&
|
(e.key === `jwt` || e.key === null) &&
|
||||||
n.visible() &&
|
n.visible() &&
|
||||||
(S(), (o.value = `idle`), n.close());
|
(S(), (o.value = `idle`), n.close());
|
||||||
@@ -360,6 +375,7 @@ var D = [`aria-labelledby`],
|
|||||||
},
|
},
|
||||||
emits: [`update:visible`],
|
emits: [`update:visible`],
|
||||||
setup(g, { emit: b }) {
|
setup(g, { emit: b }) {
|
||||||
|
// 面板状态负责凭据表单、全屏与显示文案,连接生命周期由上面的状态机统一管理。
|
||||||
let x = g,
|
let x = g,
|
||||||
C = b,
|
C = b,
|
||||||
T = useId(),
|
T = useId(),
|
||||||
@@ -404,6 +420,7 @@ var D = [`aria-labelledby`],
|
|||||||
),
|
),
|
||||||
Z = computed(() => x.hostName?.trim() || `服务器实例`);
|
Z = computed(() => x.hostName?.trim() || `服务器实例`);
|
||||||
function Q() {
|
function Q() {
|
||||||
|
// 状态或可见性变化就清除输入,避免旧会话的凭据留在重新打开的表单中。
|
||||||
((z.value = ``), (B.value = ``), (V.value = ``), (H.value = ``));
|
((z.value = ``), (B.value = ``), (V.value = ``), (H.value = ``));
|
||||||
}
|
}
|
||||||
watch([W, () => x.visible], Q);
|
watch([W, () => x.visible], Q);
|
||||||
@@ -422,6 +439,7 @@ var D = [`aria-labelledby`],
|
|||||||
(J(), Q(), C(`update:visible`, !1));
|
(J(), Q(), C(`update:visible`, !1));
|
||||||
}
|
}
|
||||||
async function me() {
|
async function me() {
|
||||||
|
// 全屏是浏览器交互能力;失败只显示提示,不影响现有远程连接。
|
||||||
U.value = ``;
|
U.value = ``;
|
||||||
try {
|
try {
|
||||||
document.fullscreenElement === L.value
|
document.fullscreenElement === L.value
|
||||||
|
|||||||
Reference in new issue
Block a user