银行-产品经理列表等

V0.1
yujialong 1 year ago
parent adf5a0dec5
commit f2159083d7
  1. 4
      .env
  2. 8
      src/api/bank.ts
  3. 28
      src/api/system.ts
  4. BIN
      src/assets/images/7.png
  5. BIN
      src/assets/images/8.png
  6. BIN
      src/assets/images/9.png
  7. BIN
      src/assets/images/plus.png
  8. BIN
      src/assets/images/search.png
  9. BIN
      src/assets/images/search1.png
  10. 12
      src/layout/components/AppHeader.vue
  11. 7
      src/layout/components/Logo.vue
  12. 13
      src/router/index.ts
  13. 2
      src/store/useCurrentUser.ts
  14. 5
      src/styles/index.scss
  15. 42
      src/utils/auth.ts
  16. 7
      src/utils/request.ts
  17. 9
      src/views/Home.vue
  18. 196
      src/views/bankProduct/index.vue
  19. 238
      src/views/product/index.vue
  20. 79
      src/views/user/GroupList.vue
  21. 183
      src/views/user/UserList.vue

@ -1,7 +1,7 @@
VITE_APP_TITLE=金融产品设计及数字化营销沙盘
VITE_PORT=9520
VITE_PROXY=http://192.168.31.126:8080
VITE_PROXY=http://192.168.31.125:8080
VITE_PUBLIC_PATH=./
VITE_BASE_API=/api
VITE_BASE_API=http://192.168.31.217:9000
VITE_I18N_LOCALE=zh-cn
VITE_I18N_FALLBACK_LOCALE=zh-cn

@ -0,0 +1,8 @@
import axios from '@/utils/request';
export const queryStorageList = async (params?: Record<string, any>): Promise<any> => (await axios.get('/backend/core/storage', { params })).data;
export const queryStorage = async (id: number): Promise<any> => (await axios.get(`/backend/core/storage/${id}`)).data;
export const updateStorage = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/storage?_method=put', data)).data;
export const primaryTypeOfGuarantee = async (): Promise<any> => (await axios.post('/product/bankGuaranteeType/primaryTypeOfGuarantee')).data;
export const bankingProductsList = async (data: Record<string, any>): Promise<any> => (await axios.post('/product/product/bank/products/bankingProductsList', data)).data;

@ -1,28 +0,0 @@
import axios from '@/utils/request';
export const queryStorageList = async (params?: Record<string, any>): Promise<any> => (await axios.get('/backend/core/storage', { params })).data;
export const queryStorage = async (id: number): Promise<any> => (await axios.get(`/backend/core/storage/${id}`)).data;
export const createStorage = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/storage', data)).data;
export const updateStorage = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/storage?_method=put', data)).data;
export const updateStorageOrder = async (data: number[]): Promise<any> => (await axios.post('/backend/core/storage/order?_method=put', data)).data;
export const deleteStorage = async (data: number[]): Promise<any> => (await axios.post('/backend/core/storage?_method=delete', data)).data;
export const querySiteList = async (params?: Record<string, any>): Promise<any> => (await axios.get('/backend/core/site', { params })).data;
export const querySite = async (id: number): Promise<any> => (await axios.get(`/backend/core/site/${id}`)).data;
export const createSite = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/site', data)).data;
export const updateSite = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/site?_method=put', data)).data;
export const updateSiteOrder = async (data: number[]): Promise<any> => (await axios.post('/backend/core/site/order?_method=put', data)).data;
export const deleteSite = async (data: number[]): Promise<any> => (await axios.post('/backend/core/site?_method=delete', data)).data;
export const querySiteThemeList = async (id: number): Promise<any> => (await axios.get(`/backend/core/site/${id}/theme`)).data;
export const queryAttachmentPage = async (params?: Record<string, any>): Promise<any> => (await axios.get('/backend/core/attachment', { params })).data;
export const queryAttachment = async (id: number): Promise<any> => (await axios.get(`/backend/core/attachment/${id}`)).data;
export const createAttachment = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/attachment', data)).data;
export const updateAttachment = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/attachment?_method=put', data)).data;
export const deleteAttachment = async (data: number[]): Promise<any> => (await axios.post('/backend/core/attachment?_method=delete', data)).data;
export const queryTaskPage = async (params?: Record<string, any>): Promise<any> => (await axios.get('/backend/core/task', { params })).data;
export const queryTask = async (id: number): Promise<any> => (await axios.get(`/backend/core/task/${id}`)).data;
export const createTask = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/task', data)).data;
export const updateTask = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/task?_method=put', data)).data;
export const deleteTask = async (data: number[]): Promise<any> => (await axios.post('/backend/core/task?_method=delete', data)).data;

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

