admin_new P0+P1 全批次合并 (84 commits) #2

Merged
direv merged 85 commits from develop into main 2026-08-07 11:27:17 +08:00
13 changed files with 206 additions and 202 deletions
Showing only changes of commit e3536ff2dd - Show all commits

View File

@ -2,6 +2,8 @@
/** /**
* F006 部门管理 - W4.14 * F006 部门管理 - W4.14
* *
* W11 A8: 套 PageHeader/SearchBar 标准化模板
*
* 后端: GET /sys/dept/list (返树结构) * 后端: GET /sys/dept/list (返树结构)
* 字段: id/pid/name/sort/createDate/parentName * 字段: id/pid/name/sort/createDate/parentName
* *
@ -11,6 +13,8 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface Dept { interface Dept {
id: string id: string
@ -144,15 +148,9 @@ onMounted(load)
<template> <template>
<div class="rr-sys-dept"> <div class="rr-sys-dept">
<div class="rr-page-header"> <PageHeader title="部门管理" :sub="``">
<div class="rr-page-titles">
<h2 class="rr-page-title">部门管理</h2>
<p class="rr-page-sub">共 {{ list.length }} 个部门(树形)</p>
</div>
<div class="rr-page-actions">
<el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增部门</el-button> <el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增部门</el-button>
</div> </PageHeader>
</div>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable
@ -222,6 +220,9 @@ onMounted(load)
<style scoped> <style scoped>
.rr-sys-dept { padding: 16px; } .rr-sys-dept { padding: 16px; }
.rr-list-card { background: var(--surface); border-radius: 12px; padding: 4px; }
.rr-time { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 12px; color: var(--ink-2); }
.rr-muted { color: var(--ink-3); font-size: 12px; }
.rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } .rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.rr-page-titles { display: flex; flex-direction: column; gap: 2px; } .rr-page-titles { display: flex; flex-direction: column; gap: 2px; }
.rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); } .rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); }

View File

@ -2,6 +2,8 @@
/** /**
* F006 字典数据 - W4.18 * F006 字典数据 - W4.18
* *
* W11 A8: 套 PageHeader/SearchBar 标准化模板
*
* 后端: GET /sys/dict/data/page * 后端: GET /sys/dict/data/page
* 字段: id/dictTypeId/dictLabel/dictValue/dictSort/remark/createDate * 字段: id/dictTypeId/dictLabel/dictValue/dictSort/remark/createDate
* *
@ -11,6 +13,8 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface DictData { interface DictData {
id: string id: string
@ -138,21 +142,19 @@ onMounted(load)
<template> <template>
<div class="rr-sys-dict-data"> <div class="rr-sys-dict-data">
<div class="rr-page-header"> <PageHeader title="字典数据" :sub="`共 ${total} 条`">
<div class="rr-page-titles">
<h2 class="rr-page-title">字典数据</h2>
<p class="rr-page-sub">共 {{ total }} 条字典项</p>
</div>
<div class="rr-page-actions">
<el-button @click="onReset" class="rr-btn-secondary">重置</el-button> <el-button @click="onReset" class="rr-btn-secondary">重置</el-button>
<el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增字典项</el-button> <el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增字典项</el-button>
</div> </PageHeader>
</div>
<div class="rr-filters-row"> <SearchBar
<el-input v-model="filters.dictLabel" placeholder="字典标签搜索" clearable class="rr-label-input" size="small" @keyup.enter="onSearch" /> v-model:filters="filters"
<el-button class="rr-btn-secondary" size="small" @click="onSearch">查询</el-button> :fields='[
</div> { key: "dictLabel", label: "字典标签", type: "text", placeholder: "字典标签" }
]'
@search="onSearch"
@reset="onReset"
/>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable
@ -222,6 +224,9 @@ onMounted(load)
<style scoped> <style scoped>
.rr-sys-dict-data { padding: 16px; } .rr-sys-dict-data { padding: 16px; }
.rr-list-card { background: var(--surface); border-radius: 12px; padding: 4px; }
.rr-time { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 12px; color: var(--ink-2); }
.rr-muted { color: var(--ink-3); font-size: 12px; }
.rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } .rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.rr-page-titles { display: flex; flex-direction: column; gap: 2px; } .rr-page-titles { display: flex; flex-direction: column; gap: 2px; }
.rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); } .rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); }

View File

@ -2,6 +2,8 @@
/** /**
* F006 字典类型 - W4.18 * F006 字典类型 - W4.18
* *
* W11 A8: 套 PageHeader/SearchBar 标准化模板
*
* 后端: GET /sys/dict/type/page * 后端: GET /sys/dict/type/page
* 字段: id/dictType/dictName/remark/createDate * 字段: id/dictType/dictName/remark/createDate
* *
@ -11,6 +13,8 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface DictType { interface DictType {
id: string id: string
@ -128,21 +132,21 @@ onMounted(load)
<template> <template>
<div class="rr-sys-dict-type"> <div class="rr-sys-dict-type">
<div class="rr-page-header"> <PageHeader title="字典类型" :sub="`共 ${total} 个字典`">
<div class="rr-page-titles">
<h2 class="rr-page-title">字典类型</h2>
<p class="rr-page-sub">共 {{ total }} 个字典类型</p>
</div>
<div class="rr-page-actions">
<el-button @click="onReset" class="rr-btn-secondary">重置</el-button> <el-button @click="onReset" class="rr-btn-secondary">重置</el-button>
<el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增字典类型</el-button> <el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增字典类型</el-button>
</div> </PageHeader>
</div>
<div class="rr-filters-row"> <SearchBar
<el-input v-model="filters.dictType" placeholder="字典类型搜索" clearable class="rr-type-input" size="small" @keyup.enter="onSearch" /> v-model:filters="filters"
<el-button class="rr-btn-secondary" size="small" @click="onSearch">查询</el-button> :fields='[
</div> { key: "dictName", label: "字典名", type: "text", placeholder: "字典名" },
{ key: "dictType", label: "字典类型", type: "text", placeholder: "字典类型" }
]'
@search="onSearch"
@reset="onReset"
/>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable
@ -204,6 +208,9 @@ onMounted(load)
<style scoped> <style scoped>
.rr-sys-dict-type { padding: 16px; } .rr-sys-dict-type { padding: 16px; }
.rr-list-card { background: var(--surface); border-radius: 12px; padding: 4px; }
.rr-time { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 12px; color: var(--ink-2); }
.rr-muted { color: var(--ink-3); font-size: 12px; }
.rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } .rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.rr-page-titles { display: flex; flex-direction: column; gap: 2px; } .rr-page-titles { display: flex; flex-direction: column; gap: 2px; }
.rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); } .rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); }

View File

@ -2,6 +2,8 @@
/** /**
* F006 文件管理 - W4.16 * F006 文件管理 - W4.16
* *
* W11 A8: 套 PageHeader/SearchBar 标准化模板
*
* 后端: GET /sys/file/page * 后端: GET /sys/file/page
* 字段: id/url/creator/createDate * 字段: id/url/creator/createDate
*/ */
@ -9,6 +11,8 @@ import { onMounted, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpDelete } from '@/utils/request' import { httpGet, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface FileItem { interface FileItem {
id: string id: string
@ -85,15 +89,9 @@ onMounted(load)
<template> <template>
<div class="rr-sys-file"> <div class="rr-sys-file">
<div class="rr-page-header"> <PageHeader title="文件管理" :sub="`共 ${total} 个文件`">
<div class="rr-page-titles">
<h2 class="rr-page-title">文件管理</h2>
<p class="rr-page-sub">共 {{ total }} 个文件</p>
</div>
<div class="rr-page-actions">
<el-button @click="load" class="rr-btn-secondary">刷新</el-button> <el-button @click="load" class="rr-btn-secondary">刷新</el-button>
</div> </PageHeader>
</div>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable
@ -133,6 +131,9 @@ onMounted(load)
<style scoped> <style scoped>
.rr-sys-file { padding: 16px; } .rr-sys-file { padding: 16px; }
.rr-list-card { background: var(--surface); border-radius: 12px; padding: 4px; }
.rr-time { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 12px; color: var(--ink-2); }
.rr-muted { color: var(--ink-3); font-size: 12px; }
.rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } .rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.rr-page-titles { display: flex; flex-direction: column; gap: 2px; } .rr-page-titles { display: flex; flex-direction: column; gap: 2px; }
.rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); } .rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); }

