fix(反馈): ①分组管理操作列加宽160px ②查询ASIN操作列补「删除」(整店全站配置清除,逐国端点) ③去重汇总编辑/删除间距(gap8) ④店铺数据记录下载文件按钮与全站编辑主色统一(btn-sm主蓝) ⑤撞款页按钮色统一蓝白(btn-primary #4f78a5);⑥全站分页统一收官: 分组管理/菜单管理/软件版本补 OldPagination(10/20/50/100)
This commit is contained in:
@@ -9,6 +9,7 @@ import { openAdminConfirm } from '@/components/admin-confirm'
|
|||||||
import { deleteShopGroup, fetchShopGroups } from './shop-group-api'
|
import { deleteShopGroup, fetchShopGroups } from './shop-group-api'
|
||||||
import type { ShopGroupItem } from './shop-group-model'
|
import type { ShopGroupItem } from './shop-group-model'
|
||||||
import GroupEditorDialog from './GroupEditorDialog.vue'
|
import GroupEditorDialog from './GroupEditorDialog.vue'
|
||||||
|
import OldPagination from '@/components/OldPagination.vue'
|
||||||
|
|
||||||
const session = useAdminSessionStore()
|
const session = useAdminSessionStore()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
@@ -30,6 +31,12 @@ const filteredRows = computed(() => {
|
|||||||
return nameOk && leaderOk
|
return nameOk && leaderOk
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
/** 全站分页统一:分组列表客户端分页(10/20/50/100)。 */
|
||||||
|
const page = ref(1)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
const pagedGroups = computed(() => filteredRows.value.slice((page.value - 1) * pageSize.value, page.value * pageSize.value))
|
||||||
|
function changeGroupPage(p: number) { page.value = p }
|
||||||
|
function changeGroupSize(size: number) { pageSize.value = size; page.value = 1 }
|
||||||
|
|
||||||
function canEditOf(group: ShopGroupItem): boolean {
|
function canEditOf(group: ShopGroupItem): boolean {
|
||||||
if (isSuperAdmin.value) return true
|
if (isSuperAdmin.value) return true
|
||||||
@@ -103,12 +110,12 @@ onMounted(loadGroups)
|
|||||||
<th>组员</th>
|
<th>组员</th>
|
||||||
<th style="width: 16%">创建时间</th>
|
<th style="width: 16%">创建时间</th>
|
||||||
<th style="width: 16%">修改时间</th>
|
<th style="width: 16%">修改时间</th>
|
||||||
<th style="width: 124px">操作</th>
|
<th style="width: 160px">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<template v-if="filteredRows.length">
|
<template v-if="filteredRows.length">
|
||||||
<tr v-for="(group, index) in filteredRows" :key="group.id">
|
<tr v-for="(group, index) in pagedGroups" :key="group.id">
|
||||||
<td>{{ index + 1 }}</td>
|
<td>{{ index + 1 }}</td>
|
||||||
<td>{{ group.name }}</td>
|
<td>{{ group.name }}</td>
|
||||||
<td>{{ group.leaderUsername || '-' }}</td>
|
<td>{{ group.leaderUsername || '-' }}</td>
|
||||||
@@ -139,6 +146,7 @@ onMounted(loadGroups)
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<OldPagination v-if="filteredRows.length > 0" :total="filteredRows.length" :page="page" :page-size="pageSize" @change="changeGroupPage" @size-change="changeGroupSize" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<GroupEditorDialog
|
<GroupEditorDialog
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { formatDateTime } from '@/utils/datetime'
|
|||||||
* script 逻辑沿用现有 Vue 实现(拖拽分组/落点/重排保存、弹窗表单)。 */
|
* script 逻辑沿用现有 Vue 实现(拖拽分组/落点/重排保存、弹窗表单)。 */
|
||||||
import { computed, onMounted, reactive, ref } from 'vue'
|
import { computed, onMounted, reactive, ref } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import OldPagination from '@/components/OldPagination.vue'
|
||||||
import { createMenu, deleteMenu, loadMenuManageTree, reorderMenus, updateMenu } from './menu-manage-api'
|
import { createMenu, deleteMenu, loadMenuManageTree, reorderMenus, updateMenu } from './menu-manage-api'
|
||||||
import {
|
import {
|
||||||
MENU_TYPE_OPTIONS,
|
MENU_TYPE_OPTIONS,
|
||||||
@@ -41,6 +42,12 @@ const filteredMenuRows = computed<MenuRow[]>(() => {
|
|||||||
return nameOk && typeOk
|
return nameOk && typeOk
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
/** 全站分页统一:菜单树展平行客户端分页(10/20/50/100)。 */
|
||||||
|
const page = ref(1)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
const pagedMenuRows = computed(() => filteredMenuRows.value.slice((page.value - 1) * pageSize.value, page.value * pageSize.value))
|
||||||
|
function changeMenuPage(p: number) { page.value = p }
|
||||||
|
function changeMenuSize(size: number) { pageSize.value = size; page.value = 1 }
|
||||||
/** 展平视图:前序 + depth。 */
|
/** 展平视图:前序 + depth。 */
|
||||||
const menuRows = computed<MenuRow[]>(() => {
|
const menuRows = computed<MenuRow[]>(() => {
|
||||||
const out: MenuRow[] = []
|
const out: MenuRow[] = []
|
||||||
@@ -240,7 +247,7 @@ onMounted(loadMenus)
|
|||||||
<tbody>
|
<tbody>
|
||||||
<template v-if="filteredMenuRows.length">
|
<template v-if="filteredMenuRows.length">
|
||||||
<tr
|
<tr
|
||||||
v-for="row in filteredMenuRows"
|
v-for="row in pagedMenuRows"
|
||||||
:key="row.id"
|
:key="row.id"
|
||||||
:class="{ 'is-column-dragging': dragState?.id === row.id }"
|
:class="{ 'is-column-dragging': dragState?.id === row.id }"
|
||||||
@dragover="onDragOver($event, row)"
|
@dragover="onDragOver($event, row)"
|
||||||
@@ -287,6 +294,7 @@ onMounted(loadMenus)
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<OldPagination v-if="filteredMenuRows.length > 0" :total="filteredMenuRows.length" :page="page" :page-size="pageSize" @change="changeMenuPage" @size-change="changeMenuSize" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<el-dialog v-model="createVisible" :title="dialogTitle" width="520px">
|
<el-dialog v-model="createVisible" :title="dialogTitle" width="520px">
|
||||||
|
|||||||
@@ -654,6 +654,9 @@ h3 {
|
|||||||
font-size: 12.5px;
|
font-size: 12.5px;
|
||||||
}
|
}
|
||||||
.ops-cell {
|
.ops-cell {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,21 @@ function normalizeAsinInput(country: string): void {
|
|||||||
draftAsin[country] = draftAsin[country].trim().toUpperCase()
|
draftAsin[country] = draftAsin[country].trim().toUpperCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function removeShopAsin(item: QueryAsinItem) {
|
||||||
|
// 删除该店铺全部站点的 ASIN 配置(逐国调用现有端点)。
|
||||||
|
if (!window.confirm(`确定删除店铺“${item.shopName}”的全部站点 ASIN 配置吗?`)) return
|
||||||
|
try {
|
||||||
|
for (const country of QUERY_ASIN_COUNTRIES) {
|
||||||
|
if (asinOf(item, country)) await deleteQueryAsinCountryAsin(item.id, country)
|
||||||
|
}
|
||||||
|
ElMessage.success('已删除')
|
||||||
|
await load()
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error(error instanceof Error ? error.message : '删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function saveConfig(): Promise<void> {
|
async function saveConfig(): Promise<void> {
|
||||||
const item = drawerItem.value
|
const item = drawerItem.value
|
||||||
if (!item) return
|
if (!item) return
|
||||||
@@ -385,6 +400,7 @@ onMounted(() => {
|
|||||||
<template v-if="row.isFirst">
|
<template v-if="row.isFirst">
|
||||||
<td :rowspan="row.rowspan" class="asin-col-actions">
|
<td :rowspan="row.rowspan" class="asin-col-actions">
|
||||||
<button class="btn btn-sm" type="button" @click="openConfig(row.item as QueryAsinItem)">配置</button>
|
<button class="btn btn-sm" type="button" @click="openConfig(row.item as QueryAsinItem)">配置</button>
|
||||||
|
<button class="btn btn-sm btn-danger" type="button" @click="removeShopAsin(row.item as QueryAsinItem)">删除</button>
|
||||||
</td>
|
</td>
|
||||||
</template>
|
</template>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { formatDateTime } from '@/utils/datetime'
|
|||||||
/** 软件版本管理页 · 像素复刻旧版 admin.html panel-version(自绘:面板头+上传新版本、版本列表、全量无分页同旧版)。
|
/** 软件版本管理页 · 像素复刻旧版 admin.html panel-version(自绘:面板头+上传新版本、版本列表、全量无分页同旧版)。
|
||||||
* script 逻辑沿用现有 Vue 实现(上传弹窗成功留驻含链接)。 */
|
* script 逻辑沿用现有 Vue 实现(上传弹窗成功留驻含链接)。 */
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
import OldPagination from '@/components/OldPagination.vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { fetchSoftwareVersions, uploadSoftwareVersion } from './version-api.ts'
|
import { fetchSoftwareVersions, uploadSoftwareVersion } from './version-api.ts'
|
||||||
import type { SoftwareVersionItem } from './version-dto.ts'
|
import type { SoftwareVersionItem } from './version-dto.ts'
|
||||||
@@ -17,6 +18,12 @@ const filteredItems = computed(() => {
|
|||||||
if (!kw) return items.value
|
if (!kw) return items.value
|
||||||
return items.value.filter((item) => `${item.version}`.toLowerCase().includes(kw))
|
return items.value.filter((item) => `${item.version}`.toLowerCase().includes(kw))
|
||||||
})
|
})
|
||||||
|
/** 全站分页统一:版本列表客户端分页(10/20/50/100)。 */
|
||||||
|
const page = ref(1)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
const pagedVersions = computed(() => filteredItems.value.slice((page.value - 1) * pageSize.value, page.value * pageSize.value))
|
||||||
|
function changeVersionPage(p: number) { page.value = p }
|
||||||
|
function changeVersionSize(size: number) { pageSize.value = size; page.value = 1 }
|
||||||
|
|
||||||
const uploadVisible = ref(false)
|
const uploadVisible = ref(false)
|
||||||
const uploading = ref(false)
|
const uploading = ref(false)
|
||||||
@@ -108,7 +115,7 @@ onMounted(load)
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<template v-if="filteredItems.length">
|
<template v-if="filteredItems.length">
|
||||||
<tr v-for="row in filteredItems" :key="row.version + row.id">
|
<tr v-for="row in pagedVersions" :key="row.version + row.id">
|
||||||
<td>{{ row.version }}</td>
|
<td>{{ row.version }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a v-if="row.fileUrl" class="link-cell" :href="row.fileUrl" target="_blank" rel="noopener" :title="row.fileUrl">{{ row.fileUrl }}</a>
|
<a v-if="row.fileUrl" class="link-cell" :href="row.fileUrl" target="_blank" rel="noopener" :title="row.fileUrl">{{ row.fileUrl }}</a>
|
||||||
@@ -130,6 +137,7 @@ onMounted(load)
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<OldPagination v-if="filteredItems.length > 0" :total="filteredItems.length" :page="page" :page-size="pageSize" @change="changeVersionPage" @size-change="changeVersionSize" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<el-dialog v-model="uploadVisible" title="上传新版本" width="520px">
|
<el-dialog v-model="uploadVisible" title="上传新版本" width="520px">
|
||||||
|
|||||||
@@ -787,10 +787,10 @@ onMounted(() => {
|
|||||||
height: 34px; border-radius: 7px; padding: 0 16px; font-size: 13px; font-weight: 600;
|
height: 34px; border-radius: 7px; padding: 0 16px; font-size: 13px; font-weight: 600;
|
||||||
display: inline-flex; align-items: center; gap: 6px; transition: background 0.15s, color 0.15s, border-color 0.15s;
|
display: inline-flex; align-items: center; gap: 6px; transition: background 0.15s, color 0.15s, border-color 0.15s;
|
||||||
}
|
}
|
||||||
.dup-ref .btn-primary { background: var(--primary); color: #fff; }
|
.dup-ref .btn-primary { background: #4f78a5; color: #fff; }
|
||||||
.dup-ref .btn-primary:hover { background: var(--primary-hover); }
|
.dup-ref .btn-primary:hover { background: #5d83ac; }
|
||||||
.dup-ref .btn-ghost { background: #fff; color: var(--text2); border: 1px solid var(--border-strong); }
|
.dup-ref .btn-ghost { background: #fff; color: var(--text2); border: 1px solid var(--border-strong); }
|
||||||
.dup-ref .btn-ghost:hover { border-color: var(--primary); color: var(--primary); }
|
.dup-ref .btn-ghost:hover { border-color: #4f78a5; color: #4f78a5; }
|
||||||
.dup-ref .btn-sm { height: 28px; padding: 0 10px; font-size: 12px; border-radius: 6px; }
|
.dup-ref .btn-sm { height: 28px; padding: 0 10px; font-size: 12px; border-radius: 6px; }
|
||||||
|
|
||||||
/* ---------- KPI 统计 ---------- */
|
/* ---------- KPI 统计 ---------- */
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ onMounted(load)
|
|||||||
</div>
|
</div>
|
||||||
<div class="sd-card-actions">
|
<div class="sd-card-actions">
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm btn-secondary"
|
class="btn btn-sm"
|
||||||
type="button"
|
type="button"
|
||||||
:disabled="!isUsableShopDataResult(row) || busyKey === row.resultId"
|
:disabled="!isUsableShopDataResult(row) || busyKey === row.resultId"
|
||||||
@click="downloadRow(row)"
|
@click="downloadRow(row)"
|
||||||
|
|||||||
Reference in New Issue
Block a user