Files
console-dev/app/pages/account/api-keys.vue
T
2026-11-06 00:04:38 +08:00

928 lines
31 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script>
import "~/assets/styles/api-keys.Bq3Csr53.css";
import { toDisplayString } from "vue";
import { onMounted } from "vue";
import { onBeforeUnmount } from "vue";
import { createBlock } from "vue";
import { ref } from "vue";
import { withCtx } from "vue";
import { createCommentVNode } from "vue";
import { computed } from "vue";
import { reactive } from "vue";
import { isRef } from "vue";
import { createElementBlock } from "vue";
import { Fragment } from "vue";
import { createElementVNode } from "vue";
import { createTextVNode } from "vue";
import { unref } from "vue";
import { defineComponent } from "vue";
import { createVNode } from "vue";
import { openBlock } from "vue";
import { withModifiers } from "vue";
import { useHead } from "#app";
import { onBeforeRouteLeave } from "vue-router";
import { NuxtLink } from "#components";
import { useApi } from "~/lib/auth.js";
import dialog from "primevue/dialog";
import button from "primevue/button";
import { t as _plugin_vue_export_helper_t } from "~/lib/_plugin-vue_export-helper.js";
import message from "primevue/message";
import inputtext from "primevue/inputtext";
import datatable from "primevue/datatable";
import paginator from "primevue/paginator";
import checkbox from "primevue/checkbox";
import column from "primevue/column";
import textarea from "primevue/textarea";
function D() {
let e = useApi(),
t = ref([]),
r = ref(0),
a = ref(1),
o = ref(!1),
s = ref(!1),
l = ref(!1),
u = ref(!1),
d = ref(``),
f = ref(``),
p = ref(``),
m = ref(null),
h = ref(null),
g = reactive({
enabled: !1,
ip: ``,
}),
_ = ref(null),
v = !0,
y = 0,
b = () => {
m.value = null;
};
onBeforeUnmount(() => {
((v = !1), y++, b());
});
async function x() {
if (!v) return;
let n = ++y;
((o.value = !0), (d.value = ``), (u.value = !1));
try {
let i = await e.get(`/api`, {
page: a.value,
limit: 20,
orderby: `id`,
sort: `desc`,
});
if (!v || n !== y) return;
if (!Array.isArray(i?.list)) throw Error(`密钥列表响应异常,请重试`);
((t.value = i.list),
(r.value = Number(i.count) || 0),
(u.value = Number(i.create_api) === 1),
(l.value = !0));
} catch (e) {
v &&
n === y &&
((d.value = e instanceof Error ? e.message : `加载失败`),
(l.value = !1));
} finally {
v && n === y && (o.value = !1);
}
}
async function C() {
if (!(!v || s.value || m.value)) {
if (((d.value = ``), (f.value = ``), !l.value || o.value)) {
d.value = `权限尚未加载,请刷新列表`;
return;
}
if (!u.value) {
d.value = `当前账户暂未开放 API 密钥创建`;
return;
}
if (!p.value.trim()) {
d.value = `请填写密钥名称`;
return;
}
s.value = !0;
try {
let t = await e.post(`/api`, {
name: p.value.trim(),
});
if (!v) return;
if (!t?.private_key || !t?.token)
throw Error(
`服务端未返回完整密钥,请刷新列表核实创建结果,避免重复创建`,
);
((m.value = t),
(p.value = ``),
(f.value = `密钥已创建,请立即保存私钥。关闭后无法再次查看。`),
(a.value = 1),
await x());
} catch (e) {
v &&
(d.value = `${e instanceof Error ? e.message : `创建失败`}。请先刷新列表核实结果,再决定是否重试。`);
} finally {
v && (s.value = !1);
}
}
}
function w(e) {
s.value ||
((d.value = ``),
(f.value = ``),
(h.value = e.id),
(g.enabled = Number(e.status) === 1),
(g.ip = e.ip || ``));
}
async function T() {
if (!v || s.value || !h.value) return;
if (((d.value = ``), (f.value = ``), g.enabled && !g.ip.trim())) {
d.value = `开启白名单时请填写 IP 地址`;
return;
}
let t = h.value;
s.value = !0;
try {
if (
(await e.put(`/api/${t}/white_list`, {
status: +!!g.enabled,
ip: g.ip.trim(),
}),
!v)
)
return;
((h.value = null), (f.value = `白名单设置已保存`), await x());
} catch (e) {
v && (d.value = e instanceof Error ? e.message : `保存失败`);
} finally {
v && (s.value = !1);
}
}
async function E() {
if (v && !s.value && _.value?.id) {
((d.value = ``), (f.value = ``), (s.value = !0));
try {
if ((await e.del(`/api/${_.value.id}`), !v)) return;
((_.value = null),
(f.value = `密钥已删除`),
t.value.length === 1 && a.value > 1 && a.value--,
await x());
} catch (e) {
v && (d.value = e instanceof Error ? e.message : `删除失败`);
} finally {
v && (s.value = !1);
}
}
}
return {
rows: t,
count: r,
page: a,
limit: 20,
loading: o,
busy: s,
loaded: l,
createAllowed: u,
error: d,
success: f,
name: p,
secret: m,
clearSecret: b,
whitelistId: h,
whitelist: g,
deleteTarget: _,
load: x,
create: C,
editWhitelist: w,
saveWhitelist: T,
remove: E,
};
}
var O = {
class: `api-page account-management-page`,
},
k = {
class: `account-management-head`,
},
A = {
class: `account-management-actions`,
},
j = {
class: `create-key-field`,
},
oe = {
key: 2,
class: `muted`,
},
se = {
class: `list-table`,
},
ce = {
class: `token`,
},
le = {
class: `row-actions`,
},
ue = {
class: `token`,
},
de = {
key: 0,
},
M = _plugin_vue_export_helper_t(
defineComponent({
__name: `api-keys`,
setup(n) {
useHead({
title: `API 密钥`,
});
let {
rows: c,
count: h,
page: S,
limit: T,
loading: M,
busy: N,
loaded: P,
createAllowed: F,
error: I,
success: L,
name: R,
secret: z,
clearSecret: B,
whitelistId: V,
whitelist: H,
deleteTarget: U,
load: W,
create: G,
editWhitelist: fe,
saveWhitelist: K,
remove: pe,
} = D(),
q = ref(!1),
J = ref(``),
me = computed(() => !!z.value),
Y = computed({
get: () => V.value !== null,
set: (e) => {
!e && !N.value && (V.value = null);
},
}),
X = computed({
get: () => !!U.value,
set: (e) => {
!e && !N.value && (U.value = null);
},
});
async function he() {
if (z.value) {
J.value = ``;
try {
(await navigator.clipboard.writeText(z.value.private_key),
(q.value = !0));
} catch {
J.value = `复制失败,请手动选择并复制私钥`;
}
}
}
function Z() {
(B(), (q.value = !1), (J.value = ``));
}
function ge(e) {
((S.value = e.page + 1), W());
}
let _e = (e) => (e ? new Date(e * 1e3).toLocaleString(`zh-CN`) : `—`);
return (
onMounted(W),
onBeforeRouteLeave(
() =>
!z.value ||
window.confirm(
`私钥仅显示一次,请确认已保存后离开。离开后将无法再次查看。`,
),
),
(t, n) => {
let i = NuxtLink,
s = button,
y = message,
b = inputtext,
D = column,
B = datatable,
V = paginator,
Q = textarea,
$ = dialog,
ve = checkbox;
return (
openBlock(),
createElementBlock(`section`, O, [
createElementVNode(`header`, k, [
createElementVNode(`div`, null, [
(n[10] ||= createElementVNode(`h2`, null, `API 密钥`, -1)),
createElementVNode(`p`, null, [
(n[9] ||= createTextVNode(
`管理程序访问凭证及 IP 白名单。`,
-1,
)),
createVNode(
i,
{
to: `/logbook?type=api`,
},
{
default: withCtx(() => [
...(n[8] ||= [
createTextVNode(`查看 API 日志`, -1),
]),
]),
_: 1,
},
),
]),
]),
createElementVNode(`div`, A, [
createVNode(
i,
{
to: `/account`,
class: `account-management-link`,
},
{
default: withCtx(() => [
...(n[11] ||= [
createElementVNode(
`i`,
{
class: `pi pi-angle-left`,
"aria-hidden": `true`,
},
null,
-1,
),
createTextVNode(`账户设置`, -1),
]),
]),
_: 1,
},
),
createVNode(
s,
{
label: `刷新`,
icon: `pi pi-refresh`,
severity: `secondary`,
outlined: ``,
loading: unref(M),
disabled: unref(N),
onClick: unref(W),
},
null,
8,
[`loading`, `disabled`, `onClick`],
),
]),
]),
unref(I)
? (openBlock(),
createBlock(
y,
{
key: 0,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(I)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
unref(L)
? (openBlock(),
createBlock(
y,
{
key: 1,
severity: `success`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(L)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
createElementVNode(
`form`,
{
class: `create-key`,
onSubmit: (n[1] ||= withModifiers(
(...e) => unref(G) && unref(G)(...e),
[`prevent`],
)),
},
[
createElementVNode(`div`, j, [
(n[12] ||= createElementVNode(
`label`,
{
for: `api-name`,
},
`密钥名称`,
-1,
)),
createVNode(
b,
{
id: `api-name`,
modelValue: unref(R),
"onUpdate:modelValue": (n[0] ||= (e) =>
isRef(R) ? (R.value = e) : null),
maxlength: `100`,
placeholder: `例如:自动化管理`,
disabled: unref(N) || !unref(F),
},
null,
8,
[`modelValue`, `disabled`],
),
]),
createVNode(
s,
{
type: `submit`,
label: `创建密钥`,
loading: unref(N),
disabled:
!unref(P) || !unref(F) || unref(M) || !!unref(z),
},
null,
8,
[`loading`, `disabled`],
),
],
32,
),
unref(P) && !unref(F)
? (openBlock(),
createElementBlock(`p`, oe, `当前账户暂未开放创建密钥。`))
: createCommentVNode(``, !0),
createElementVNode(`div`, se, [
createVNode(
B,
{
value: unref(c),
loading: unref(M),
"data-key": `id`,
scrollable: ``,
},
{
empty: withCtx(() => [
createTextVNode(
toDisplayString(
unref(P)
? `暂无 API 密钥`
: `尚未加载密钥,请刷新重试`,
),
1,
),
]),
default: withCtx(() => [
createVNode(D, {
field: `name`,
header: `名称`,
}),
createVNode(
D,
{
field: `token`,
header: `Token`,
},
{
body: withCtx(({ data: t }) => [
createElementVNode(
`code`,
ce,
toDisplayString(t.token),
1,
),
]),
_: 1,
},
),
createVNode(
D,
{
header: `创建时间`,
},
{
body: withCtx(({ data: t }) => [
createTextVNode(
toDisplayString(_e(t.create_time)),
1,
),
]),
_: 1,
},
),
createVNode(
D,
{
header: `IP 白名单`,
},
{
body: withCtx(({ data: t }) => [
createTextVNode(
toDisplayString(
Number(t.status) === 1 ? t.ip : `未开启`,
),
1,
),
]),
_: 1,
},
),
createVNode(
D,
{
header: `操作`,
},
{
body: withCtx(({ data: e }) => [
createElementVNode(`div`, le, [
createVNode(
s,
{
label: `白名单`,
text: ``,
disabled: unref(N),
onClick: (t) => unref(fe)(e),
},
null,
8,
[`disabled`, `onClick`],
),
createVNode(
s,
{
label: `删除`,
severity: `danger`,
text: ``,
disabled: unref(N),
onClick: (t) => (U.value = e),
},
null,
8,
[`disabled`, `onClick`],
),
]),
]),
_: 1,
},
),
]),
_: 1,
},
8,
[`value`, `loading`],
),
]),
unref(h) > unref(T)
? (openBlock(),
createBlock(
V,
{
key: 3,
first: (unref(S) - 1) * unref(T),
rows: unref(T),
"total-records": unref(h),
onPage: ge,
},
null,
8,
[`first`, `rows`, `total-records`],
))
: createCommentVNode(``, !0),
createVNode(
$,
{
visible: unref(me),
header: `保存新私钥`,
modal: ``,
closable: !1,
draggable: !1,
style: {
width: `600px`,
maxWidth: `94vw`,
},
},
{
footer: withCtx(() => [
createVNode(
s,
{
label: unref(q) ? `已复制` : `复制私钥`,
severity: `secondary`,
onClick: he,
},
null,
8,
[`label`],
),
createVNode(s, {
label: `已安全保存,关闭`,
onClick: Z,
}),
]),
default: withCtx(() => [
(n[16] ||= createElementVNode(
`p`,
null,
`私钥仅显示一次。请保存到安全位置后关闭此窗口。`,
-1,
)),
unref(z)
? (openBlock(),
createElementBlock(
Fragment,
{
key: 0,
},
[
createElementVNode(`p`, null, [
(n[13] ||= createElementVNode(
`strong`,
null,
`Token:`,
-1,
)),
createElementVNode(
`code`,
ue,
toDisplayString(unref(z).token),
1,
),
]),
unref(z).api_url
? (openBlock(),
createElementBlock(`p`, de, [
(n[14] ||= createElementVNode(
`strong`,
null,
`API 地址:`,
-1,
)),
createTextVNode(
toDisplayString(unref(z).api_url),
1,
),
]))
: createCommentVNode(``, !0),
(n[15] ||= createElementVNode(
`label`,
{
for: `private-key`,
},
`私钥`,
-1,
)),
createVNode(
Q,
{
id: `private-key`,
"model-value": unref(z).private_key,
readonly: ``,
rows: `8`,
fluid: ``,
},
null,
8,
[`model-value`],
),
],
64,
))
: createCommentVNode(``, !0),
unref(J)
? (openBlock(),
createBlock(
y,
{
key: 1,
severity: `error`,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(J)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
]),
_: 1,
},
8,
[`visible`],
),
createVNode(
$,
{
visible: unref(Y),
"onUpdate:visible": (n[5] ||= (e) =>
isRef(Y) ? (Y.value = e) : null),
header: `API 白名单`,
modal: ``,
closable: !unref(N),
draggable: !1,
style: {
width: `480px`,
maxWidth: `94vw`,
},
},
{
default: withCtx(() => [
createElementVNode(
`form`,
{
class: `whitelist-form`,
onSubmit: (n[4] ||= withModifiers(
(...e) => unref(K) && unref(K)(...e),
[`prevent`],
)),
},
[
createElementVNode(`div`, null, [
createVNode(
ve,
{
modelValue: unref(H).enabled,
"onUpdate:modelValue": (n[2] ||= (e) =>
(unref(H).enabled = e)),
"input-id": `api-whitelist-on`,
binary: ``,
disabled: unref(N),
},
null,
8,
[`modelValue`, `disabled`],
),
(n[17] ||= createTextVNode()),
(n[18] ||= createElementVNode(
`label`,
{
for: `api-whitelist-on`,
},
`启用 IP 白名单`,
-1,
)),
]),
(n[19] ||= createElementVNode(
`label`,
{
for: `api-whitelist-ip`,
},
`允许访问的 IP 地址`,
-1,
)),
createVNode(
Q,
{
id: `api-whitelist-ip`,
modelValue: unref(H).ip,
"onUpdate:modelValue": (n[3] ||= (e) =>
(unref(H).ip = e)),
disabled: unref(N) || !unref(H).enabled,
rows: `4`,
fluid: ``,
},
null,
8,
[`modelValue`, `disabled`],
),
unref(I)
? (openBlock(),
createBlock(
y,
{
key: 0,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(
toDisplayString(unref(I)),
1,
),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
createVNode(
s,
{
type: `submit`,
label: `保存`,
loading: unref(N),
},
null,
8,
[`loading`],
),
],
32,
),
]),
_: 1,
},
8,
[`visible`, `closable`],
),
createVNode(
$,
{
visible: unref(X),
"onUpdate:visible": (n[7] ||= (e) =>
isRef(X) ? (X.value = e) : null),
header: `删除 API 密钥`,
modal: ``,
closable: !unref(N),
draggable: !1,
style: {
width: `450px`,
maxWidth: `94vw`,
},
},
{
footer: withCtx(() => [
createVNode(
s,
{
label: `取消`,
severity: `secondary`,
disabled: unref(N),
onClick: (n[6] ||= (e) => (U.value = null)),
},
null,
8,
[`disabled`],
),
createVNode(
s,
{
label: `确认删除`,
severity: `danger`,
loading: unref(N),
onClick: unref(pe),
},
null,
8,
[`loading`, `onClick`],
),
]),
default: withCtx(() => [
createElementVNode(
`p`,
null,
`确认删除「` +
toDisplayString(unref(U)?.name) +
`」?使用此密钥的程序将立即失去访问权限。`,
1,
),
unref(I)
? (openBlock(),
createBlock(
y,
{
key: 0,
severity: `error`,
closable: !1,
},
{
default: withCtx(() => [
createTextVNode(toDisplayString(unref(I)), 1),
]),
_: 1,
},
))
: createCommentVNode(``, !0),
]),
_: 1,
},
8,
[`visible`, `closable`],
),
])
);
}
);
},
}),
[[`__scopeId`, `data-v-76e29360`]],
);
export {};
export default M;
</script>