View File

@ -2,6 +2,8 @@
/** /**
* F006 菜单管理 - W4.14 * F006 菜单管理 - W4.14
* *
* W11 A8: 套 PageHeader (树形保留 el-table)
*
* 后端: GET /sys/menu/list (返树结构) * 后端: GET /sys/menu/list (返树结构)
* 字段: id/pid/name/url/type/permissions/icon/sort/createDate * 字段: id/pid/name/url/type/permissions/icon/sort/createDate
* *
@ -11,6 +13,7 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
interface Menu { interface Menu {
id: string id: string
@ -168,15 +171,9 @@ onMounted(load)
<template> <template>
<div class="rr-sys-menu"> <div class="rr-sys-menu">
<div class="rr-page-header"> <PageHeader title="菜单管理" :sub="`共 ${list.length} 个菜单`">
<div class="rr-page-titles">
<h2 class="rr-page-title">菜单管理</h2>
<p class="rr-page-sub">共 {{ list.length }} 个菜单(树形)</p>
</div>
<div class="rr-page-actions">
<el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增菜单</el-button> <el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增菜单</el-button>
</div> </PageHeader>
</div>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable
@ -272,6 +269,9 @@ onMounted(load)
<style scoped> <style scoped>
.rr-sys-menu { padding: 16px; } .rr-sys-menu { padding: 16px; }
.rr-list-card { background: var(--surface); border-radius: 12px; padding: 4px; }
.rr-time { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 12px; color: var(--ink-2); }
.rr-muted { color: var(--ink-3); font-size: 12px; }
.rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } .rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.rr-page-titles { display: flex; flex-direction: column; gap: 2px; } .rr-page-titles { display: flex; flex-direction: column; gap: 2px; }
.rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); } .rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); }

View File

@ -2,6 +2,8 @@
/** /**
* F006 通知公告 - W4.18 * F006 通知公告 - W4.18
* *
* W11 A8: 套 PageHeader/SearchBar 标准化模板
*
* 后端: GET /sys/notice/page * 后端: GET /sys/notice/page
* 字段: id/title/content/type/status/publisherName/createDate * 字段: id/title/content/type/status/publisherName/createDate
* *
@ -11,6 +13,8 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface Notice { interface Notice {
id: string id: string
@ -154,21 +158,19 @@ onMounted(load)
<template> <template>
<div class="rr-sys-notice"> <div class="rr-sys-notice">
<div class="rr-page-header"> <PageHeader title="通知公告" :sub="`共 ${total} 条`">
<div class="rr-page-titles">
<h2 class="rr-page-title">通知公告</h2>
<p class="rr-page-sub">共 {{ total }} 条公告</p>
</div>
<div class="rr-page-actions">
<el-button @click="onReset" class="rr-btn-secondary">重置</el-button> <el-button @click="onReset" class="rr-btn-secondary">重置</el-button>
<el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增公告</el-button> <el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增公告</el-button>
</div> </PageHeader>
</div>
<div class="rr-filters-row"> <SearchBar
<el-input v-model="filters.title" placeholder="标题搜索" clearable class="rr-title-input" size="small" @keyup.enter="onSearch" /> v-model:filters="filters"
<el-button class="rr-btn-secondary" size="small" @click="onSearch">查询</el-button> :fields='[
</div> { key: "title", label: "标题", type: "text", placeholder: "标题" }
]'
@search="onSearch"
@reset="onReset"
/>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable
@ -253,6 +255,9 @@ onMounted(load)
<style scoped> <style scoped>
.rr-sys-notice { padding: 16px; } .rr-sys-notice { padding: 16px; }
.rr-list-card { background: var(--surface); border-radius: 12px; padding: 4px; }
.rr-time { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 12px; color: var(--ink-2); }
.rr-muted { color: var(--ink-3); font-size: 12px; }
.rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } .rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.rr-page-titles { display: flex; flex-direction: column; gap: 2px; } .rr-page-titles { display: flex; flex-direction: column; gap: 2px; }
.rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); } .rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); }

View File

@ -19,6 +19,8 @@ import { onMounted, ref, reactive, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
interface SysParams { interface SysParams {
@ -193,19 +195,10 @@ onMounted(() => {
<template> <template>
<div class="rr-sys-params"> <div class="rr-sys-params">
<div class="rr-page-header"> <PageHeader title="参数管理" :sub="hasParamsPerm ? `共 ${total} 个参数` : '当前角色无参数管理权限'">
<div class="rr-page-titles">
<h2 class="rr-page-title">参数管理</h2>
<p class="rr-page-sub">
<template v-if="hasParamsPerm">共 {{ total }} 个参数</template>
<template v-else>当前角色无参数管理权限</template>
</p>
</div>
<div class="rr-page-actions">
<el-button @click="onReset" class="rr-btn-secondary">重置</el-button> <el-button @click="onReset" class="rr-btn-secondary">重置</el-button>
<el-button type="primary" class="rr-btn-primary" :disabled="!hasParamsPerm" @click="createHandle">+ 新增参数</el-button> <el-button type="primary" class="rr-btn-primary" :disabled="!hasParamsPerm" @click="createHandle">+ 新增参数</el-button>
</div> </PageHeader>
</div>
<!-- 无权限提示卡 --> <!-- 无权限提示卡 -->
<el-alert <el-alert
@ -222,17 +215,14 @@ onMounted(() => {
</el-alert> </el-alert>
<template v-else> <template v-else>
<div class="rr-filters-row"> <SearchBar
<el-input v-model:filters="filters"
v-model="filters.paramCode" :fields='[
placeholder="参数编码搜索" { key: "paramKey", label: "参数键", type: "text", placeholder: "参数键" }
clearable ]'
class="rr-code-input" @search="onSearch"
size="small" @reset="onReset"
@keyup.enter="onSearch"
/> />
<el-button class="rr-btn-secondary" size="small" @click="onSearch">查询</el-button>
</div>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable

View File

@ -2,6 +2,8 @@
/** /**
* F006 岗位管理 - W4.16 * F006 岗位管理 - W4.16
* *
* W11 A8: 套 PageHeader/SearchBar 标准化模板
*
* 后端: GET /sys/post/page * 后端: GET /sys/post/page
* 字段: id/postCode/postName/sort/status/createDate * 字段: id/postCode/postName/sort/status/createDate
*/ */
@ -9,6 +11,8 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface Post { interface Post {
id: string id: string
@ -126,22 +130,21 @@ onMounted(load)
<template> <template>
<div class="rr-sys-post"> <div class="rr-sys-post">
<div class="rr-page-header"> <PageHeader title="岗位管理" :sub="`共 ${total} 个岗位`">
<div class="rr-page-titles">
<h2 class="rr-page-title">岗位管理</h2>
<p class="rr-page-sub">共 {{ total }} 个岗位</p>
</div>
<div class="rr-page-actions">
<el-button @click="onReset" class="rr-btn-secondary">重置</el-button> <el-button @click="onReset" class="rr-btn-secondary">重置</el-button>
<el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增岗位</el-button> <el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增岗位</el-button>
</div> </PageHeader>
</div>
<div class="rr-filters-row"> <SearchBar
<el-input v-model="filters.postCode" placeholder="岗位编码" clearable class="rr-code-input" size="small" @keyup.enter="onSearch" /> v-model:filters="filters"
<el-input v-model="filters.postName" placeholder="岗位名称" clearable class="rr-name-input" size="small" @keyup.enter="onSearch" /> :fields='[
<el-button class="rr-btn-secondary" size="small" @click="onSearch">查询</el-button> { key: "postCode", label: "岗位编码", type: "text", placeholder: "岗位编码" },
</div> { key: "postName", label: "岗位名称", type: "text", placeholder: "岗位名称" }
]'
@search="onSearch"
@reset="onReset"
/>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable
@ -213,6 +216,9 @@ onMounted(load)
<style scoped> <style scoped>
.rr-sys-post { padding: 16px; } .rr-sys-post { padding: 16px; }
.rr-list-card { background: var(--surface); border-radius: 12px; padding: 4px; }
.rr-time { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 12px; color: var(--ink-2); }
.rr-muted { color: var(--ink-3); font-size: 12px; }
.rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } .rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.rr-page-titles { display: flex; flex-direction: column; gap: 2px; } .rr-page-titles { display: flex; flex-direction: column; gap: 2px; }
.rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); } .rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); }

