This commit is contained in:
fengchuanhn@gmail.com
2026-05-22 16:25:19 +08:00
parent c8d7d3e8f3
commit a2ff5b065e
4 changed files with 37 additions and 99 deletions

View File

@@ -160,19 +160,17 @@ pub async fn send_heartbeat(token: &str) -> Result<(), String> {
let server_code = response_server_verify_code(&value);
if server_code != Some(expected.as_str()) {
return Err("会员已过期".into());
}
if let Some(ok) = value.get("ok").and_then(|v| v.as_bool()) {
if !ok {
if value.get("ok").and_then(|v| v.as_bool()) == Some(false) {
let msg = value
.get("message")
.and_then(|m| m.as_str())
.unwrap_or("心跳校验失败");
return Err(msg.to_string());
}
}
Ok(())
}

View File

@@ -25,7 +25,7 @@ function oemRequest(token, path, options = {}) {
* roleId?: number | null,
* }} [params]
*/
export function listAgentUsersApi(
export function listOemUsersApi(
token,
{ page = 1, pageSize = 20, username, oemId, agentId, roleId } = {},
) {

View File

@@ -7,7 +7,7 @@ import {
updateAdminCardKeyApi,
deleteAdminCardKeyApi,
} from "../../api/oemCardKeys.js";
import { listAgentUsersApi } from "../../api/oemUsers.js";
import { listOemUsersApi } from "../../api/oemUsers.js";
const auth = useAuthStore();
@@ -93,7 +93,7 @@ function showMessage(severity, message) {
async function loadFilterOptions() {
const [ agentRes] = await Promise.all([
listAgentUsersApi(auth.token, { page: 1, pageSize: 200, roleId: ROLE_AGENT }),
listOemUsersApi(auth.token, { page: 1, pageSize: 200, roleId: ROLE_AGENT }),
]);
if (agentRes.ok && Array.isArray(agentRes.data?.items)) {
@@ -304,16 +304,7 @@ onMounted(async () => {
class="admin-users__search"
@keyup.enter="applyFilters"
/>
<Select
v-model="filters.oem_id"
:options="oemOptions"
option-label="username"
option-value="id"
placeholder="全部 OEM"
show-clear
filter
class="admin-users__filter-select"
/>
<Select
v-model="filters.agent_id"
:options="agentOptions"
@@ -368,11 +359,7 @@ onMounted(async () => {
</template>
</Column>
<Column field="duration_days" header="时长(天)" style="width: 6rem" />
<Column header="OEM" style="width: 7rem">
<template #body="{ data }">
{{ ownerLabel(data.oem_id) }}
</template>
</Column>
<Column header="代理" style="width: 7rem">
<template #body="{ data }">
{{ ownerLabel(data.agent_id) }}
@@ -400,7 +387,7 @@ onMounted(async () => {
</Column>
<Column field="remark" header="备注">
<template #body="{ data }">
{{ data.remark || "—" }}
{{ data.oem_remark || "—" }}
</template>
</Column>
<Column header="操作" style="width: 9rem">
@@ -437,10 +424,7 @@ onMounted(async () => {
>
<div class="flex flex-col gap-4">
<template v-if="dialogMode === 'create'">
<div class="flex flex-col gap-2">
<label class="text-xs text-text-muted uppercase">时长</label>
<InputNumber v-model="form.duration_days" :min="1" :max="3650" class="w-full" />
</div>
<div class="flex flex-col gap-2">
<label class="text-xs text-text-muted uppercase">生成数量</label>
<InputNumber v-model="form.count" :min="1" :max="100" class="w-full" />
@@ -488,16 +472,7 @@ onMounted(async () => {
disabled
/>
</div>
<div class="flex flex-col gap-2">
<label class="text-xs text-text-muted uppercase">时长</label>
<InputNumber
v-model="form.duration_days"
:min="1"
:max="3650"
class="w-full"
:disabled="isActivated"
/>
</div>
</template>
<div class="flex flex-col gap-2">

View File

@@ -2,7 +2,7 @@
import { computed, onMounted, ref } from "vue";
import { useAuthStore, ROLE_ADMIN, ROLE_AGENT,ROLE_OEM } from "../../stores/auth.js";
import {
listAgentUsersApi,
listOemUsersApi,
createOemUserApi,
updateOemUserApi,
deleteOemUserApi,
@@ -10,11 +10,10 @@ import {
const auth = useAuthStore();
const ROLE_OPTIONS = [
/** 新建/编辑时可分配的角色(仅普通用户、代理) */
const FORM_ROLE_OPTIONS = [
{ label: "普通用户", value: 0 },
{ label: "管理员", value: 1 },
{ label: "代理", value: 2 },
{ label: "OEM", value: 3 },
];
const ROLE_LABELS = {
@@ -49,8 +48,6 @@ const emptyForm = () => ({
password: "",
phone: "",
role_id: 0,
vip_end_time: "",
clear_vip_end_time: false,
});
const form = ref(emptyForm());
@@ -66,14 +63,6 @@ function formatDateTime(value) {
return d.toLocaleString("zh-CN", { hour12: false });
}
function toDatetimeLocalValue(iso) {
if (!iso) return "";
const d = new Date(iso);
if (Number.isNaN(d.getTime())) return "";
const pad = (n) => String(n).padStart(2, "0");
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
}
function roleLabel(roleId) {
return ROLE_LABELS[roleId] ?? `角色 ${roleId}`;
}
@@ -104,7 +93,7 @@ function showMessage(severity, message) {
async function loadFilterOptions() {
const [ agentRes] = await Promise.all([
listAgentUsersApi(auth.token, { page: 1, pageSize: 200, roleId: ROLE_AGENT }),
listOemUsersApi(auth.token, { page: 1, pageSize: 200, roleId: ROLE_AGENT }),
]);
if (agentRes.ok && Array.isArray(agentRes.data?.items)) {
@@ -115,27 +104,25 @@ async function loadFilterOptions() {
async function loadUsers() {
loading.value = true;
feedback.value = { severity: "", message: "" };
// const res = await listOemUsersApi(auth.token, {
// page: page.value,
// pageSize: pageSize.value,
// username: filters.value.username,
// oemId: filters.value.oem_id,
// agentId: filters.value.agent_id,
// });
// loading.value = false;
const res = await listOemUsersApi(auth.token, {
page: page.value,
pageSize: pageSize.value,
username: filters.value.username,
oemId: filters.value.oem_id,
agentId: filters.value.agent_id,
});
loading.value = false;
// if (!res.ok) {
// showMessage("error", res.message || "加载用户列表失败");
// return;
// }
if (!res.ok) {
showMessage("error", res.message || "加载用户列表失败");
return;
}
// const data = res.data;
// users.value = Array.isArray(data?.items) ? data.items : [];
// total.value = typeof data?.total === "number" ? data.total : 0;
users.value=[];
total.value=0;
// if (typeof data?.page === "number") page.value = data.page;
// if (typeof data?.page_size === "number") pageSize.value = data.page_size;
const data = res.data;
users.value = Array.isArray(data?.items) ? data.items : [];
total.value = typeof data?.total === "number" ? data.total : 0;
if (typeof data?.page === "number") page.value = data.page;
if (typeof data?.page_size === "number") pageSize.value = data.page_size;
}
async function onPage(event) {
@@ -170,8 +157,6 @@ function openEditDialog(row) {
password: "",
phone: row.phone || "",
role_id: row.role_id,
vip_end_time: toDatetimeLocalValue(row.vip_end_time),
clear_vip_end_time: false,
};
dialogVisible.value = true;
}
@@ -187,12 +172,6 @@ function buildPayload() {
payload.password = form.value.password;
}
if (form.value.clear_vip_end_time) {
payload.clear_vip_end_time = true;
} else if (form.value.vip_end_time) {
payload.vip_end_time = new Date(form.value.vip_end_time).toISOString();
}
return payload;
}
@@ -415,26 +394,12 @@ onMounted(async () => {
<label class="text-xs text-text-muted uppercase">角色</label>
<Select
v-model="form.role_id"
:options="ROLE_OPTIONS"
:options="FORM_ROLE_OPTIONS"
option-label="label"
option-value="value"
class="w-full"
/>
</div>
<div class="flex flex-col gap-2">
<label class="text-xs text-text-muted uppercase">VIP 到期时间</label>
<InputText
v-model="form.vip_end_time"
type="datetime-local"
class="w-full"
:disabled="form.clear_vip_end_time"
/>
<label v-if="dialogMode === 'edit'" class="flex items-center gap-2 text-sm text-text-muted">
<Checkbox v-model="form.clear_vip_end_time" :binary="true" input-id="clear-vip" />
<span>清除 VIP 到期时间</span>
</label>
</div>
</div>
<template #footer>