@ -19,7 +19,7 @@
import { ref, onMounted, computed } from 'vue';
import { setCookieLocale, getSessionSiteId, setSessionSiteId } from '@/utils/common';
import { toTree, flatTree } from '@/utils/tree';
import { querySiteList } from '@/api/system';
// import { querySiteList } from '@/api/bank';
import { currentUser, perm, logout } from '@/store/useCurrentUser';
import { appState, toggleSidebar } from '@/store/useAppState';
import Logo from './Logo.vue';
@ -28,10 +28,10 @@ const siteId = ref<number | null>(getSessionSiteId());
const siteList = ref<any[]>([]);
const site = computed(() => siteList.value.find((item) => item.id === siteId.value));
const fetchSiteList = async () => {
siteList.value = flatTree(toTree(await querySiteList()));
if (siteId.value == null) {
siteId.value = siteList.value[0]?.id;
}
// siteList.value = flatTree(toTree(await querySiteList()));
// if (siteId.value == null) {
// siteId.value = siteList.value[0]?.id;
// }
};
const changeSiteId = (id: number) => {
setSessionSiteId(id);
@ -39,7 +39,7 @@ const changeSiteId = (id: number) => {
window.location.reload();
};
onMounted(() => {
fetchSiteList();
// fetchSiteList();
});
const handleLogout = () => {

@ -1,9 +1,7 @@
<template>
<div class="flex items-center justify-center overflow-hidden">
<router-link class="whitespace-nowrap text-center"
to="/">
<h1 v-if="!collapse"
class="ml-1 text-[22px] leading-[1] font-bold text-[#333]">{{ title }}</h1>
<router-link class="whitespace-nowrap text-center" to="/">
<h1 v-if="!collapse" class="ml-1 text-[22px] leading-[1] font-bold text-[#333]">{{ title }}</h1>
</router-link>
</div>
</template>
@ -23,7 +21,6 @@ export default defineComponent({
data() {
return {
title: Settings.title,
logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png',
};
},
});

@ -8,18 +8,25 @@ declare module 'vue-router' {
hidden?: boolean;
title?: string;
icon?: Component;
requiresPermission?: string;
// requiresPermission?: string;
}
}
export const routes: Array<RouteRecordRaw> = [
// { path: '/login', component: () => import('@/views/Login.vue'), meta: { hidden: true } },
// { path: '/product', component: () => import('@/views/product/index.vue'), meta: { hidden: true } },
{ path: '/404', component: () => import('@/views/404.vue'), meta: { hidden: true } },
{ path: '/403', component: () => import('@/views/403.vue'), meta: { hidden: true } },
{
path: '',
component: Layout,
meta: { hidden: true },
children: [{ path: '', component: () => import('@/views/Home.vue'), meta: { title: 'menu.home', requiresPermission: 'auth' } }],
children: [{ path: '', component: () => import('@/views/Home.vue'), meta: { title: 'menu.home' } }],
},
{
path: '/product',
redirect: '/product/index',
component: Layout,
meta: { title: '产品经理', icon: UserFilled },
children: [{ path: 'index', component: () => import('@/views/product/index.vue'), meta: { title: '产品经理' } }],
},
// 404 page must be placed at the end !!!
{

@ -14,7 +14,6 @@ import {
setSessionTimeout,
removeSessionTimeout,
removeRefreshToken,
removeAccessAt,
removeRefreshAt,
} from '@/utils/auth';
@ -49,7 +48,6 @@ export const login = async (params: LoginParam): Promise<any> => {
};
export const logout = (): void => {
removeAccessAt();
removeRefreshAt();
removeAccessToken();
removeRefreshToken();

@ -16,8 +16,9 @@ body {
}
// global css
.app-block {
@apply shadow-sm;
.block {
@apply p-5;
@apply rounded-lg;
@apply bg-white;
}

@ -1,58 +1,56 @@
import Cookies from 'js-cookie';
const JWT_ACCESS_TOKEN = 'jwt-access-token';
const JWT_ACCESS_AT = 'jwt-access-at';
const JWT_REFRESH_TOKEN = 'jwt-refresh-token';
const JWT_REFRESH_AT = 'jwt-refresh-at';
const JWT_SESSION_TIMEOUT = 'jwt-session-timeout';
const SAND_ACCESS_TOKEN = 'sand-token';
const SAND_ACCESS_AT = 'jwt-access-at';
const SAND_REFRESH_TOKEN = 'jwt-refresh-token';
const SAND_REFRESH_AT = 'jwt-refresh-at';
const SAND_SESSION_TIMEOUT = 'jwt-session-timeout';
export const getAccessToken = (): string | undefined => Cookies.get(JWT_ACCESS_TOKEN);
export const getAccessToken = (): string | undefined => Cookies.get(SAND_ACCESS_TOKEN);
export const setAccessToken = (token: string): void => {
Cookies.set(JWT_ACCESS_TOKEN, token);
Cookies.set(SAND_ACCESS_TOKEN, token);
};
export const removeAccessToken = (): void => Cookies.remove(JWT_ACCESS_TOKEN);
export const removeAccessToken = (): void => Cookies.remove(SAND_ACCESS_TOKEN);
export const getRefreshToken = (): string | undefined => Cookies.get(JWT_REFRESH_TOKEN);
export const getRefreshToken = (): string | undefined => Cookies.get(SAND_REFRESH_TOKEN);
export const setRefreshToken = (token: string): void => {
Cookies.set(JWT_REFRESH_TOKEN, token);
Cookies.set(SAND_REFRESH_TOKEN, token);
};
export const removeRefreshToken = (): void => {
Cookies.remove(JWT_REFRESH_TOKEN);
Cookies.remove(SAND_REFRESH_TOKEN);
};
export const getRefreshAt = (): number => {
const refreshAt = Cookies.get(JWT_REFRESH_AT);
const refreshAt = Cookies.get(SAND_REFRESH_AT);
return refreshAt ? Number(refreshAt) : 0;
};
export const setRefreshAt = (refreshAt: number): void => {
Cookies.set(JWT_REFRESH_AT, String(refreshAt));
Cookies.set(SAND_REFRESH_AT, String(refreshAt));
};
export const removeRefreshAt = (): void => {
Cookies.remove(JWT_REFRESH_AT);
Cookies.remove(SAND_REFRESH_AT);
};
export const getAccessAt = (): number => {
const accessAt = Cookies.get(JWT_ACCESS_AT);
const accessAt = Cookies.get(SAND_ACCESS_AT);
return accessAt ? Number(accessAt) : 0;
};
export const setAccessAt = (accessAt: number): void => {
Cookies.set(JWT_ACCESS_AT, String(accessAt));
Cookies.set(SAND_ACCESS_AT, String(accessAt));
};
export const removeAccessAt = () => Cookies.remove(JWT_ACCESS_AT);
export const getSessionTimeout = (): number => {
const sessionTimeout = Cookies.get(JWT_SESSION_TIMEOUT);
const sessionTimeout = Cookies.get(SAND_SESSION_TIMEOUT);
// 默认 30 分钟
return sessionTimeout ? Number(sessionTimeout) : 30;
};
export const setSessionTimeout = (sessionTimeout: number): void => {
Cookies.set(JWT_SESSION_TIMEOUT, String(sessionTimeout));
Cookies.set(SAND_SESSION_TIMEOUT, String(sessionTimeout));
};
export const removeSessionTimeout = (): void => {
Cookies.remove(JWT_SESSION_TIMEOUT);
Cookies.remove(SAND_SESSION_TIMEOUT);
};
export const getAuthHeaders = (): any => {
const accessToken = getAccessToken();
return { Authorization: accessToken ? `Bearer ${accessToken}` : '' };
return { token: getAccessToken() };
};

@ -15,7 +15,7 @@ service.interceptors.request.use(
(config) => {
setAccessAt(new Date().getTime());
// eslint-disable-next-line
config.headers = { ...config.headers, ...getAuthHeaders(), ...getSiteHeaders() };
config.headers = { ...config.headers, ...getAuthHeaders() };
return config;
},
(error) => Promise.reject(error),
@ -30,12 +30,11 @@ service.interceptors.response.use(
status,
},
} = e;
console.log('🚀 ~ file: request.ts:27 ~ e:', e, status, message);
const {
global: { t },
} = i18n;
if (exception === 'com.ujcms.core.exception.LogicException') {
ElMessageBox.alert(message, { type: 'warning' });
} else if (status === 401) {
if (status === 401) {
ElMessageBox.confirm(t('confirmLogin'), { confirmButtonText: t('loginAgain'), type: 'warning' }).then(() => {
// 未登录。刷新页面以触发登录。无法直接使用router,会导致其它函数不可用的奇怪问题。
window.location.reload();

@ -1,9 +1,12 @@
<template>
<div>
<div class="app-block p-3 flex">
<div class="block p-3 flex">
<div>
<el-avatar :size="76" class="flex justify-center items-center">
<el-icon class="text-5xl"><avatar /></el-icon>
<el-avatar :size="76"
class="flex justify-center items-center">
<el-icon class="text-5xl">
<avatar />
</el-icon>
</el-avatar>
</div>
<div class="ml-3 space-y-1 text-gray-regular text-sm">

@ -0,0 +1,196 @@
<template>
<div>
<div class="filter block">
<dl>
<dt>担保方式</dt>
<div class="vals">
<dd v-for="(item, i) in methods"
:key="i"
:class="{ active: method === item.id }"
@click="filterClick(item, 'method')">{{ item.name }}</dd>
</div>
</dl>
<dl>
<dt>产品进度</dt>
<div class="vals">
<dd v-for="(item, i) in methods"
:key="i"
:class="{ active: method === item.id }"
@click="filterClick(item, 'method')">{{ item.name }}</dd>
</div>
</dl>
</div>
<div class="block mt-3">
<div class="search">
<input type="text"
placeholder="搜索"
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
</div>
<el-table ref="table"
v-loading="loading"
:data="data"
@selection-change="(rows) => (selection = rows)"
@sort-change="handleSort">
<el-table-column type="selection"
:selectable="deletable"
width="50"></el-table-column>
<el-table-column property="id"
label="ID"
width="64"
sortable="custom"></el-table-column>
</el-table>
<el-pagination v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:page-sizes="pageSizes"
:layout="pageLayout"
@size-change="fetchData()"
@current-change="fetchData()"
small
background
class="px-3 py-2 justify-end"></el-pagination>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { ElMessage } from 'element-plus';
import { Search } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import dayjs from 'dayjs';
import { perm } from '@/store/useCurrentUser';
import { pageSizes, pageLayout, toParams, resetParams } from '@/utils/common';
import { deleteUser, queryUserPage } from '@/api/user';
const { t } = useI18n();
const params = ref<any>({});
const sort = ref<any>();
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);
const total = ref<number>(0);
const table = ref<any>();
const method = ref<any>('');
const methods = ref<Array<any>>([
{
id: '',
name: '不限',
},
{
id: 1,
name: '信用贷',
},
{
id: 2,
name: '信用贷',
},
]);
const data = ref<Array<any>>([]);
const selection = ref<Array<any>>([]);
const loading = ref<boolean>(false);
const beanId = ref<number>();
const fetchData = async () => {
loading.value = true;
try {
const { content, totalElements } = await queryUserPage({ ...toParams(params.value), Q_OrderBy: sort.value, page: currentPage.value, pageSize: pageSize.value });
data.value = content;
total.value = totalElements;
} finally {
loading.value = false;
}
};
// onMounted(fetchData);
const handleSort = ({ column, prop, order }: { column: any; prop: string; order: string }) => {
if (prop) {
sort.value = (column.sortBy ?? prop) + (order === 'descending' ? '_desc' : '');
} else {
sort.value = undefined;
}
fetchData();
};
const handleSearch = () => fetchData();
const handleReset = () => {
table.value.clearSort();
resetParams(params.value);
sort.value = undefined;
fetchData();
};
const handleAdd = () => {
beanId.value = undefined;
};
const handleEdit = (id: number) => {
beanId.value = id;
};
const handleDelete = async (ids: number[]) => {
await deleteUser(ids);
fetchData();
ElMessage.success(t('success'));
};
const deletable = (bean: any) => bean.id > 1;
</script>
<style lang="scss" scoped>
.filter {
dl {
display: flex;
flex-wrap: wrap;
align-items: center;
margin-bottom: 17px;
&:last-child {
margin-bottom: 0;
}
dt,
dd {
font-size: 14px;
font-family: MiSans;
color: #333;
}
.vals {
display: inline-flex;
flex-wrap: wrap;
align-items: center;
margin-left: 10px;
}
dd {
padding: 6px 10px;
margin-right: 10px;
cursor: pointer;
}
.active {
color: #fff;
background: #006bff;
border-radius: 4px;
}
}
}
.search {
position: relative;
width: 320px;
padding: 0 12px;
background-color: #f6f8fc;
border-radius: 8px;
input {
width: 90%;
height: 36px;
font-size: 14px;
line-height: 36px;
color: #333;
border: 0;
background-color: transparent;
&:focus {
outline: none;
}
}
.icon {
position: absolute;
top: 9px;
right: 12px;
cursor: pointer;
}
}
</style>

@ -0,0 +1,238 @@
<template>
<div>
<div class="block">
<div class="flex justify-between items-center mb-5">
<div class="search">
<input type="text"
placeholder="搜索"
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
</div>
<div class="filter">
<div class="select">
<el-select v-model="guarantyStyleId"
placeholder="担保方式"
size="large">
<el-option label="担保方式"
value="" />
<el-option v-for="item in guarantees"
:key="item.id"
:label="item.guarantyStyle"
:value="item.id" />
</el-select>
<img src="@/assets/images/7.png"
alt=""
class="icon" />
</div>
<div class="select">
<el-select v-model="pace"
placeholder="产品进度"
size="large">
<el-option v-for="item in paces"
:key="item.id"
:label="item.name"
:value="item.id" />
</el-select>
<img src="@/assets/images/8.png"
alt=""
class="icon" />
</div>
<div class="add-btn">
<img src="@/assets/images/plus.png"
alt=""
class="icon" />
新增产品
</div>
<img src="@/assets/images/9.png"
alt=""
class="ml-4 cursor-pointer" />
</div>
</div>
<el-table ref="table"
v-loading="loading"
:data="list"
@sort-change="handleSort">
<el-table-column prop="id"
label="产品名称"></el-table-column>
<el-table-column prop="id"
label="产品编号"></el-table-column>
<el-table-column prop="id"
label="担保方式"></el-table-column>
<el-table-column prop="id"
label="最高额度/年利率/期限"></el-table-column>
<el-table-column prop="id"
label="创建日期"></el-table-column>
<el-table-column prop="id"
label="产品进度"></el-table-column>
<el-table-column prop="id"
label="操作">
<template #default="{ row }">
<el-button type="text"
@click="handleEdit(row.id)"
size="small">配置要素</el-button>
<el-button type="text"
@click="handleEdit(row.id)"
size="small">产品详情</el-button>
<el-button type="text"
@click="handleEdit(row.id)"
size="small">删除</el-button>
</template></el-table-column>
</el-table>
<el-pagination v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:page-sizes="pageSizes"
:layout="pageLayout"
@size-change="fetchData()"
@current-change="fetchData()"
small
background
class="px-3 py-2 justify-end"></el-pagination>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue';
import { ElMessage } from 'element-plus';
import { Search } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import dayjs from 'dayjs';
import { perm } from '@/store/useCurrentUser';
import { pageSizes, pageLayout, toParams, resetParams } from '@/utils/common';
import { primaryTypeOfGuarantee, bankingProductsList } from '@/api/bank';
const { t } = useI18n();
const params = ref<any>({
createDateSort: '',
guarantyStyleId: '',
keyWord: '',
productType: '',
status: '',
});
const sort = ref<any>();
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);
const total = ref<number>(0);
const table = ref<any>();
const guarantyStyleId = ref<any>('');
const guarantees = ref<Array<any>>([]);
const pace = ref<any>('');
const paces = ref<Array<any>>([]);
const list = ref<Array<any>>([]);
const selection = ref<Array<any>>([]);
const loading = ref<boolean>(false);
const beanId = ref<number>();
//
const getGuarantee = async () => {
try {
const { data } = await primaryTypeOfGuarantee();
guarantees.value = data;
} finally {
}
};
//
const fetchData = async () => {
loading.value = true;
try {
const { data } = await bankingProductsList({ pageNum: currentPage.value, pageSize: pageSize.value, ...toParams(params.value) });
list.value = data.message.records;
total.value = data.message.total;
} finally {
loading.value = false;
}
};
onMounted(() => {
getGuarantee();
fetchData();
});
const handleSort = ({ column, prop, order }: { column: any; prop: string; order: string }) => {
if (prop) {
sort.value = (column.sortBy ?? prop) + (order === 'descending' ? '_desc' : '');
} else {
sort.value = undefined;
}
fetchData();
};
const handleSearch = () => fetchData();
const handleAdd = () => {
beanId.value = undefined;
};
const handleEdit = (id: number) => {
beanId.value = id;
};
const handleDelete = async (ids: number[]) => {
await deleteUser(ids);
fetchData();
ElMessage.success(t('success'));
};
const deletable = (bean: any) => bean.id > 1;
</script>
<style lang="scss" scoped>
.search {
display: flex;
align-items: center;
width: 300px;
padding: 0 24px;
background-color: #fff;
border: 1px solid #dfe9f8;
border-radius: 18px;
input {
width: 230px;
height: 36px;
margin-right: 10px;
font-size: 14px;
line-height: 36px;
color: #333;
border: 0;
background-color: transparent;
&:focus {
outline: none;
}
}
.icon {
cursor: pointer;
}
}
.filter {
display: inline-flex;
align-items: center;
.select {
position: relative;
margin-right: 12px;
.icon {
position: absolute;
top: 12px;
left: 20px;
}
:deep(.el-select) {
width: 170px;
.el-input__inner {
padding-left: 41px;
border-radius: 18px;
border-color: #dfe9f8;
}
}
}
.add-btn {
display: inline-flex;
align-items: center;
height: 36px;
padding: 0 24px;
font-size: 14px;
color: #fff;
background: linear-gradient(-36deg, #006bff, #2ab1ff);
border: 1px solid #ffffff;
border-radius: 18px;
cursor: pointer;
.icon {
margin-right: 8px;
}
}
}
</style>

@ -1,35 +1,73 @@
<template>
<div>
<div class="mb-3">
<query-form :params="params" @search="handleSearch" @reset="handleReset">
<query-item :label="$t('group.name')" name="Q_Contains_name"></query-item>
<query-item :label="$t('group.description')" name="Q_Contains_description"></query-item>
<query-form :params="params"
@search="handleSearch"
@reset="handleReset">
<query-item :label="$t('group.name')"
name="Q_Contains_name"></query-item>
<query-item :label="$t('group.description')"
name="Q_Contains_description"></query-item>
</query-form>
</div>
<div>
<el-button type="primary" :disabled="perm('group:create')" :icon="Plus" @click="handleAdd">{{ $t('add') }}</el-button>
<el-popconfirm :title="$t('confirmDelete')" @confirm="handleDelete(selection.map((row) => row.id))">
<el-button type="primary"
:disabled="perm('group:create')"
:icon="Plus"
@click="handleAdd">{{ $t('add') }}</el-button>
<el-popconfirm :title="$t('confirmDelete')"
@confirm="handleDelete(selection.map((row) => row.id))">
<template #reference>
<el-button :disabled="selection.filter((row) => deletable(row.id)).length <= 0 || perm('group:delete')" :icon="Delete">{{ $t('delete') }}</el-button>
<el-button :disabled="selection.filter((row) => deletable(row.id)).length <= 0 || perm('group:delete')"
:icon="Delete">{{ $t('delete') }}</el-button>
</template>
</el-popconfirm>
<list-move class="ml-2" :disabled="selection.length <= 0 || filtered || perm('org:update')" @move="(type) => move(selection, type)" />
<column-setting name="group" class="ml-2" />
<list-move class="ml-2"
:disabled="selection.length <= 0 || filtered || perm('org:update')"
@move="(type) => move(selection, type)" />
<column-setting name="group"
class="ml-2" />
</div>
<div class="app-block mt-3">
<el-table ref="table" v-loading="loading" :data="data" @selection-change="(rows) => (selection = rows)" @row-dblclick="(row) => handleEdit(row.id)" @sort-change="handleSort">
<div class="block mt-3">
<el-table ref="table"
v-loading="loading"
:data="data"
@selection-change="(rows) => (selection = rows)"
@row-dblclick="(row) => handleEdit(row.id)"
@sort-change="handleSort">
<column-list name="group">
<el-table-column type="selection" width="50"></el-table-column>
<el-table-column property="id" label="ID" width="64" sortable="custom"></el-table-column>
<el-table-column property="name" :label="$t('group.name')" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column property="description" :label="$t('group.description')" min-width="150" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column property="type" :label="$t('group.type')" sortable="custom" show-overflow-tooltip :formatter="(row) => $t(`group.type.${row.type}`)" />
<el-table-column type="selection"
width="50"></el-table-column>
<el-table-column property="id"
label="ID"
width="64"
sortable="custom"></el-table-column>
<el-table-column property="name"
:label="$t('group.name')"
sortable="custom"
show-overflow-tooltip></el-table-column>
<el-table-column property="description"
:label="$t('group.description')"
min-width="150"
sortable="custom"
show-overflow-tooltip></el-table-column>
<el-table-column property="type"
:label="$t('group.type')"
sortable="custom"
show-overflow-tooltip
:formatter="(row) => $t(`group.type.${row.type}`)" />
<el-table-column :label="$t('table.action')">
<template #default="{ row }">
<el-button type="text" :disabled="perm('group:update')" @click="handleEdit(row.id)" size="small">{{ $t('edit') }}</el-button>
<el-popconfirm :title="$t('confirmDelete')" @confirm="handleDelete([row.id])">
<el-button type="text"
:disabled="perm('group:update')"
@click="handleEdit(row.id)"
size="small">{{ $t('edit') }}</el-button>
<el-popconfirm :title="$t('confirmDelete')"
@confirm="handleDelete([row.id])">
<template #reference>
<el-button type="text" :disabled="!deletable(row.id) || perm('group:delete')" size="small">{{ $t('delete') }}</el-button>
<el-button type="text"
:disabled="!deletable(row.id) || perm('group:delete')"
size="small">{{ $t('delete') }}</el-button>
</template>
</el-popconfirm>
</template>
@ -37,7 +75,10 @@
</column-list>
</el-table>
</div>
<group-form v-model="formVisible" :beanId="beanId" :beanIds="beanIds" @finished="fetchData" />
<group-form v-model="formVisible"
:beanId="beanId"
:beanIds="beanIds"
@finished="fetchData" />
</div>
</template>

@ -1,77 +1,176 @@
<template>
<div>
<div class="mb-3">
<query-form :params="params" @search="handleSearch" @reset="handleReset">
<query-item :label="$t('user.username')" name="Q_Contains_username"></query-item>
<query-item :label="$t('user.mobile')" name="Q_Contains_mobile"></query-item>
<query-item :label="$t('user.email')" name="Q_Contains_email"></query-item>
<query-item :label="$t('user.rank')" name="Q_GE_rank,Q_LE_rank" type="number"></query-item>
<query-item :label="$t('user.created')" name="Q_GE_@userExt-created_DateTime,Q_LE_@userExt-created_DateTime" type="datetime"></query-item>
<query-item :label="$t('user.status')" name="Q_In_status_Int" :options="[0, 1].map((item) => ({ label: $t(`user.status.${item}`), value: item }))"></query-item>
<query-form :params="params"
@search="handleSearch"
@reset="handleReset">
<query-item :label="$t('user.username')"
name="Q_Contains_username"></query-item>
<query-item :label="$t('user.mobile')"
name="Q_Contains_mobile"></query-item>
<query-item :label="$t('user.email')"
name="Q_Contains_email"></query-item>
<query-item :label="$t('user.rank')"
name="Q_GE_rank,Q_LE_rank"
type="number"></query-item>
<query-item :label="$t('user.created')"
name="Q_GE_@userExt-created_DateTime,Q_LE_@userExt-created_DateTime"
type="datetime"></query-item>
<query-item :label="$t('user.status')"
name="Q_In_status_Int"
:options="[0, 1].map((item) => ({ label: $t(`user.status.${item}`), value: item }))"></query-item>
</query-form>
</div>
<div>
<el-button type="primary" :icon="Plus" @click="handleAdd">{{ $t('add') }}</el-button>
<el-popconfirm :title="$t('confirmDelete')" @confirm="handleDelete(selection.map((row) => row.id))">
<el-button type="primary"
:icon="Plus"
@click="handleAdd">{{ $t('add') }}</el-button>
<el-popconfirm :title="$t('confirmDelete')"
@confirm="handleDelete(selection.map((row) => row.id))">
<template #reference>
<el-button :disabled="selection.length <= 0 || perm('user:delete')" :icon="Delete">{{ $t('delete') }}</el-button>
<el-button :disabled="selection.length <= 0 || perm('user:delete')"
:icon="Delete">{{ $t('delete') }}</el-button>
</template>
</el-popconfirm>
<column-setting name="user" class="ml-2" />
<column-setting name="user"
class="ml-2" />
</div>
<div class="app-block mt-3">
<el-table ref="table" v-loading="loading" :data="data" @selection-change="(rows) => (selection = rows)" @row-dblclick="(row) => handleEdit(row.id)" @sort-change="handleSort">
<div class="block mt-3">
<el-table ref="table"
v-loading="loading"
:data="data"
@selection-change="(rows) => (selection = rows)"
@row-dblclick="(row) => handleEdit(row.id)"
@sort-change="handleSort">
<column-list name="user">
<el-table-column type="selection" :selectable="deletable" width="50"></el-table-column>
<el-table-column property="id" label="ID" width="64" sortable="custom"></el-table-column>
<el-table-column property="username" :label="$t('user.username')" sortable="custom" min-width="100"></el-table-column>
<el-table-column property="mobile" :label="$t('user.mobile')" sortable="custom" display="none" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column property="email" :label="$t('user.email')" sortable="custom" display="none" min-width="100" show-overflow-tooltip></el-table-column>
<el-table-column property="realName" :label="$t('user.realName')" sort-by="@userExt-realName" sortable="custom" min-width="100" show-overflow-tooltip />
<el-table-column property="gender" :label="$t('user.gender')" sort-by="@userExt-gender" sortable="custom" display="none">
<el-table-column type="selection"
:selectable="deletable"
width="50"></el-table-column>
<el-table-column property="id"
label="ID"
width="64"
sortable="custom"></el-table-column>
<el-table-column property="username"
:label="$t('user.username')"
sortable="custom"
min-width="100"></el-table-column>
<el-table-column property="mobile"
:label="$t('user.mobile')"
sortable="custom"
display="none"
min-width="100"
show-overflow-tooltip></el-table-column>
<el-table-column property="email"
:label="$t('user.email')"
sortable="custom"
display="none"
min-width="100"
show-overflow-tooltip></el-table-column>
<el-table-column property="realName"
:label="$t('user.realName')"
sort-by="@userExt-realName"
sortable="custom"
min-width="100"
show-overflow-tooltip />
<el-table-column property="gender"
:label="$t('user.gender')"
sort-by="@userExt-gender"
sortable="custom"
display="none">
<template #default="{ row }">{{ $t(`gender.${row.gender}`) }}</template>
</el-table-column>
<el-table-column property="created" :label="$t('user.created')" sort-by="@userExt-created" sortable="custom" display="none" width="170">
<el-table-column property="created"
:label="$t('user.created')"
sort-by="@userExt-created"
sortable="custom"
display="none"
width="170">
<template #default="{ row }">{{ dayjs(row.created).format('YYYY-MM-DD HH:mm:ss') }}</template>
</el-table-column>
<el-table-column property="birthday" :label="$t('user.birthday')" sort-by="@userExt-birthday" sortable="custom" display="none" width="110">
<el-table-column property="birthday"
:label="$t('user.birthday')"
sort-by="@userExt-birthday"
sortable="custom"
display="none"
width="110">
<template #default="{ row }">{{ dayjs(row.birthday).format('YYYY-MM-DD') }}</template>
</el-table-column>
<el-table-column property="loginDate" :label="$t('user.loginDate')" sort-by="@userExt-loginDate" sortable="custom" display="none" width="170">
<el-table-column property="loginDate"
:label="$t('user.loginDate')"
sort-by="@userExt-loginDate"
sortable="custom"
display="none"
width="170">
<template #default="{ row }">{{ dayjs(row.loginDate).format('YYYY-MM-DD HH:mm:ss') }}</template>
</el-table-column>
<el-table-column property="loginIp" :label="$t('user.loginIp')" sort-by="@userExt-loginIp" sortable="custom" display="none" show-overflow-tooltip />
<el-table-column property="loginCount" :label="$t('user.loginCount')" sort-by="@userExt-loginCount" sortable="custom" display="none" show-overflow-tooltip />
<el-table-column property="org.name" :label="$t('user.org')" sort-by="org-name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column property="roles" :label="$t('user.role')" show-overflow-tooltip>
<el-table-column property="loginIp"
:label="$t('user.loginIp')"
sort-by="@userExt-loginIp"
sortable="custom"
display="none"
show-overflow-tooltip />
<el-table-column property="loginCount"
:label="$t('user.loginCount')"
sort-by="@userExt-loginCount"
sortable="custom"
display="none"
show-overflow-tooltip />
<el-table-column property="org.name"
:label="$t('user.org')"
sort-by="org-name"
sortable="custom"
show-overflow-tooltip></el-table-column>
<el-table-column property="roles"
:label="$t('user.role')"
show-overflow-tooltip>
<template #default="{ row }">
<el-space>
<span v-for="item in row.roleList" :key="item.id">{{ item.name }}</span>
<span v-for="item in row.roleList"
:key="item.id">{{ item.name }}</span>
</el-space>
</template>
</el-table-column>
<el-table-column property="group.name" :label="$t('user.group')" sort-by="group-name" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column property="rank" :label="$t('user.rank')" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column property="status" :label="$t('user.status')" sortable="custom" show-overflow-tooltip>
<el-table-column property="group.name"
:label="$t('user.group')"
sort-by="group-name"
sortable="custom"
show-overflow-tooltip></el-table-column>
<el-table-column property="rank"
:label="$t('user.rank')"
sortable="custom"
show-overflow-tooltip></el-table-column>
<el-table-column property="status"
:label="$t('user.status')"
sortable="custom"
show-overflow-tooltip>
<template #default="{ row }">
<el-tag v-if="row.status === 0" type="success" size="small">{{ $t(`user.status.${row.status}`) }}</el-tag>
<el-tag v-if="row.status === 1" type="danger" size="small">{{ $t(`user.status.${row.status}`) }}</el-tag>
<el-tag v-if="row.status === 0"
type="success"
size="small">{{ $t(`user.status.${row.status}`) }}</el-tag>
<el-tag v-if="row.status === 1"
type="danger"
size="small">{{ $t(`user.status.${row.status}`) }}</el-tag>
</template>
</el-table-column>
<el-table-column :label="$t('table.action')">
<template #default="{ row }">
<el-button type="text" @click="handleEdit(row.id)" :disabled="perm('user:show')" size="small">{{ $t('edit') }}</el-button>
<el-popconfirm :title="$t('confirmDelete')" @confirm="handleDelete([row.id])">
<el-button type="text"
@click="handleEdit(row.id)"
:disabled="perm('user:show')"
size="small">{{ $t('edit') }}</el-button>
<el-popconfirm :title="$t('confirmDelete')"
@confirm="handleDelete([row.id])">
<template #reference>
<el-button type="text" :disabled="!deletable(row) || perm('user:delete')" size="small">{{ $t('delete') }}</el-button>
<el-button type="text"
:disabled="!deletable(row) || perm('user:delete')"
size="small">{{ $t('delete') }}</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</column-list>
</el-table>
<el-pagination
v-model:currentPage="currentPage"
<el-pagination v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:page-sizes="pageSizes"
@ -80,10 +179,12 @@
@current-change="fetchData()"
small
background
class="px-3 py-2 justify-end"
></el-pagination>
class="px-3 py-2 justify-end"></el-pagination>
</div>
<user-form v-model="formVisible" :beanId="beanId" :beanIds="beanIds" @finished="fetchData" />
<user-form v-model="formVisible"
:beanId="beanId"
:beanIds="beanIds"
@finished="fetchData" />
</div>
</template>

Loading…
Cancel
Save