View File

@ -2,6 +2,8 @@
/** /**
* F006 商品管理 - W4.18 * F006 商品管理 - W4.18
* *
* W11 A8: 套 PageHeader/SearchBar 标准化模板
*
* 后端: GET /sys/product/page * 后端: GET /sys/product/page
* 字段: id/name/categoryId/originPrice/price/stock/status/createDate * 字段: id/name/categoryId/originPrice/price/stock/status/createDate
* *
@ -11,6 +13,8 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface Product { interface Product {
id: string id: string
@ -152,21 +156,19 @@ onMounted(load)
<template> <template>
<div class="rr-sys-product"> <div class="rr-sys-product">
<div class="rr-page-header"> <PageHeader title="商品管理" :sub="`共 ${total} 个商品`">
<div class="rr-page-titles">
<h2 class="rr-page-title">商品管理</h2>
<p class="rr-page-sub">共 {{ total }} 个商品</p>
</div>
<div class="rr-page-actions">
<el-button @click="onReset" class="rr-btn-secondary">重置</el-button> <el-button @click="onReset" class="rr-btn-secondary">重置</el-button>
<el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增商品</el-button> <el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增商品</el-button>
</div> </PageHeader>
</div>
<div class="rr-filters-row"> <SearchBar
<el-input v-model="filters.name" placeholder="商品名搜索" clearable class="rr-name-input" size="small" @keyup.enter="onSearch" /> v-model:filters="filters"
<el-button class="rr-btn-secondary" size="small" @click="onSearch">查询</el-button> :fields='[
</div> { key: "name", label: "商品名称", type: "text", placeholder: "商品名称" }
]'
@search="onSearch"
@reset="onReset"
/>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable
@ -247,6 +249,9 @@ onMounted(load)
<style scoped> <style scoped>
.rr-sys-product { padding: 16px; } .rr-sys-product { padding: 16px; }
.rr-list-card { background: var(--surface); border-radius: 12px; padding: 4px; }
.rr-time { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 12px; color: var(--ink-2); }
.rr-muted { color: var(--ink-3); font-size: 12px; }
.rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } .rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.rr-page-titles { display: flex; flex-direction: column; gap: 2px; } .rr-page-titles { display: flex; flex-direction: column; gap: 2px; }
.rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); } .rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); }

View File

@ -2,6 +2,8 @@
/** /**
* F006 角色组管理 - W4.16 * F006 角色组管理 - W4.16
* *
* W11 A8: 套 PageHeader/SearchBar 标准化模板
*
* 后端: GET /sys/roleGroup/page * 后端: GET /sys/roleGroup/page
* 字段: id/operationId/name/createDate * 字段: id/operationId/name/createDate
*/ */
@ -9,6 +11,8 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface RoleGroup { interface RoleGroup {
id: string id: string
@ -111,21 +115,19 @@ onMounted(load)
<template> <template>
<div class="rr-sys-role-group"> <div class="rr-sys-role-group">
<div class="rr-page-header"> <PageHeader title="角色组管理" :sub="`共 ${total} 个角色组`">
<div class="rr-page-titles">
<h2 class="rr-page-title">角色组管理</h2>
<p class="rr-page-sub">共 {{ total }} 个角色组</p>
</div>
<div class="rr-page-actions">
<el-button @click="onReset" class="rr-btn-secondary">重置</el-button> <el-button @click="onReset" class="rr-btn-secondary">重置</el-button>
<el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增角色组</el-button> <el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增角色组</el-button>
</div> </PageHeader>
</div>
<div class="rr-filters-row"> <SearchBar
<el-input v-model="filters.name" placeholder="角色组名" clearable class="rr-name-input" size="small" @keyup.enter="onSearch" /> v-model:filters="filters"
<el-button class="rr-btn-secondary" size="small" @click="onSearch">查询</el-button> :fields='[
</div> { key: "name", label: "角色组名", type: "text", placeholder: "角色组名" }
]'
@search="onSearch"
@reset="onReset"
/>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable
@ -182,6 +184,9 @@ onMounted(load)
<style scoped> <style scoped>
.rr-sys-role-group { padding: 16px; } .rr-sys-role-group { padding: 16px; }
.rr-list-card { background: var(--surface); border-radius: 12px; padding: 4px; }
.rr-time { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 12px; color: var(--ink-2); }
.rr-muted { color: var(--ink-3); font-size: 12px; }
.rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } .rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.rr-page-titles { display: flex; flex-direction: column; gap: 2px; } .rr-page-titles { display: flex; flex-direction: column; gap: 2px; }
.rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); } .rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); }

