refactor: extract image form to standalone page and implement tags view store

- Created ImageForm.vue as standalone page for add/edit image functionality
- Removed dialog-based image form from VmImages.vue
- Implemented tagsViewStore for global tab state management
- Added automatic tab closing on form cancel/back
- Fixed data persistence issue when switching between image edits
- Removed quick actions section from ImageForm
- Updated router configuration for new image form route
This commit is contained in:
2025-11-28 14:15:29 +08:00
parent 067e0539ba
commit f7c3be1d30
45 changed files with 8776 additions and 6881 deletions
+218 -148
View File
@@ -1,131 +1,115 @@
<template>
<div class="order-list-container">
<!-- 搜索和操作栏 -->
<el-card class="filter-container" shadow="never">
<!-- <el-form :inline="true" :model="queryParams" class="search-form">
<el-form-item label="订单号">
<el-input v-model="queryParams.order_no" placeholder="请输入订单号" clearable style="width: 200px" />
</el-form-item>
<el-form-item label="用户ID">
<el-input v-model="queryParams.user_id" placeholder="请输入用户ID" clearable style="width: 150px" />
</el-form-item>
<el-form-item label="订单状态">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 150px">
<el-option label="待支付" value="0" />
<el-option label="已支付" value="1" />
<el-option label="已完成" value="2" />
<el-option label="已取消" value="3" />
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="queryParams.dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">
<el-icon><Search /></el-icon>查询
</el-button>
<el-button @click="resetQuery">重置</el-button>
</el-form-item>
</el-form> -->
<div class="action-bar">
<el-button type="primary" @click="handleAdd">
<el-icon><Plus /></el-icon>新增订单
</el-button>
<el-button type="success" @click="fetchOrderList">
<el-icon><Refresh /></el-icon>刷新
</el-button>
<!-- <el-button type="danger" :disabled="!selectedRows.length" @click="handleBatchDelete">
<el-icon><Delete /></el-icon>批量删除
</el-button> -->
<!-- <el-button type="success">
<el-icon><Download /></el-icon>导出订单
</el-button> -->
<!-- 主容器 -->
<el-card class="main-container" shadow="never">
<!-- 搜索和操作栏 -->
<div class="filter-section">
<div class="filter-content">
<div class="action-bar">
<el-button type="primary" @click="handleAdd">
<el-icon><Plus /></el-icon>新增订单
</el-button>
<el-button type="success" @click="fetchOrderList">
<el-icon><Refresh /></el-icon>刷新
</el-button>
</div>
</div>
</div>
</el-card>
<!-- 订单列表 -->
<el-card class="table-container" shadow="never">
<el-table
v-loading="loading"
:data="orderList"
@selection-change="handleSelectionChange"
style="width: 100%"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="订单ID" width="100" />
<el-table-column prop="name" label="订单名称" min-width="180" />
<el-table-column prop="userId" label="用户ID" width="100" />
<el-table-column prop="commodityId" label="商品ID" width="100" />
<el-table-column label="表名" width="120">
<template #default="{ row }">
<el-tag size="small">{{ row.table || '未知' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="订单金额" width="120">
<template #default="{ row }">
<span class="amount">¥{{ (row.price / 100).toFixed(2) }}</span>
</template>
</el-table-column>
<el-table-column label="续费价格" width="120">
<template #default="{ row }">
<span class="renew-price">¥{{ (row.renewPrice / 100).toFixed(2) }}</span>
</template>
</el-table-column>
<el-table-column label="数量" width="80">
<template #default="{ row }">
<span>{{ row.payNum }}</span>
</template>
</el-table-column>
<el-table-column label="订单状态" width="100">
<template #default="{ row }">
<el-tag :type="getStatusType(row.state)">
{{ getStatusText(row.state) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="支付方式" width="100">
<template #default="{ row }">
<span>{{ row.payType || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="过期时间" width="170">
<template #default="{ row }">
<span>{{ formatDate(row.expireTime) }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" width="170">
<template #default="{ row }">
<span>{{ formatDate(row.CreatedAt) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="handleView(row)">查看</el-button>
<el-button type="warning" link @click="handleEdit(row)">编辑</el-button>
<!-- <el-button type="danger" link @click="handleDelete(row)">删除</el-button> -->
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="queryParams.page"
v-model:page-size="queryParams.count"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
background
class="pagination"
/>
<!-- 订单列表 -->
<div class="table-section">
<!-- 骨架屏 -->
<div v-if="loading" class="skeleton-container">
<div v-for="i in 5" :key="i" class="skeleton-row">
<div class="skeleton-cell skeleton-checkbox"></div>
<div class="skeleton-cell skeleton-id"></div>
<div class="skeleton-cell skeleton-name"></div>
<div class="skeleton-cell skeleton-user"></div>
<div class="skeleton-cell skeleton-price"></div>
<div class="skeleton-cell skeleton-status"></div>
<div class="skeleton-cell skeleton-time"></div>
<div class="skeleton-cell skeleton-action"></div>
</div>
</div>
<el-table
v-else
v-loading="loading"
:data="orderList"
@selection-change="handleSelectionChange"
style="width: 100%"
:header-cell-style="{ background: '#fafafa', color: '#333', fontWeight: 600 }"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="订单ID" width="100" />
<el-table-column prop="name" label="订单名称" min-width="180" />
<el-table-column prop="userId" label="用户ID" width="100" />
<el-table-column prop="commodityId" label="商品ID" width="100" />
<el-table-column label="表名" width="120">
<template #default="{ row }">
<el-tag size="small">{{ row.table || '未知' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="订单金额" width="120">
<template #default="{ row }">
<span class="amount">¥{{ (row.price / 100).toFixed(2) }}</span>
</template>
</el-table-column>
<el-table-column label="续费价格" width="120">
<template #default="{ row }">
<span class="renew-price">¥{{ (row.renewPrice / 100).toFixed(2) }}</span>
</template>
</el-table-column>
<el-table-column label="数量" width="80">
<template #default="{ row }">
<span>{{ row.payNum }}</span>
</template>
</el-table-column>
<el-table-column label="订单状态" width="100">
<template #default="{ row }">
<el-tag :type="getStatusType(row.state)">
{{ getStatusText(row.state) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="支付方式" width="100">
<template #default="{ row }">
<span>{{ row.payType || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="过期时间" width="170">
<template #default="{ row }">
<span>{{ formatDate(row.expireTime) }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" width="170">
<template #default="{ row }">
<span>{{ formatDate(row.CreatedAt) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<div class="action-buttons">
<el-button type="primary" link @click="handleView(row)">查看</el-button>
<el-button type="warning" link @click="handleEdit(row)">编辑</el-button>
</div>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="queryParams.page"
v-model:page-size="queryParams.count"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
background
class="pagination"
/>
</div>
</el-card>
<!-- 订单详情对话框 -->
@@ -133,6 +117,7 @@
v-model="detailDialogVisible"
title="订单详情"
width="800px"
append-to-body
>
<el-descriptions :column="2" border v-if="orderDetail">
<el-descriptions-item label="订单ID">{{ orderDetail.id }}</el-descriptions-item>
@@ -162,6 +147,7 @@
v-model="dialogVisible"
:title="dialogType === 'add' ? '新增订单' : '编辑订单'"
width="700px"
append-to-body
>
<el-form
ref="orderFormRef"
@@ -217,8 +203,10 @@
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</div>
</template>
</el-dialog>
</div>
@@ -531,37 +519,40 @@ onMounted(() => {
padding: 0;
}
.filter-container {
margin-bottom: 20px;
border-radius: 8px;
.main-container {
border: 1px solid #e1e8ed;
background: #ffffff;
}
.search-form {
margin-bottom: 15px;
.filter-section {
padding: 0;
border-bottom: 1px solid #e1e8ed;
background: #fafbfc;
}
.filter-content {
display: flex;
justify-content: flex-end;
align-items: center;
padding: 16px 20px;
gap: 20px;
flex-wrap: wrap;
}
.action-bar {
display: flex;
gap: 12px;
flex-shrink: 0;
}
.table-container {
border-radius: 8px;
.table-section {
padding: 0;
}
.user-info {
padding: 4px 0;
}
.username {
font-size: 14px;
font-weight: 500;
margin-bottom: 4px;
}
.user-id {
font-size: 12px;
color: #999;
.action-buttons {
display: flex;
gap: 8px;
align-items: center;
}
.amount {
@@ -577,8 +568,87 @@ onMounted(() => {
}
.pagination {
margin-top: 24px;
margin-top: 20px;
padding: 16px 20px;
border-top: 1px solid #e1e8ed;
background: #fafbfc;
justify-content: flex-end;
}
</style>
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 12px;
padding: 0;
}
/* 表格样式优化 */
:deep(.el-table) {
border: none;
color: #2c3e50;
}
:deep(.el-table__header) {
background: #f8f9fa;
}
:deep(.el-table th) {
background: #f8f9fa !important;
border-bottom: 2px solid #e1e8ed;
color: #2c3e50;
font-weight: 600;
font-size: 13px;
}
:deep(.el-table td) {
border-bottom: 1px solid #f0f2f5;
color: #34495e;
}
:deep(.el-table tr:hover > td) {
background-color: #f8f9fa !important;
}
:deep(.el-card__body) {
padding: 0;
}
/* 骨架屏样式 */
.skeleton-container {
padding: 20px;
}
.skeleton-row {
display: flex;
align-items: center;
padding: 16px 0;
border-bottom: 1px solid #f0f0f0;
gap: 16px;
}
.skeleton-row:last-child {
border-bottom: none;
}
.skeleton-cell {
height: 20px;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s ease-in-out infinite;
border-radius: 4px;
}
.skeleton-checkbox { width: 55px; }
.skeleton-id { width: 100px; }
.skeleton-name { width: 180px; }
.skeleton-user { width: 100px; }
.skeleton-price { width: 120px; }
.skeleton-status { width: 100px; }
.skeleton-time { width: 170px; }
.skeleton-action { width: 200px; height: 32px; }
@keyframes skeleton-loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
</style>