修复补号功能
This commit is contained in:
@@ -54,6 +54,8 @@ function normalizeRow(raw) {
|
||||
const p = (v) => String(v).padStart(2, '0');
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
||||
};
|
||||
const st = Number(pick('is_extracted', 'isExtracted', 'IsExtracted'));
|
||||
const extractStatus = Number.isFinite(st) ? st : 0;
|
||||
return {
|
||||
id: pick('id', 'Id', 'ID'),
|
||||
type: pick('data_type', 'dataType', 'type'),
|
||||
@@ -61,7 +63,8 @@ function normalizeRow(raw) {
|
||||
password: pick('password', 'Password'),
|
||||
token: pick('token', 'Token'),
|
||||
remark: pick('remark', 'Remark'),
|
||||
extracted: Number(pick('is_extracted', 'isExtracted', 'IsExtracted')) === 1,
|
||||
extractStatus,
|
||||
extracted: extractStatus !== 0,
|
||||
extractedAt: formatTime(pickNullable('extracted_time', 'extractedAt')),
|
||||
extractedPlatform: pickNullable('extracted_platform', 'extractedPlatform'),
|
||||
createdAt: formatTime(pick('create_time', 'createdAt')),
|
||||
|
||||
@@ -100,7 +100,9 @@ function copyToken() {
|
||||
<span class="token-text">{{ row.token || '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="提取状态">
|
||||
{{ row.extracted ? '已提取' : '未提取' }}
|
||||
{{
|
||||
row.extractStatus === 2 ? '补号' : row.extracted ? '已提取' : '未提取'
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="提取时间">{{ row.extractedAt || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="提取平台">
|
||||
|
||||
@@ -20,13 +20,23 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
replenish: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
platformMap: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'update:platform', 'update:remark', 'confirm']);
|
||||
const emit = defineEmits([
|
||||
'update:modelValue',
|
||||
'update:platform',
|
||||
'update:remark',
|
||||
'update:replenish',
|
||||
'confirm',
|
||||
]);
|
||||
|
||||
function typeText(type) {
|
||||
if (type === 'account') return '账号密码';
|
||||
@@ -47,6 +57,14 @@ function typeText(type) {
|
||||
<el-form-item label="提取类型">
|
||||
<el-input :model-value="typeText(type)" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否补号">
|
||||
<el-switch
|
||||
:model-value="replenish"
|
||||
active-text="是"
|
||||
inactive-text="否"
|
||||
@update:model-value="(v) => emit('update:replenish', v)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="提取平台">
|
||||
<el-select
|
||||
:model-value="platform"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, onUnmounted, reactive, ref, watch } from "vue";
|
||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref, watch } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import Edit from "./components/edit.vue";
|
||||
import DetailDialog from "./components/detail.vue";
|
||||
@@ -40,6 +40,7 @@ const extractForm = reactive({
|
||||
platform: "local",
|
||||
type: "account",
|
||||
remark: "",
|
||||
replenish: false,
|
||||
});
|
||||
|
||||
const tableData = ref([]);
|
||||
@@ -54,6 +55,9 @@ const pagination = reactive({
|
||||
pageSize: 20,
|
||||
});
|
||||
|
||||
/** 跳转未提取末页时跳过 watcher,避免先被重置到第 1 页 */
|
||||
const skipWatchFetchDuringUnusedJump = ref(false);
|
||||
|
||||
const pagedList = computed(() => tableData.value);
|
||||
|
||||
function resetQuery() {
|
||||
@@ -73,6 +77,7 @@ const typeTabs = computed(() => {
|
||||
watch(
|
||||
() => [query.keyword, query.status, activeTypeTab.value],
|
||||
() => {
|
||||
if (skipWatchFetchDuringUnusedJump.value) return;
|
||||
pagination.page = 1;
|
||||
fetchList();
|
||||
},
|
||||
@@ -81,6 +86,7 @@ watch(
|
||||
watch(
|
||||
() => [pagination.page, pagination.pageSize],
|
||||
() => {
|
||||
if (skipWatchFetchDuringUnusedJump.value) return;
|
||||
fetchList();
|
||||
},
|
||||
);
|
||||
@@ -142,6 +148,7 @@ function openExtractDialog() {
|
||||
extractTargetRow.value = null;
|
||||
extractForm.platform = "local";
|
||||
extractForm.type = "account";
|
||||
extractForm.replenish = false;
|
||||
extractVisible.value = true;
|
||||
}
|
||||
|
||||
@@ -150,6 +157,7 @@ function openExtractByRow(row) {
|
||||
extractForm.platform = "local";
|
||||
extractForm.type = row.type;
|
||||
extractForm.remark = row.remark || "";
|
||||
extractForm.replenish = false;
|
||||
extractVisible.value = true;
|
||||
}
|
||||
|
||||
@@ -165,6 +173,14 @@ function buildCopyTextByRow(row) {
|
||||
return parts.join('\n');
|
||||
}
|
||||
|
||||
function rowToText(row) {
|
||||
const parts = [];
|
||||
if (row?.account) parts.push(row.account);
|
||||
if (row?.password) parts.push(row.password);
|
||||
if (row?.token) parts.push(row.token);
|
||||
return parts.join(' / ');
|
||||
}
|
||||
|
||||
async function copyToClipboard(text) {
|
||||
if (!text) {
|
||||
ElMessage.warning('无可复制内容');
|
||||
@@ -193,6 +209,7 @@ async function handleExtract() {
|
||||
type: target.type,
|
||||
platform: extractForm.platform,
|
||||
remark: extractForm.remark || "",
|
||||
replenish: !!extractForm.replenish,
|
||||
});
|
||||
if (res?.code !== 200) {
|
||||
ElMessage.error(res?.msg || "提取失败");
|
||||
@@ -270,12 +287,46 @@ async function handleBatchExtract() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleReplenish() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await replenishAccountPool(moduleKey, {
|
||||
type: replenishForm.type,
|
||||
platform: replenishForm.platform,
|
||||
remark: replenishForm.remark || "",
|
||||
});
|
||||
if (res?.code !== 200) {
|
||||
ElMessage.error(res?.msg || "补号失败");
|
||||
return;
|
||||
}
|
||||
ElMessage.success("补号成功,已复制到剪贴板");
|
||||
replenishVisible.value = false;
|
||||
const row = normalizeRow(res.data || {});
|
||||
navigator.clipboard.writeText(rowToText(row)).catch(() => {});
|
||||
await fetchList();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function typeText(type) {
|
||||
if (type === "account") return "账号密码";
|
||||
if (type === "account_tk") return "账号密码+Token";
|
||||
return "Token";
|
||||
}
|
||||
|
||||
function extractStatusLabel(row) {
|
||||
if (row?.extractStatus === 2) return "补号";
|
||||
if (row?.extracted) return "已提取";
|
||||
return "未提取";
|
||||
}
|
||||
|
||||
function extractStatusTagType(row) {
|
||||
if (row?.extractStatus === 2) return "warning";
|
||||
if (row?.extracted) return "success";
|
||||
return "info";
|
||||
}
|
||||
|
||||
const tooltipOpts = {
|
||||
popperClass: 'pool-tooltip',
|
||||
popperStyle: { maxWidth: '600px', wordBreak: 'break-all', whiteSpace: 'pre-wrap' },
|
||||
@@ -318,6 +369,8 @@ function normalizeRow(raw) {
|
||||
const p = (v) => String(v).padStart(2, "0");
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
||||
};
|
||||
const st = Number(pick("is_extracted", "isExtracted", "IsExtracted"));
|
||||
const extractStatus = Number.isFinite(st) ? st : 0;
|
||||
return {
|
||||
id: pick("id", "Id", "ID"),
|
||||
type: pick("data_type", "dataType", "type"),
|
||||
@@ -325,7 +378,8 @@ function normalizeRow(raw) {
|
||||
password: pick("password", "Password"),
|
||||
token: pick("token", "Token"),
|
||||
remark: pick("remark", "Remark"),
|
||||
extracted: Number(pick("is_extracted", "isExtracted", "IsExtracted")) === 1,
|
||||
extractStatus,
|
||||
extracted: extractStatus !== 0,
|
||||
extractedAt: formatTime(pickNullable("extracted_time", "extractedAt")),
|
||||
extractedPlatform: pickNullable("extracted_platform", "extractedPlatform"),
|
||||
createdAt: formatTime(pick("create_time", "createdAt")),
|
||||
@@ -354,6 +408,35 @@ async function fetchList() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 筛选「未提取」并翻到该条件下的最后一页(当前关键词、账号类型 tab 不变) */
|
||||
async function jumpToLastUnusedPage() {
|
||||
const type = activeTypeTab.value === "all" ? undefined : activeTypeTab.value;
|
||||
const res = await getAccountPoolList(moduleKey, {
|
||||
page: 1,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: query.keyword || undefined,
|
||||
status: "unused",
|
||||
type,
|
||||
});
|
||||
if (res?.code !== 200) {
|
||||
ElMessage.error(res?.msg || "获取列表失败");
|
||||
return;
|
||||
}
|
||||
const cnt = Number(res?.data?.total || 0);
|
||||
if (cnt === 0) {
|
||||
ElMessage.warning("暂无未提取数据");
|
||||
return;
|
||||
}
|
||||
const lastPage = Math.max(1, Math.ceil(cnt / pagination.pageSize));
|
||||
skipWatchFetchDuringUnusedJump.value = true;
|
||||
pagination.page = lastPage;
|
||||
query.status = "unused";
|
||||
await nextTick();
|
||||
skipWatchFetchDuringUnusedJump.value = false;
|
||||
await fetchList();
|
||||
ElMessage.success(`已跳转未提取第 ${lastPage} 页(共 ${cnt} 条)`);
|
||||
}
|
||||
|
||||
function updateDeviceType() {
|
||||
isMobile.value = window.innerWidth <= 768;
|
||||
}
|
||||
@@ -470,6 +553,14 @@ function copyCardInfo(row) {
|
||||
<el-option label="未提取" value="unused" />
|
||||
<el-option label="已提取" value="extracted" />
|
||||
</el-select>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
title="按当前搜索与账号类型,筛选未提取并跳到最后一页"
|
||||
@click="jumpToLastUnusedPage"
|
||||
>
|
||||
未提取末页
|
||||
</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
@@ -517,8 +608,8 @@ function copyCardInfo(row) {
|
||||
<el-table-column prop="remark" label="备注" min-width="140" show-overflow-tooltip :tooltip-options="tooltipOpts" />
|
||||
<el-table-column label="提取状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.extracted ? 'success' : 'info'">
|
||||
{{ row.extracted ? "已提取" : "未提取" }}
|
||||
<el-tag :type="extractStatusTagType(row)">
|
||||
{{ extractStatusLabel(row) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -541,9 +632,9 @@ function copyCardInfo(row) {
|
||||
>详情</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="!row.extractedAt && !row.extracted"
|
||||
link
|
||||
type="warning"
|
||||
:disabled="row.extracted"
|
||||
@click="openExtractByRow(row)"
|
||||
>提取</el-button
|
||||
>
|
||||
@@ -586,9 +677,11 @@ function copyCardInfo(row) {
|
||||
:type="extractForm.type"
|
||||
:platform="extractForm.platform"
|
||||
:remark="extractForm.remark"
|
||||
:replenish="extractForm.replenish"
|
||||
:platform-map="PLATFORM_MAP"
|
||||
@update:platform="(v) => (extractForm.platform = v)"
|
||||
@update:remark="(v) => (extractForm.remark = v)"
|
||||
@update:replenish="(v) => (extractForm.replenish = v)"
|
||||
@confirm="handleExtract"
|
||||
/>
|
||||
|
||||
|
||||
@@ -90,7 +90,9 @@ function copyToken() {
|
||||
<el-descriptions-item label="Token">
|
||||
<span class="token-text">{{ row.token || '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="提取状态">{{ row.extracted ? '已提取' : '未提取' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="提取状态">{{
|
||||
row.extractStatus === 2 ? '补号' : row.extracted ? '已提取' : '未提取'
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="提取时间">{{ row.extractedAt || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="提取平台">
|
||||
<el-tag v-if="row.extractedPlatform" :type="platformType" size="small">{{ platformLabel }}</el-tag>
|
||||
|
||||
@@ -5,10 +5,17 @@ const props = defineProps({
|
||||
type: { type: String, default: 'account' },
|
||||
platform: { type: String, default: 'local' },
|
||||
remark: { type: String, default: '' },
|
||||
replenish: { type: Boolean, default: false },
|
||||
platformMap: { type: Object, default: () => ({}) },
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'update:platform', 'update:remark', 'confirm']);
|
||||
const emit = defineEmits([
|
||||
'update:modelValue',
|
||||
'update:platform',
|
||||
'update:remark',
|
||||
'update:replenish',
|
||||
'confirm',
|
||||
]);
|
||||
|
||||
function typeText(type) {
|
||||
if (type === 'account') return '账号密码';
|
||||
@@ -29,6 +36,14 @@ function typeText(type) {
|
||||
<el-form-item label="提取类型">
|
||||
<el-input :model-value="typeText(type)" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否补号">
|
||||
<el-switch
|
||||
:model-value="replenish"
|
||||
active-text="是"
|
||||
inactive-text="否"
|
||||
@update:model-value="(v) => emit('update:replenish', v)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="提取平台">
|
||||
<el-select
|
||||
:model-value="platform"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import Edit from './components/edit.vue';
|
||||
import DetailDialog from './components/detail.vue';
|
||||
@@ -34,7 +34,7 @@ const patchVisible = ref(false);
|
||||
const query = reactive({ keyword: "", status: "" });
|
||||
const activeTypeTab = ref("all");
|
||||
|
||||
const extractForm = reactive({ platform: 'local', type: 'account', remark: '' });
|
||||
const extractForm = reactive({ platform: 'local', type: 'account', remark: '', replenish: false });
|
||||
|
||||
const tableData = ref([]);
|
||||
const total = ref(0);
|
||||
@@ -44,6 +44,8 @@ const detailRemarkSaving = ref(false);
|
||||
const isMobile = ref(false);
|
||||
const pagination = reactive({ page: 1, pageSize: 30 });
|
||||
|
||||
const skipWatchFetchDuringUnusedJump = ref(false);
|
||||
|
||||
const pagedList = computed(() => tableData.value);
|
||||
|
||||
function resetQuery() {
|
||||
@@ -61,6 +63,7 @@ const typeTabs = computed(() => [
|
||||
watch(
|
||||
() => [query.keyword, query.status, activeTypeTab.value],
|
||||
() => {
|
||||
if (skipWatchFetchDuringUnusedJump.value) return;
|
||||
pagination.page = 1;
|
||||
fetchList();
|
||||
},
|
||||
@@ -68,6 +71,7 @@ watch(
|
||||
watch(
|
||||
() => [pagination.page, pagination.pageSize],
|
||||
() => {
|
||||
if (skipWatchFetchDuringUnusedJump.value) return;
|
||||
fetchList();
|
||||
},
|
||||
);
|
||||
@@ -124,6 +128,7 @@ function openExtractByRow(row) {
|
||||
extractForm.platform = "local";
|
||||
extractForm.type = row.type;
|
||||
extractForm.remark = row.remark || '';
|
||||
extractForm.replenish = false;
|
||||
extractVisible.value = true;
|
||||
}
|
||||
|
||||
@@ -157,7 +162,11 @@ async function handleExtract() {
|
||||
const target = extractTargetRow.value;
|
||||
if (!target) { ElMessage.warning("未找到提取目标"); return; }
|
||||
const res = await extractAccountPool(moduleKey, {
|
||||
id: target.id, type: target.type, platform: extractForm.platform, remark: extractForm.remark || '',
|
||||
id: target.id,
|
||||
type: target.type,
|
||||
platform: extractForm.platform,
|
||||
remark: extractForm.remark || '',
|
||||
replenish: !!extractForm.replenish,
|
||||
});
|
||||
if (res?.code !== 200) { ElMessage.error(res?.msg || "提取失败"); return; }
|
||||
ElMessage.success("提取成功");
|
||||
@@ -294,6 +303,8 @@ function normalizeRow(raw) {
|
||||
const p = (v) => String(v).padStart(2, "0");
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
||||
};
|
||||
const st = Number(pick("is_extracted", "isExtracted", "IsExtracted"));
|
||||
const extractStatus = Number.isFinite(st) ? st : 0;
|
||||
return {
|
||||
id: pick("id", "Id", "ID"),
|
||||
type: pick("data_type", "dataType", "type"),
|
||||
@@ -301,13 +312,26 @@ function normalizeRow(raw) {
|
||||
password: pick("password", "Password"),
|
||||
token: pick("token", "Token"),
|
||||
remark: pick("remark", "Remark"),
|
||||
extracted: Number(pick("is_extracted", "isExtracted", "IsExtracted")) === 1,
|
||||
extractStatus,
|
||||
extracted: extractStatus !== 0,
|
||||
extractedAt: formatTime(pickNullable("extracted_time", "extractedAt")),
|
||||
extractedPlatform: pickNullable("extracted_platform", "extractedPlatform"),
|
||||
createdAt: formatTime(pick("create_time", "createdAt")),
|
||||
};
|
||||
}
|
||||
|
||||
function extractStatusLabel(row) {
|
||||
if (row?.extractStatus === 2) return "补号";
|
||||
if (row?.extracted) return "已提取";
|
||||
return "未提取";
|
||||
}
|
||||
|
||||
function extractStatusTagType(row) {
|
||||
if (row?.extractStatus === 2) return "warning";
|
||||
if (row?.extracted) return "success";
|
||||
return "info";
|
||||
}
|
||||
|
||||
async function fetchList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -330,6 +354,34 @@ async function fetchList() {
|
||||
}
|
||||
}
|
||||
|
||||
async function jumpToLastUnusedPage() {
|
||||
const type = activeTypeTab.value === "all" ? undefined : activeTypeTab.value;
|
||||
const res = await getAccountPoolList(moduleKey, {
|
||||
page: 1,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: query.keyword || undefined,
|
||||
status: "unused",
|
||||
type,
|
||||
});
|
||||
if (res?.code !== 200) {
|
||||
ElMessage.error(res?.msg || "获取列表失败");
|
||||
return;
|
||||
}
|
||||
const cnt = Number(res?.data?.total || 0);
|
||||
if (cnt === 0) {
|
||||
ElMessage.warning("暂无未提取数据");
|
||||
return;
|
||||
}
|
||||
const lastPage = Math.max(1, Math.ceil(cnt / pagination.pageSize));
|
||||
skipWatchFetchDuringUnusedJump.value = true;
|
||||
pagination.page = lastPage;
|
||||
query.status = "unused";
|
||||
await nextTick();
|
||||
skipWatchFetchDuringUnusedJump.value = false;
|
||||
await fetchList();
|
||||
ElMessage.success(`已跳转未提取第 ${lastPage} 页(共 ${cnt} 条)`);
|
||||
}
|
||||
|
||||
onMounted(() => { fetchList(); });
|
||||
|
||||
// ---- 接口说明数据 ----
|
||||
@@ -428,6 +480,14 @@ function copyCardInfo(row) {
|
||||
<el-option label="未提取" value="unused" />
|
||||
<el-option label="已提取" value="extracted" />
|
||||
</el-select>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
title="按当前搜索与账号类型,筛选未提取并跳到最后一页"
|
||||
@click="jumpToLastUnusedPage"
|
||||
>
|
||||
未提取末页
|
||||
</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
@@ -465,8 +525,8 @@ function copyCardInfo(row) {
|
||||
<el-table-column prop="remark" label="备注" min-width="140" show-overflow-tooltip :tooltip-options="tooltipOpts" />
|
||||
<el-table-column label="提取状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.extracted ? 'success' : 'info'">{{
|
||||
row.extracted ? "已提取" : "未提取"
|
||||
<el-tag :type="extractStatusTagType(row)">{{
|
||||
extractStatusLabel(row)
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -489,9 +549,9 @@ function copyCardInfo(row) {
|
||||
>详情</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="!row.extractedAt && !row.extracted"
|
||||
link
|
||||
type="warning"
|
||||
:disabled="row.extracted"
|
||||
@click="openExtractByRow(row)"
|
||||
>提取</el-button
|
||||
>
|
||||
@@ -534,9 +594,11 @@ function copyCardInfo(row) {
|
||||
:type="extractForm.type"
|
||||
:platform="extractForm.platform"
|
||||
:remark="extractForm.remark"
|
||||
:replenish="extractForm.replenish"
|
||||
:platform-map="PLATFORM_MAP"
|
||||
@update:platform="(v) => (extractForm.platform = v)"
|
||||
@update:remark="(v) => (extractForm.remark = v)"
|
||||
@update:replenish="(v) => (extractForm.replenish = v)"
|
||||
@confirm="handleExtract"
|
||||
/>
|
||||
|
||||
|
||||
@@ -90,7 +90,9 @@ function copyToken() {
|
||||
<el-descriptions-item label="Token">
|
||||
<span class="token-text">{{ row.token || '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="提取状态">{{ row.extracted ? '已提取' : '未提取' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="提取状态">{{
|
||||
row.extractStatus === 2 ? '补号' : row.extracted ? '已提取' : '未提取'
|
||||
}}</el-descriptions-item>
|
||||
<el-descriptions-item label="提取时间">{{ row.extractedAt || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="提取平台">
|
||||
<el-tag v-if="row.extractedPlatform" :type="platformType" size="small">{{ platformLabel }}</el-tag>
|
||||
|
||||
@@ -5,10 +5,17 @@ const props = defineProps({
|
||||
type: { type: String, default: 'account' },
|
||||
platform: { type: String, default: 'local' },
|
||||
remark: { type: String, default: '' },
|
||||
replenish: { type: Boolean, default: false },
|
||||
platformMap: { type: Object, default: () => ({}) },
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'update:platform', 'update:remark', 'confirm']);
|
||||
const emit = defineEmits([
|
||||
'update:modelValue',
|
||||
'update:platform',
|
||||
'update:remark',
|
||||
'update:replenish',
|
||||
'confirm',
|
||||
]);
|
||||
|
||||
function typeText(type) {
|
||||
if (type === 'account') return '账号密码';
|
||||
@@ -29,6 +36,14 @@ function typeText(type) {
|
||||
<el-form-item label="提取类型">
|
||||
<el-input :model-value="typeText(type)" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否补号">
|
||||
<el-switch
|
||||
:model-value="replenish"
|
||||
active-text="是"
|
||||
inactive-text="否"
|
||||
@update:model-value="(v) => emit('update:replenish', v)"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="提取平台">
|
||||
<el-select
|
||||
:model-value="platform"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import Edit from './components/edit.vue';
|
||||
import DetailDialog from './components/detail.vue';
|
||||
@@ -33,7 +33,7 @@ const patchVisible = ref(false);
|
||||
const query = reactive({ keyword: "", status: "" });
|
||||
const activeTypeTab = ref("all");
|
||||
|
||||
const extractForm = reactive({ platform: 'local', type: 'account', remark: '' });
|
||||
const extractForm = reactive({ platform: 'local', type: 'account', remark: '', replenish: false });
|
||||
|
||||
const tableData = ref([]);
|
||||
const total = ref(0);
|
||||
@@ -43,6 +43,8 @@ const detailRemarkSaving = ref(false);
|
||||
const isMobile = ref(false);
|
||||
const pagination = reactive({ page: 1, pageSize: 30 });
|
||||
|
||||
const skipWatchFetchDuringUnusedJump = ref(false);
|
||||
|
||||
const pagedList = computed(() => tableData.value);
|
||||
|
||||
function resetQuery() {
|
||||
@@ -60,6 +62,7 @@ const typeTabs = computed(() => [
|
||||
watch(
|
||||
() => [query.keyword, query.status, activeTypeTab.value],
|
||||
() => {
|
||||
if (skipWatchFetchDuringUnusedJump.value) return;
|
||||
pagination.page = 1;
|
||||
fetchList();
|
||||
},
|
||||
@@ -67,6 +70,7 @@ watch(
|
||||
watch(
|
||||
() => [pagination.page, pagination.pageSize],
|
||||
() => {
|
||||
if (skipWatchFetchDuringUnusedJump.value) return;
|
||||
fetchList();
|
||||
},
|
||||
);
|
||||
@@ -123,6 +127,7 @@ function openExtractByRow(row) {
|
||||
extractForm.platform = "local";
|
||||
extractForm.type = row.type;
|
||||
extractForm.remark = row.remark || '';
|
||||
extractForm.replenish = false;
|
||||
extractVisible.value = true;
|
||||
}
|
||||
|
||||
@@ -156,7 +161,11 @@ async function handleExtract() {
|
||||
const target = extractTargetRow.value;
|
||||
if (!target) { ElMessage.warning("未找到提取目标"); return; }
|
||||
const res = await extractAccountPool(moduleKey, {
|
||||
id: target.id, type: target.type, platform: extractForm.platform, remark: extractForm.remark || '',
|
||||
id: target.id,
|
||||
type: target.type,
|
||||
platform: extractForm.platform,
|
||||
remark: extractForm.remark || '',
|
||||
replenish: !!extractForm.replenish,
|
||||
});
|
||||
if (res?.code !== 200) { ElMessage.error(res?.msg || "提取失败"); return; }
|
||||
ElMessage.success("提取成功");
|
||||
@@ -293,6 +302,8 @@ function normalizeRow(raw) {
|
||||
const p = (v) => String(v).padStart(2, "0");
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
||||
};
|
||||
const st = Number(pick("is_extracted", "isExtracted", "IsExtracted"));
|
||||
const extractStatus = Number.isFinite(st) ? st : 0;
|
||||
return {
|
||||
id: pick("id", "Id", "ID"),
|
||||
type: pick("data_type", "dataType", "type"),
|
||||
@@ -300,13 +311,26 @@ function normalizeRow(raw) {
|
||||
password: pick("password", "Password"),
|
||||
token: pick("token", "Token"),
|
||||
remark: pick("remark", "Remark"),
|
||||
extracted: Number(pick("is_extracted", "isExtracted", "IsExtracted")) === 1,
|
||||
extractStatus,
|
||||
extracted: extractStatus !== 0,
|
||||
extractedAt: formatTime(pickNullable("extracted_time", "extractedAt")),
|
||||
extractedPlatform: pickNullable("extracted_platform", "extractedPlatform"),
|
||||
createdAt: formatTime(pick("create_time", "createdAt")),
|
||||
};
|
||||
}
|
||||
|
||||
function extractStatusLabel(row) {
|
||||
if (row?.extractStatus === 2) return "补号";
|
||||
if (row?.extracted) return "已提取";
|
||||
return "未提取";
|
||||
}
|
||||
|
||||
function extractStatusTagType(row) {
|
||||
if (row?.extractStatus === 2) return "warning";
|
||||
if (row?.extracted) return "success";
|
||||
return "info";
|
||||
}
|
||||
|
||||
async function fetchList() {
|
||||
loading.value = true;
|
||||
try {
|
||||
@@ -329,6 +353,34 @@ async function fetchList() {
|
||||
}
|
||||
}
|
||||
|
||||
async function jumpToLastUnusedPage() {
|
||||
const type = activeTypeTab.value === 'all' ? undefined : activeTypeTab.value;
|
||||
const res = await getAccountPoolList(moduleKey, {
|
||||
page: 1,
|
||||
pageSize: pagination.pageSize,
|
||||
keyword: query.keyword || undefined,
|
||||
status: 'unused',
|
||||
type,
|
||||
});
|
||||
if (res?.code !== 200) {
|
||||
ElMessage.error(res?.msg || '获取列表失败');
|
||||
return;
|
||||
}
|
||||
const cnt = Number(res?.data?.total || 0);
|
||||
if (cnt === 0) {
|
||||
ElMessage.warning('暂无未提取数据');
|
||||
return;
|
||||
}
|
||||
const lastPage = Math.max(1, Math.ceil(cnt / pagination.pageSize));
|
||||
skipWatchFetchDuringUnusedJump.value = true;
|
||||
pagination.page = lastPage;
|
||||
query.status = 'unused';
|
||||
await nextTick();
|
||||
skipWatchFetchDuringUnusedJump.value = false;
|
||||
await fetchList();
|
||||
ElMessage.success(`已跳转未提取第 ${lastPage} 页(共 ${cnt} 条)`);
|
||||
}
|
||||
|
||||
onMounted(() => { fetchList(); });
|
||||
|
||||
// ---- 接口说明数据 ----
|
||||
@@ -427,6 +479,14 @@ function copyCardInfo(row) {
|
||||
<el-option label="未提取" value="unused" />
|
||||
<el-option label="已提取" value="extracted" />
|
||||
</el-select>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
title="按当前搜索与账号类型,筛选未提取并跳到最后一页"
|
||||
@click="jumpToLastUnusedPage"
|
||||
>
|
||||
未提取末页
|
||||
</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
@@ -464,8 +524,8 @@ function copyCardInfo(row) {
|
||||
<el-table-column prop="remark" label="备注" min-width="140" show-overflow-tooltip :tooltip-options="tooltipOpts" />
|
||||
<el-table-column label="提取状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.extracted ? 'success' : 'info'">{{
|
||||
row.extracted ? "已提取" : "未提取"
|
||||
<el-tag :type="extractStatusTagType(row)">{{
|
||||
extractStatusLabel(row)
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -488,9 +548,9 @@ function copyCardInfo(row) {
|
||||
>详情</el-button
|
||||
>
|
||||
<el-button
|
||||
v-if="!row.extractedAt && !row.extracted"
|
||||
link
|
||||
type="warning"
|
||||
:disabled="row.extracted"
|
||||
@click="openExtractByRow(row)"
|
||||
>提取</el-button
|
||||
>
|
||||
@@ -533,9 +593,11 @@ function copyCardInfo(row) {
|
||||
:type="extractForm.type"
|
||||
:platform="extractForm.platform"
|
||||
:remark="extractForm.remark"
|
||||
:replenish="extractForm.replenish"
|
||||
:platform-map="PLATFORM_MAP"
|
||||
@update:platform="(v) => (extractForm.platform = v)"
|
||||
@update:remark="(v) => (extractForm.remark = v)"
|
||||
@update:replenish="(v) => (extractForm.replenish = v)"
|
||||
@confirm="handleExtract"
|
||||
/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user