View File

@ -20,6 +20,8 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface SysRole { interface SysRole {
id: string id: string
@ -178,28 +180,19 @@ onMounted(() => { load() })
<template> <template>
<div class="rr-sys-role"> <div class="rr-sys-role">
<div class="rr-page-header"> <PageHeader title="角色管理" :sub="`共 ${total} 个角色`">
<div class="rr-page-titles">
<h2 class="rr-page-title">角色管理</h2>
<p class="rr-page-sub">共 {{ total }} 个角色</p>
</div>
<div class="rr-page-actions">
<el-button @click="onReset" class="rr-btn-secondary">重置</el-button> <el-button @click="onReset" class="rr-btn-secondary">重置</el-button>
<el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增角色</el-button> <el-button type="primary" class="rr-btn-primary" @click="createHandle">+ 新增角色</el-button>
</div> </PageHeader>
</div>
<div class="rr-filters-row"> <SearchBar
<el-input v-model:filters="filters"
v-model="filters.name" :fields='[
placeholder="角色名搜索" { key: "roleName", label: "角色名", type: "text", placeholder: "角色名" }
clearable ]'
class="rr-name-input" @search="onSearch"
size="small" @reset="onReset"
@keyup.enter="onSearch"
/> />
<el-button class="rr-btn-secondary" size="small" @click="onSearch">查询</el-button>
</div>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable

View File

@ -2,6 +2,8 @@
/** /**
* F006 定时任务 - W4.16 * F006 定时任务 - W4.16
* *
* W11 A8: 套 PageHeader/SearchBar 标准化模板
*
* 后端: GET /sys/schedule/page * 后端: GET /sys/schedule/page
* 字段: id/beanName/methodName/params/cron/expression/status/remark/createDate * 字段: id/beanName/methodName/params/cron/expression/status/remark/createDate
*/ */
@ -9,6 +11,8 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface Schedule { interface Schedule {
id: string id: string
@ -121,20 +125,18 @@ onMounted(load)
<template> <template>
<div class="rr-sys-schedule"> <div class="rr-sys-schedule">
<div class="rr-page-header"> <PageHeader title="定时任务" :sub="`共 ${total} 个任务`">
<div class="rr-page-titles">
<h2 class="rr-page-title">定时任务</h2>
<p class="rr-page-sub">共 {{ total }} 个定时任务</p>
</div>
<div class="rr-page-actions">
<el-button @click="onReset" class="rr-btn-secondary">重置</el-button> <el-button @click="onReset" class="rr-btn-secondary">重置</el-button>
</div> </PageHeader>
</div>
<div class="rr-filters-row"> <SearchBar
<el-input v-model="filters.beanName" placeholder="Bean 名搜索" clearable class="rr-bean-input" size="small" @keyup.enter="onSearch" /> v-model:filters="filters"
<el-button class="rr-btn-secondary" size="small" @click="onSearch">查询</el-button> :fields='[
</div> { key: "beanName", label: "Bean 名", type: "text", placeholder: "Bean 名" }
]'
@search="onSearch"
@reset="onReset"
/>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable
@ -180,6 +182,9 @@ onMounted(load)
<style scoped> <style scoped>
.rr-sys-schedule { padding: 16px; } .rr-sys-schedule { padding: 16px; }
.rr-list-card { background: var(--surface); border-radius: 12px; padding: 4px; }
.rr-time { font-family: 'SF Mono', Menlo, Monaco, Consolas, monospace; font-size: 12px; color: var(--ink-2); }
.rr-muted { color: var(--ink-3); font-size: 12px; }
.rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; } .rr-page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.rr-page-titles { display: flex; flex-direction: column; gap: 2px; } .rr-page-titles { display: flex; flex-direction: column; gap: 2px; }
.rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); } .rr-page-title { margin: 0; font-size: 18px; font-weight: 600; color: var(--el-text-color-primary); }

