1
This commit is contained in:
@@ -160,19 +160,17 @@ pub async fn send_heartbeat(token: &str) -> Result<(), String> {
|
|||||||
|
|
||||||
let server_code = response_server_verify_code(&value);
|
let server_code = response_server_verify_code(&value);
|
||||||
if server_code != Some(expected.as_str()) {
|
if server_code != Some(expected.as_str()) {
|
||||||
|
|
||||||
return Err("会员已过期".into());
|
return Err("会员已过期".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ok) = value.get("ok").and_then(|v| v.as_bool()) {
|
if value.get("ok").and_then(|v| v.as_bool()) == Some(false) {
|
||||||
if !ok {
|
|
||||||
let msg = value
|
let msg = value
|
||||||
.get("message")
|
.get("message")
|
||||||
.and_then(|m| m.as_str())
|
.and_then(|m| m.as_str())
|
||||||
.unwrap_or("心跳校验失败");
|
.unwrap_or("心跳校验失败");
|
||||||
return Err(msg.to_string());
|
return Err(msg.to_string());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function oemRequest(token, path, options = {}) {
|
|||||||
* roleId?: number | null,
|
* roleId?: number | null,
|
||||||
* }} [params]
|
* }} [params]
|
||||||
*/
|
*/
|
||||||
export function listAgentUsersApi(
|
export function listOemUsersApi(
|
||||||
token,
|
token,
|
||||||
{ page = 1, pageSize = 20, username, oemId, agentId, roleId } = {},
|
{ page = 1, pageSize = 20, username, oemId, agentId, roleId } = {},
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
updateAdminCardKeyApi,
|
updateAdminCardKeyApi,
|
||||||
deleteAdminCardKeyApi,
|
deleteAdminCardKeyApi,
|
||||||
} from "../../api/oemCardKeys.js";
|
} from "../../api/oemCardKeys.js";
|
||||||
import { listAgentUsersApi } from "../../api/oemUsers.js";
|
import { listOemUsersApi } from "../../api/oemUsers.js";
|
||||||
|
|
||||||
const auth = useAuthStore();
|
const auth = useAuthStore();
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ function showMessage(severity, message) {
|
|||||||
async function loadFilterOptions() {
|
async function loadFilterOptions() {
|
||||||
const [ agentRes] = await Promise.all([
|
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)) {
|
if (agentRes.ok && Array.isArray(agentRes.data?.items)) {
|
||||||
@@ -304,16 +304,7 @@ onMounted(async () => {
|
|||||||
class="admin-users__search"
|
class="admin-users__search"
|
||||||
@keyup.enter="applyFilters"
|
@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
|
<Select
|
||||||
v-model="filters.agent_id"
|
v-model="filters.agent_id"
|
||||||
:options="agentOptions"
|
:options="agentOptions"
|
||||||
@@ -368,11 +359,7 @@ onMounted(async () => {
|
|||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column field="duration_days" header="时长(天)" style="width: 6rem" />
|
<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">
|
<Column header="代理" style="width: 7rem">
|
||||||
<template #body="{ data }">
|
<template #body="{ data }">
|
||||||
{{ ownerLabel(data.agent_id) }}
|
{{ ownerLabel(data.agent_id) }}
|
||||||
@@ -400,7 +387,7 @@ onMounted(async () => {
|
|||||||
</Column>
|
</Column>
|
||||||
<Column field="remark" header="备注">
|
<Column field="remark" header="备注">
|
||||||
<template #body="{ data }">
|
<template #body="{ data }">
|
||||||
{{ data.remark || "—" }}
|
{{ data.oem_remark || "—" }}
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
<Column header="操作" style="width: 9rem">
|
<Column header="操作" style="width: 9rem">
|
||||||
@@ -437,10 +424,7 @@ onMounted(async () => {
|
|||||||
>
|
>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<template v-if="dialogMode === 'create'">
|
<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">
|
<div class="flex flex-col gap-2">
|
||||||
<label class="text-xs text-text-muted uppercase">生成数量</label>
|
<label class="text-xs text-text-muted uppercase">生成数量</label>
|
||||||
<InputNumber v-model="form.count" :min="1" :max="100" class="w-full" />
|
<InputNumber v-model="form.count" :min="1" :max="100" class="w-full" />
|
||||||
@@ -488,16 +472,7 @@ onMounted(async () => {
|
|||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
</div>
|
</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>
|
</template>
|
||||||
|
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import { useAuthStore, ROLE_ADMIN, ROLE_AGENT,ROLE_OEM } from "../../stores/auth.js";
|
import { useAuthStore, ROLE_ADMIN, ROLE_AGENT,ROLE_OEM } from "../../stores/auth.js";
|
||||||
import {
|
import {
|
||||||
listAgentUsersApi,
|
listOemUsersApi,
|
||||||
createOemUserApi,
|
createOemUserApi,
|
||||||
updateOemUserApi,
|
updateOemUserApi,
|
||||||
deleteOemUserApi,
|
deleteOemUserApi,
|
||||||
@@ -10,11 +10,10 @@ import {
|
|||||||
|
|
||||||
const auth = useAuthStore();
|
const auth = useAuthStore();
|
||||||
|
|
||||||
const ROLE_OPTIONS = [
|
/** 新建/编辑时可分配的角色(仅普通用户、代理) */
|
||||||
|
const FORM_ROLE_OPTIONS = [
|
||||||
{ label: "普通用户", value: 0 },
|
{ label: "普通用户", value: 0 },
|
||||||
{ label: "管理员", value: 1 },
|
|
||||||
{ label: "代理", value: 2 },
|
{ label: "代理", value: 2 },
|
||||||
{ label: "OEM", value: 3 },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const ROLE_LABELS = {
|
const ROLE_LABELS = {
|
||||||
@@ -49,8 +48,6 @@ const emptyForm = () => ({
|
|||||||
password: "",
|
password: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
role_id: 0,
|
role_id: 0,
|
||||||
vip_end_time: "",
|
|
||||||
clear_vip_end_time: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const form = ref(emptyForm());
|
const form = ref(emptyForm());
|
||||||
@@ -66,14 +63,6 @@ function formatDateTime(value) {
|
|||||||
return d.toLocaleString("zh-CN", { hour12: false });
|
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) {
|
function roleLabel(roleId) {
|
||||||
return ROLE_LABELS[roleId] ?? `角色 ${roleId}`;
|
return ROLE_LABELS[roleId] ?? `角色 ${roleId}`;
|
||||||
}
|
}
|
||||||
@@ -104,7 +93,7 @@ function showMessage(severity, message) {
|
|||||||
async function loadFilterOptions() {
|
async function loadFilterOptions() {
|
||||||
const [ agentRes] = await Promise.all([
|
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)) {
|
if (agentRes.ok && Array.isArray(agentRes.data?.items)) {
|
||||||
@@ -115,27 +104,25 @@ async function loadFilterOptions() {
|
|||||||
async function loadUsers() {
|
async function loadUsers() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
feedback.value = { severity: "", message: "" };
|
feedback.value = { severity: "", message: "" };
|
||||||
// const res = await listOemUsersApi(auth.token, {
|
const res = await listOemUsersApi(auth.token, {
|
||||||
// page: page.value,
|
page: page.value,
|
||||||
// pageSize: pageSize.value,
|
pageSize: pageSize.value,
|
||||||
// username: filters.value.username,
|
username: filters.value.username,
|
||||||
// oemId: filters.value.oem_id,
|
oemId: filters.value.oem_id,
|
||||||
// agentId: filters.value.agent_id,
|
agentId: filters.value.agent_id,
|
||||||
// });
|
});
|
||||||
// loading.value = false;
|
loading.value = false;
|
||||||
|
|
||||||
// if (!res.ok) {
|
if (!res.ok) {
|
||||||
// showMessage("error", res.message || "加载用户列表失败");
|
showMessage("error", res.message || "加载用户列表失败");
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// const data = res.data;
|
const data = res.data;
|
||||||
// users.value = Array.isArray(data?.items) ? data.items : [];
|
users.value = Array.isArray(data?.items) ? data.items : [];
|
||||||
// total.value = typeof data?.total === "number" ? data.total : 0;
|
total.value = typeof data?.total === "number" ? data.total : 0;
|
||||||
users.value=[];
|
if (typeof data?.page === "number") page.value = data.page;
|
||||||
total.value=0;
|
if (typeof data?.page_size === "number") pageSize.value = data.page_size;
|
||||||
// if (typeof data?.page === "number") page.value = data.page;
|
|
||||||
// if (typeof data?.page_size === "number") pageSize.value = data.page_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onPage(event) {
|
async function onPage(event) {
|
||||||
@@ -170,8 +157,6 @@ function openEditDialog(row) {
|
|||||||
password: "",
|
password: "",
|
||||||
phone: row.phone || "",
|
phone: row.phone || "",
|
||||||
role_id: row.role_id,
|
role_id: row.role_id,
|
||||||
vip_end_time: toDatetimeLocalValue(row.vip_end_time),
|
|
||||||
clear_vip_end_time: false,
|
|
||||||
};
|
};
|
||||||
dialogVisible.value = true;
|
dialogVisible.value = true;
|
||||||
}
|
}
|
||||||
@@ -187,12 +172,6 @@ function buildPayload() {
|
|||||||
payload.password = form.value.password;
|
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;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,26 +394,12 @@ onMounted(async () => {
|
|||||||
<label class="text-xs text-text-muted uppercase">角色</label>
|
<label class="text-xs text-text-muted uppercase">角色</label>
|
||||||
<Select
|
<Select
|
||||||
v-model="form.role_id"
|
v-model="form.role_id"
|
||||||
:options="ROLE_OPTIONS"
|
:options="FORM_ROLE_OPTIONS"
|
||||||
option-label="label"
|
option-label="label"
|
||||||
option-value="value"
|
option-value="value"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
|||||||
Reference in New Issue
Block a user