View File

@ -26,6 +26,8 @@ import { onMounted, ref, reactive } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request' import { httpGet, httpPost, httpPut, httpDelete } from '@/utils/request'
import DataTable from '@/components/DataTable/DataTable.vue' import DataTable from '@/components/DataTable/DataTable.vue'
import PageHeader from '@/components/PageHeader/PageHeader.vue'
import SearchBar from '@/components/SearchBar/SearchBar.vue'
interface SysUser { interface SysUser {
id: string id: string
@ -227,39 +229,18 @@ onMounted(() => { load() })
<template> <template>
<div class="rr-sys-user"> <div class="rr-sys-user">
<div class="rr-page-header"> <PageHeader title="后台用户" :sub="`共 ${total} 个用户`">
<div class="rr-page-titles">
<h2 class="rr-page-title">用户管理</h2>
<p class="rr-page-sub">共 {{ total }} 个用户(含 {{ USER_TYPE_MAP[99] ? USER_TYPE_MAP[99].label : 'AI公司' }} 账号)</p>
</div>
<div class="rr-page-actions">
<el-button @click="onReset" class="rr-btn-secondary">重置</el-button> <el-button @click="onReset" class="rr-btn-secondary">重置</el-button>
</div> </PageHeader>
</div>
<div class="rr-filters-row"> <SearchBar
<el-input v-model:filters="filters"
v-model="filters.username" :fields='[
placeholder="用户名搜索" { key: "username", label: "用户名", type: "text", placeholder: "用户名" }
clearable ]'
class="rr-username-input" @search="onSearch"
size="small" @reset="onReset"
@keyup.enter="onSearch"
/> />
<el-select
v-model="filters.userType"
placeholder="用户类型"
class="rr-type-select"
clearable
size="small"
>
<el-option value="1" label="试用期" />
<el-option value="2" label="正式员工" />
<el-option value="3" label="外包员工" />
<el-option value="99" label="AI 公司" />
</el-select>
<el-button class="rr-btn-secondary" size="small" @click="onSearch">查询</el-button>
</div>
<div class="rr-list-card"> <div class="rr-list-card">
<DataTable <DataTable