feat: 更新和原型图一致
parent
6602e58d19
commit
1496a8b5b9
|
@ -7,5 +7,6 @@ NODE_ENV = 'development'
|
|||
|
||||
# 本地环境接口地址
|
||||
# 如果没有跨域问题,直接在这里配置即可
|
||||
VITE_APP_BASE_API = 'http://192.168.1.116:8080'
|
||||
# VITE_APP_BASE_API = 'http://192.168.1.116:8080'
|
||||
VITE_APP_BASE_API = 'http://121.41.36.72:8080'
|
||||
# VITE_APP_BASE_API = 'https://3lp9319797lh.vicp.fun'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { PageRowsResult, PageRowsType } from '@/types';
|
||||
import { ApiManageType, StatisticsType } from '@/types/help';
|
||||
import { PageRowsResult } from '@/types';
|
||||
import { ApiManagePageType, ApiManageType, StatisticsType } from '@/types/help';
|
||||
import http from '@/utils/request';
|
||||
|
||||
// api接口
|
||||
|
@ -9,6 +9,7 @@ const api = {
|
|||
apiPage: '/cargo/api/page', // 分页列表
|
||||
apiSave: '/cargo/api/save', // 保存
|
||||
statistics: '/cargo/statistics/', // 首页数据统计
|
||||
adImage: '/cargo/adver/image', // 广告图
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -31,10 +32,10 @@ export function postApiGetAPI(data: { id: number | string }) {
|
|||
|
||||
/**
|
||||
* 分页列表
|
||||
* @param {PageRowsType} data 查询条件
|
||||
* @param {ApiManagePageType} data 查询条件
|
||||
* @return 返回请求分页列表接口的结果
|
||||
*/
|
||||
export function postApiPageAPI(data: Partial<PageRowsType>) {
|
||||
export function postApiPageAPI(data: Partial<ApiManagePageType>) {
|
||||
return http.post<PageRowsResult<ApiManageType>>(api.apiPage, data);
|
||||
}
|
||||
|
||||
|
@ -54,3 +55,11 @@ export function postApiSaveAPI(data: Partial<ApiManageType>) {
|
|||
export function getStatisticsAPI() {
|
||||
return http.get<StatisticsType>(api.statistics);
|
||||
}
|
||||
|
||||
/**
|
||||
* 广告图
|
||||
* @return 返回接口的结果
|
||||
*/
|
||||
export function getAdImageAPI() {
|
||||
return http.get<string>(api.adImage);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { PageRowsResult } from '@/types';
|
||||
import { BoatInfoPageType, BoatInfoType } from '@/types/boatInfo';
|
||||
import { BoatInfoPageType, BoatInfoType, vinSearchType } from '@/types/boatInfo';
|
||||
import http from '@/utils/request';
|
||||
|
||||
// api接口
|
||||
|
@ -10,7 +10,10 @@ const api = {
|
|||
sailScheduleSave: '/cargo/sail_schedule/save', // 保存
|
||||
sailScheduleTmpExport: '/cargo/sail_schedule/tmp/export', // 船期模板下载
|
||||
sailScheduleImport: '/cargo/sail_schedule/import', // 导入
|
||||
historyList: '/cargo/sail_schedule/history/page', // 历史数据
|
||||
sailScheduleExport: '/cargo/sail_schedule/export', // 船期导出
|
||||
publishHistoryList: '/cargo/sail_schedule/history/publish/page', // 我发布的历史数据
|
||||
receiveHistoryList: '/cargo/sail_schedule/history/receive/page', // 我接受的历史数据
|
||||
vinSearch: '/cargo/sail_schedule/vin/query', // 车架号查询
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -73,10 +76,39 @@ export function getSailScheduleImportAPI(data: { file: File }) {
|
|||
}
|
||||
|
||||
/**
|
||||
* 历史数据
|
||||
* 船期导出
|
||||
* @param {BoatInfoPageType} data 分页信息
|
||||
* @return 返回请求分页列表接口的结果
|
||||
*/
|
||||
export function getHistoryListAPI(data: Partial<BoatInfoPageType>) {
|
||||
return http.post<PageRowsResult<BoatInfoType>>(api.historyList, data);
|
||||
export function getSailScheduleExportAPI(data: Partial<BoatInfoPageType>) {
|
||||
return http.get<ArrayBuffer>(api.sailScheduleExport, data, {
|
||||
responseType: 'arraybuffer',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 我发布的历史数据
|
||||
* @param {BoatInfoPageType} data 分页信息
|
||||
* @return 返回请求分页列表接口的结果
|
||||
*/
|
||||
export function getPublishHistoryListAPI(data: Partial<BoatInfoPageType>) {
|
||||
return http.post<PageRowsResult<BoatInfoType>>(api.publishHistoryList, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 我接受的历史数据
|
||||
* @param {BoatInfoPageType} data 分页信息
|
||||
* @return 返回请求分页列表接口的结果
|
||||
*/
|
||||
export function getReceiveHistoryListAPI(data: Partial<BoatInfoPageType>) {
|
||||
return http.post<PageRowsResult<BoatInfoType>>(api.receiveHistoryList, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 车架号查询
|
||||
* @param {BoatInfoPageType} data 分页信息
|
||||
* @return 返回请求分页列表接口的结果
|
||||
*/
|
||||
export function getVinSearchAPI(data: { vin: string }) {
|
||||
return http.get<vinSearchType[]>(api.vinSearch, data);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@ const api = {
|
|||
employeeGet: '/cargo/employee/get', // 获取
|
||||
employeeList: '/cargo/employee/list', // 字典列表
|
||||
employeePage: '/cargo/employee/page', // 分页列表
|
||||
employeeSave: '/cargo/enterprise/employee/add', // 保存
|
||||
employeeAdd: '/cargo/enterprise/employee/add', // 保存
|
||||
employeeSave: '/cargo/employee/save', // 编辑
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -72,6 +73,15 @@ export function postEmployeeListAPI(data: dictionaryType) {
|
|||
* @param {EmployeeType} data 员工信息
|
||||
* @return 返回请求保存接口的结果
|
||||
*/
|
||||
export function postEmployeeAddAPI(data: Partial<EmployeeType>) {
|
||||
return http.post<string>(api.employeeAdd, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param {EmployeeType} data 员工信息
|
||||
* @return 返回请求保存接口的结果
|
||||
*/
|
||||
export function postEmployeeSaveAPI(data: Partial<EmployeeType>) {
|
||||
return http.post<string>(api.employeeSave, data);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { PageRowsResult, PageRowsType } from '@/types';
|
||||
import { HelpType } from '@/types/help';
|
||||
import { agreeTextType, HelpType } from '@/types/help';
|
||||
import http from '@/utils/request';
|
||||
|
||||
// api接口
|
||||
|
@ -8,6 +8,10 @@ const api = {
|
|||
helpGet: '/cargo/help/get', // 获取
|
||||
helpPage: '/cargo/help/page', // 分页列表
|
||||
helpSave: '/cargo/help/save', // 保存
|
||||
textAgree: '/cargo/text/agree', // 同意协议
|
||||
textGet: '/cargo/text/get', // 获取协议
|
||||
textSave: '/cargo/text/save', // 保存
|
||||
textIsAgree: '/cargo/text/sign', // 是否同意
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -45,3 +49,36 @@ export function postHelpPageAPI(data: Partial<PageRowsType>) {
|
|||
export function postHelpSaveAPI(data: Partial<HelpType>) {
|
||||
return http.post<string>(api.helpSave, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同意协议
|
||||
* @return 返回请求保存接口的结果
|
||||
*/
|
||||
export function postTextAgreeAPI() {
|
||||
return http.post<string>(api.textAgree);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取协议
|
||||
* @return 返回请求保存接口的结果
|
||||
*/
|
||||
export function postTextGetAPI(data: { textType: string }) {
|
||||
return http.get<agreeTextType>(api.textGet, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存协议
|
||||
* @param {HelpType} data 参数
|
||||
* @return 返回请求保存接口的结果
|
||||
*/
|
||||
export function postTextSaveAPI(data: Partial<agreeTextType>) {
|
||||
return http.post<string>(api.textSave, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否同意
|
||||
* @return 返回请求保存接口的结果
|
||||
*/
|
||||
export function postTextIsAgreeAPI() {
|
||||
return http.post<boolean>(api.textIsAgree);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ const api = {
|
|||
manifestSave: '/cargo/manifest/save', // 保存
|
||||
manifestImport: '/cargo/manifest/import', // 舱单导入
|
||||
manifestExport: '/cargo/manifest/tmp/export', // 下载模版
|
||||
manifestFileExport: '/cargo/manifest/export', // 舱单导出
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -70,3 +71,13 @@ export function getManifestTmpExportAPI() {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 舱单导出
|
||||
* @return 返回请求下载接口的结果
|
||||
*/
|
||||
export function getManifestFileExportAPI(data: Partial<ManifestPageType>) {
|
||||
return http.get<ArrayBuffer>(api.manifestFileExport, data, {
|
||||
responseType: 'arraybuffer',
|
||||
});
|
||||
}
|
||||
|
|
|
@ -21,5 +21,5 @@ export function getAppListAPI() {
|
|||
* @return 返回请求获取系统操作权限树接口的结果
|
||||
*/
|
||||
export function getMenuTreeAPI(data: menuParamsType) {
|
||||
return http.post<menuType[]>(api.menuTree, data);
|
||||
return http.postParams<menuType[]>(api.menuTree, data);
|
||||
}
|
||||
|
|
|
@ -1,29 +1,14 @@
|
|||
import { dictionaryListType, dictionaryType, PageRowsResult } from '@/types';
|
||||
import { getRoleListType, rolePremType, roleType } from '@/types/role';
|
||||
import { rolePremType } from '@/types/role';
|
||||
import http from '@/utils/request';
|
||||
|
||||
// api接口
|
||||
const api = {
|
||||
roleSave: '/admin/role/save', // 角色保存
|
||||
rolePremSave: '/admin/role/perm/save', // 添加角色操作权限
|
||||
rolePage: '/admin/role/page', // 角色分页列表
|
||||
roleList: '/admin/role/list', // 角色字典列表
|
||||
roleGet: '/admin/role/get', // 角色详情
|
||||
roleDelete: '/admin/role/delete', // 角色删除
|
||||
roleMenuList: '/admin/role/perm/list', // 角色菜单列表
|
||||
rolePremSave: '/admin/user/perm/save', // 添加角色操作权限
|
||||
roleMenuList: '/admin/user/perm/list', // 用户菜单列表
|
||||
};
|
||||
|
||||
/**
|
||||
* 角色保存
|
||||
* @param {roleType} data 角色信息
|
||||
* @return 返回请求角色保存接口的结果
|
||||
*/
|
||||
export function postRoleSaveAPI(data: roleType) {
|
||||
return http.post<string>(api.roleSave, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色操作权限
|
||||
* 用户添加操作权限
|
||||
* @param {rolePremType} data 角色权限
|
||||
* @return 返回请求角色操作权限接口的结果
|
||||
*/
|
||||
|
@ -32,46 +17,10 @@ export function postRolePremSaveAPI(data: rolePremType) {
|
|||
}
|
||||
|
||||
/**
|
||||
* 角色分页列表
|
||||
* @param {getUserListType} data 分页信息
|
||||
* @return 返回请求角色分页列表接口的结果
|
||||
*/
|
||||
export function postRolePageAPI(data: Partial<getRoleListType>) {
|
||||
return http.post<PageRowsResult<roleType>>(api.rolePage, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色字典列表
|
||||
* @param {dictionaryType} data 字典信息
|
||||
* @return 返回请求角色字典列表接口的结果
|
||||
*/
|
||||
export function getRoleListAPI(data: dictionaryType) {
|
||||
return http.postParams<dictionaryListType[]>(api.roleList, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色详情
|
||||
* @param {string|number} data 角色id
|
||||
* @return 返回请求角色详情接口的结果
|
||||
*/
|
||||
export function getRoleGetAPI(data: { id: number | string }) {
|
||||
return http.postParams<roleType>(api.roleGet, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色删除
|
||||
* @param {number} data 角色id
|
||||
* @return 返回请求角色删除接口的结果
|
||||
*/
|
||||
export function getRoleDeleteAPI(data: number[]) {
|
||||
return http.post<string>(api.roleDelete, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色菜单列表
|
||||
* 用户操作权限菜单列表
|
||||
* @param {string|number} data 角色id
|
||||
* @return 返回请求角色菜单列表接口的结果
|
||||
*/
|
||||
export function getRoleMenuListAPI(data: { roleId: number | string }) {
|
||||
export function getUserRoleMenuListAPI(data: { userId: number | string }) {
|
||||
return http.postParams<string[]>(api.roleMenuList, data);
|
||||
}
|
||||
|
|
|
@ -1,26 +1,11 @@
|
|||
import { dictionaryListType, dictionaryType, PageRowsResult } from '@/types';
|
||||
import { roleType } from '@/types/role';
|
||||
import {
|
||||
getUserListType,
|
||||
loginDataType,
|
||||
userInfoRepType,
|
||||
userPasswordType,
|
||||
userRoleType,
|
||||
userType,
|
||||
} from '@/types/user';
|
||||
import { loginDataType, userInfoRepType, userPasswordType, userType } from '@/types/user';
|
||||
import http from '@/utils/request';
|
||||
|
||||
// api接口
|
||||
const api = {
|
||||
login: '/admin/user/login', // 用户登录接口
|
||||
userSave: '/admin/user/save', // 用户保存
|
||||
userPassword: '/admin/user/password', // 用户修改密码
|
||||
userPage: '/admin/user/page', // 用户分页列表
|
||||
userList: '/admin/user/list', // 用户字典列表
|
||||
userGet: '/admin/user/get', // 用户详情
|
||||
userDelete: '/admin/user/delete', // 用户删除
|
||||
userRole: '/admin/user/role/add', // 用户添加角色
|
||||
userRoleList: '/admin/user/role/list', // 用户角色列表
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -36,15 +21,6 @@ export function postLoginAPI(data: loginDataType) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户保存
|
||||
* @param {userType} data 用户信息
|
||||
* @return 返回请求保存接口的结果
|
||||
*/
|
||||
export function postUserSaveAPI(data: userType) {
|
||||
return http.post<string>(api.userSave, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户修改密码
|
||||
* @param {userPasswordType} data 用户修改密码信息
|
||||
|
@ -54,24 +30,6 @@ export function postUserPasswordAPI(data: userPasswordType) {
|
|||
return http.post<string>(api.userPassword, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户分页列表
|
||||
* @param {getUserListType} data 分页信息
|
||||
* @return 返回请求分页列表接口的结果
|
||||
*/
|
||||
export function postUserPageAPI(data: Partial<getUserListType>) {
|
||||
return http.post<PageRowsResult<userType>>(api.userPage, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户字典列表
|
||||
* @param {dictionaryType} data 字典信息
|
||||
* @return 返回请求用户字典列表接口的结果
|
||||
*/
|
||||
export function getUserListAPI(data: dictionaryType) {
|
||||
return http.postParams<dictionaryListType[]>(api.userList, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户详情
|
||||
* @param {string|number} data 用户id
|
||||
|
@ -80,30 +38,3 @@ export function getUserListAPI(data: dictionaryType) {
|
|||
export function getUserGetAPI(data: { id: number | string }) {
|
||||
return http.postParams<userType>(api.userGet, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户删除
|
||||
* @param {number} data 用户id
|
||||
* @return 返回请求用户删除接口的结果
|
||||
*/
|
||||
export function getUserDeleteAPI(data: number[]) {
|
||||
return http.post<string>(api.userDelete, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户添加角色
|
||||
* @param {userRoleType} data 用户角色
|
||||
* @return 返回请求用户添加角色接口的结果
|
||||
*/
|
||||
export function postUserRoleAPI(data: userRoleType) {
|
||||
return http.post<string>(api.userRole, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户角色列表
|
||||
* @param {string|number} data 用户id
|
||||
* @return 返回请求用户角色列表接口的结果
|
||||
*/
|
||||
export function getUserRoleListAPI(data: { userId: number | string }) {
|
||||
return http.postParams<roleType[]>(api.userRoleList, data);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { dictionaryListType, dictionaryType, PageRowsResult } from '@/types';
|
||||
import { LoadWharfPageType, LoadWharfType } from '@/types/boatInfo';
|
||||
import { LoadInfoType, LoadWharfPageType, LoadWharfType } from '@/types/boatInfo';
|
||||
import http from '@/utils/request';
|
||||
|
||||
// api接口
|
||||
|
@ -9,6 +9,8 @@ const api = {
|
|||
wharfList: '/cargo/wharf/list', // 字典列表
|
||||
wharfPage: '/cargo/wharf/page', // 分页列表
|
||||
wharfSave: '/cargo/wharf/save', // 保存
|
||||
wharfInfo: '/cargo/wharf/get/info', // 获取绑定的码头信息
|
||||
wharfPhoto: '/cargo/wharf/image/', // 获取绑定的码头图片
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -55,3 +57,25 @@ export function postWharfPageAPI(data: Partial<LoadWharfPageType>) {
|
|||
export function postWharfSaveAPI(data: Partial<LoadWharfType>) {
|
||||
return http.post<string>(api.wharfSave, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取绑定的码头信息
|
||||
* @return 返回请求保存接口的结果
|
||||
*/
|
||||
export function postWharfInfoAPI() {
|
||||
return http.get<LoadInfoType>(api.wharfInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取绑定的码头图片
|
||||
* @return 返回请求保存接口的结果
|
||||
*/
|
||||
export function getWharfPhotoAPI(id: string | number) {
|
||||
return http.get<ArrayBuffer>(
|
||||
`${api.wharfPhoto}/${id}`,
|
||||
{},
|
||||
{
|
||||
responseType: 'arraybuffer',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="32px" height="29px" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1 0 0 1 -84 -186 )">
|
||||
<path d="M 31.8064516129032 16.1945266272189 C 32.1290322580645 15.7655325443787 31.9139784946237 15.0147928994083 31.2688172043011 14.6930473372781 L 26.9677419354839 12.8698224852071 L 26.9677419354839 7.40014792899408 C 26.9677419354839 6.86390532544379 26.6451612903226 6.43491124260355 26.2150537634409 6.22041420118343 L 18.4731182795699 3.21745562130178 L 18.4731182795699 2.46671597633136 C 18.4731182795699 1.07248520710059 17.3978494623656 0 16 0 C 14.6021505376344 0 13.5268817204301 1.07248520710059 13.5268817204301 2.46671597633136 L 13.5268817204301 3.21745562130178 L 5.67741935483871 6.32766272189349 C 5.13978494623656 6.54215976331361 4.9247311827957 6.97115384615385 4.9247311827957 7.40014792899408 L 4.9247311827957 12.8698224852071 L 0.731182795698925 14.6930473372781 C 0.0860215053763442 15.0147928994083 -0.129032258064516 15.7655325443787 0.301075268817205 16.301775147929 L 6.75268817204301 26.5976331360947 C 6.86021505376344 26.8121301775148 7.0752688172043 26.9193786982249 7.29032258064516 27.0266272189349 C 8.47311827956989 27.241124260355 9.44086021505376 27.7773668639053 10.3010752688172 28.6353550295858 L 10.4086021505376 28.7426035502959 C 10.7311827956989 29.064349112426 11.3763440860215 29.064349112426 11.6989247311828 28.7426035502959 L 11.8064516129032 28.6353550295858 C 12.8817204301075 27.5628698224852 14.3870967741935 26.9193786982248 16 26.9193786982248 C 17.6129032258065 26.9193786982248 19.1182795698925 27.5628698224852 20.1935483870968 28.6353550295858 C 20.5161290322581 28.957100591716 21.1612903225806 28.957100591716 21.4838709677419 28.6353550295858 C 22.3440860215054 27.7773668639053 23.5268817204301 27.133875739645 24.7096774193548 26.9193786982248 C 24.9247311827957 26.9193786982248 25.1397849462366 26.7048816568047 25.3548387096774 26.4903846153846 L 31.8064516129032 16.1945266272189 Z M 24.494623655914 11.7973372781065 L 16.8602150537634 8.47263313609468 C 16.3225806451613 8.25813609467456 15.6774193548387 8.25813609467456 15.1397849462366 8.47263313609468 L 7.29032258064516 11.7973372781065 L 7.29032258064516 8.25813609467456 L 16 4.93343195266272 L 24.494623655914 8.25813609467456 L 24.494623655914 11.7973372781065 Z " fill-rule="nonzero" fill="#aaaaaa" stroke="none" transform="matrix(1 0 0 1 84 186 )" />
|
||||
<path d="M 31.8064516129032 16.1945266272189 C 32.1290322580645 15.7655325443787 31.9139784946237 15.0147928994083 31.2688172043011 14.6930473372781 L 26.9677419354839 12.8698224852071 L 26.9677419354839 7.40014792899408 C 26.9677419354839 6.86390532544379 26.6451612903226 6.43491124260355 26.2150537634409 6.22041420118343 L 18.4731182795699 3.21745562130178 L 18.4731182795699 2.46671597633136 C 18.4731182795699 1.07248520710059 17.3978494623656 0 16 0 C 14.6021505376344 0 13.5268817204301 1.07248520710059 13.5268817204301 2.46671597633136 L 13.5268817204301 3.21745562130178 L 5.67741935483871 6.32766272189349 C 5.13978494623656 6.54215976331361 4.9247311827957 6.97115384615385 4.9247311827957 7.40014792899408 L 4.9247311827957 12.8698224852071 L 0.731182795698925 14.6930473372781 C 0.0860215053763442 15.0147928994083 -0.129032258064516 15.7655325443787 0.301075268817205 16.301775147929 L 6.75268817204301 26.5976331360947 C 6.86021505376344 26.8121301775148 7.0752688172043 26.9193786982249 7.29032258064516 27.0266272189349 C 8.47311827956989 27.241124260355 9.44086021505376 27.7773668639053 10.3010752688172 28.6353550295858 L 10.4086021505376 28.7426035502959 C 10.7311827956989 29.064349112426 11.3763440860215 29.064349112426 11.6989247311828 28.7426035502959 L 11.8064516129032 28.6353550295858 C 12.8817204301075 27.5628698224852 14.3870967741935 26.9193786982248 16 26.9193786982248 C 17.6129032258065 26.9193786982248 19.1182795698925 27.5628698224852 20.1935483870968 28.6353550295858 C 20.5161290322581 28.957100591716 21.1612903225806 28.957100591716 21.4838709677419 28.6353550295858 C 22.3440860215054 27.7773668639053 23.5268817204301 27.133875739645 24.7096774193548 26.9193786982248 C 24.9247311827957 26.9193786982248 25.1397849462366 26.7048816568047 25.3548387096774 26.4903846153846 L 31.8064516129032 16.1945266272189 Z M 24.494623655914 11.7973372781065 L 16.8602150537634 8.47263313609468 C 16.3225806451613 8.25813609467456 15.6774193548387 8.25813609467456 15.1397849462366 8.47263313609468 L 7.29032258064516 11.7973372781065 L 7.29032258064516 8.25813609467456 L 16 4.93343195266272 L 24.494623655914 8.25813609467456 L 24.494623655914 11.7973372781065 Z " fill-rule="nonzero" stroke="none" transform="matrix(1 0 0 1 84 186 )" />
|
||||
</g>
|
||||
</svg>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="32px" height="32px" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1 0 0 1 -84 -593 )">
|
||||
<path d="M 32 21.3333333333333 C 32 27.2 27.7333333333333 32 22.4 32 C 17.0666666666667 32 12.8 27.2 12.8 21.3333333333333 C 12.8 15.4666666666667 17.0666666666667 10.6666666666667 22.4 10.6666666666667 C 27.7333333333333 10.6666666666667 32 15.4666666666667 32 21.3333333333333 Z M 27.2 19.5555555555556 L 24 19.5555555555556 L 24 16 C 24 15.1111111111111 23.2888888888889 14.2222222222222 22.4 14.2222222222222 C 21.5111111111111 14.2222222222222 20.8 14.9333333333333 20.8 16 L 20.8 21.3333333333333 C 20.8 22.2222222222222 21.5111111111111 23.1111111111111 22.4 23.1111111111111 L 27.2 23.1111111111111 C 28.0888888888889 23.1111111111111 28.8 22.4 28.8 21.3333333333333 C 28.8 20.2666666666667 28.0888888888889 19.5555555555556 27.2 19.5555555555556 Z M 0 2.66666666666667 C 0 1.24444444444444 1.06666666666667 0 2.31111111111111 0 L 29.5111111111111 0 C 30.9333333333333 0 32 1.24444444444444 32 2.66666666666667 C 32 4.08888888888889 30.9333333333333 5.33333333333333 29.6888888888889 5.33333333333333 L 2.31111111111111 5.33333333333333 C 1.06666666666667 5.33333333333333 0 4.08888888888889 0 2.66666666666667 Z M 0 11.5555555555556 C 0 10.1333333333333 1.06666666666667 8.88888888888889 2.31111111111111 8.88888888888889 L 10.3111111111111 8.88888888888889 C 11.7333333333333 8.88888888888889 12.6222222222222 10.1333333333333 12.6222222222222 11.5555555555556 C 12.6222222222222 12.9777777777778 11.7333333333333 14.2222222222222 10.4888888888889 14.2222222222222 L 2.31111111111111 14.2222222222222 C 1.06666666666667 14.2222222222222 0 12.9777777777778 0 11.5555555555556 Z M 0 20.4444444444444 C 0 19.0222222222222 1.06666666666667 17.7777777777778 2.31111111111111 17.7777777777778 L 7.11111111111111 17.7777777777778 C 8.53333333333333 17.7777777777778 9.42222222222222 19.0222222222222 9.42222222222222 20.4444444444444 C 9.6 21.8666666666667 8.53333333333333 23.1111111111111 7.11111111111111 23.1111111111111 L 2.31111111111111 23.1111111111111 C 1.06666666666667 23.1111111111111 0 21.8666666666667 0 20.4444444444444 Z M 0 29.3333333333333 C 0 27.9111111111111 1.06666666666667 26.6666666666667 2.31111111111111 26.6666666666667 L 3.91111111111111 26.6666666666667 C 5.33333333333333 26.6666666666667 6.22222222222222 27.9111111111111 6.22222222222222 29.3333333333333 C 6.22222222222222 30.7555555555555 5.33333333333333 32 4.08888888888889 32 L 2.31111111111111 32 C 1.06666666666667 32 0 30.7555555555555 0 29.3333333333333 Z " fill-rule="nonzero" fill="#aaaaaa" stroke="none" transform="matrix(1 0 0 1 84 593 )" />
|
||||
<path d="M 32 21.3333333333333 C 32 27.2 27.7333333333333 32 22.4 32 C 17.0666666666667 32 12.8 27.2 12.8 21.3333333333333 C 12.8 15.4666666666667 17.0666666666667 10.6666666666667 22.4 10.6666666666667 C 27.7333333333333 10.6666666666667 32 15.4666666666667 32 21.3333333333333 Z M 27.2 19.5555555555556 L 24 19.5555555555556 L 24 16 C 24 15.1111111111111 23.2888888888889 14.2222222222222 22.4 14.2222222222222 C 21.5111111111111 14.2222222222222 20.8 14.9333333333333 20.8 16 L 20.8 21.3333333333333 C 20.8 22.2222222222222 21.5111111111111 23.1111111111111 22.4 23.1111111111111 L 27.2 23.1111111111111 C 28.0888888888889 23.1111111111111 28.8 22.4 28.8 21.3333333333333 C 28.8 20.2666666666667 28.0888888888889 19.5555555555556 27.2 19.5555555555556 Z M 0 2.66666666666667 C 0 1.24444444444444 1.06666666666667 0 2.31111111111111 0 L 29.5111111111111 0 C 30.9333333333333 0 32 1.24444444444444 32 2.66666666666667 C 32 4.08888888888889 30.9333333333333 5.33333333333333 29.6888888888889 5.33333333333333 L 2.31111111111111 5.33333333333333 C 1.06666666666667 5.33333333333333 0 4.08888888888889 0 2.66666666666667 Z M 0 11.5555555555556 C 0 10.1333333333333 1.06666666666667 8.88888888888889 2.31111111111111 8.88888888888889 L 10.3111111111111 8.88888888888889 C 11.7333333333333 8.88888888888889 12.6222222222222 10.1333333333333 12.6222222222222 11.5555555555556 C 12.6222222222222 12.9777777777778 11.7333333333333 14.2222222222222 10.4888888888889 14.2222222222222 L 2.31111111111111 14.2222222222222 C 1.06666666666667 14.2222222222222 0 12.9777777777778 0 11.5555555555556 Z M 0 20.4444444444444 C 0 19.0222222222222 1.06666666666667 17.7777777777778 2.31111111111111 17.7777777777778 L 7.11111111111111 17.7777777777778 C 8.53333333333333 17.7777777777778 9.42222222222222 19.0222222222222 9.42222222222222 20.4444444444444 C 9.6 21.8666666666667 8.53333333333333 23.1111111111111 7.11111111111111 23.1111111111111 L 2.31111111111111 23.1111111111111 C 1.06666666666667 23.1111111111111 0 21.8666666666667 0 20.4444444444444 Z M 0 29.3333333333333 C 0 27.9111111111111 1.06666666666667 26.6666666666667 2.31111111111111 26.6666666666667 L 3.91111111111111 26.6666666666667 C 5.33333333333333 26.6666666666667 6.22222222222222 27.9111111111111 6.22222222222222 29.3333333333333 C 6.22222222222222 30.7555555555555 5.33333333333333 32 4.08888888888889 32 L 2.31111111111111 32 C 1.06666666666667 32 0 30.7555555555555 0 29.3333333333333 Z " fill-rule="nonzero" stroke="none" transform="matrix(1 0 0 1 84 593 )" />
|
||||
</g>
|
||||
</svg>
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="32px" height="29px" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1 0 0 1 -84 -394 )">
|
||||
<path d="M 31.8318401748088 4.05227163775821 C 32.0982363040425 2.9064139719341 31.8318401748088 1.82791880937854 31.0327142188232 1.0190632354223 L 30.899547370064 0.884275037043493 C 30.0338067738411 0.142813562276649 28.8351178398627 -0.126794430401814 27.769626970501 0.277633356576309 L 1.66483533635087 10.5231162294082 C 0.732542531606056 10.8601499171969 0.133198064616825 11.7363995903425 0.0665834243795847 12.7474690577878 C 0 13.7585385252332 0.466146402372405 14.7022138934891 1.33188699859529 15.1740357796566 L 6.85915405025753 18.4768837705918 C 7.19213360387077 18.6790976640809 7.59169658186359 18.5442778697812 7.79147807086 18.2072441819925 C 7.99125955985641 17.8702420901246 7.85806149523958 17.4658143031465 7.525113157484 17.2636004096575 L 1.9978148899641 14.0281781138325 C 1.59825191197128 13.7585385252332 1.33188699859529 13.354110738255 1.39847042297487 12.8822888520875 C 1.46505384735446 12.41046696592 1.73144997658811 12.0060391789419 2.19759637896051 11.8038252854528 L 28.3023880131107 1.55831081670008 C 28.7019509911035 1.42349102240042 29.1015139690963 1.42349102240042 29.4344623068519 1.55831081670008 L 10.1888559388169 18.5442778697812 C 9.5229280474481 19.1509195502484 9.12336506945528 20.0271692233941 9.12336506945528 20.97084459165 L 9.12336506945528 28.1831506580668 C 9.12336506945528 28.5875784450449 9.38972998283128 28.8571864377234 9.7892929608241 28.8571864377234 C 10.1888559388169 28.8571864377234 10.4552208521929 28.5875784450449 10.4552208521929 28.1831506580668 L 10.4552208521929 20.97084459165 C 10.4552208521929 20.4315970103722 10.6550023411893 19.8923810250153 11.1211799594194 19.5553473372265 L 30.4333697518339 2.43456048984573 C 30.6331512408303 2.83898827682385 30.6331512408303 3.24341606380197 30.5665678164508 3.64784385078009 L 25.7052286561573 22.4537359452628 C 25.4388325269237 23.3974113135187 24.7729046355549 24.2062668874749 23.9071952551896 24.5433005752637 C 23.0414858748244 24.8803342630524 21.9759637896051 24.8803026671315 21.1102544092399 24.3410866817746 L 14.6506321211175 20.6338109038612 C 14.3176837833619 20.4315970103722 13.9181208053691 20.5664168046718 13.7183393163727 20.9034504924606 C 13.5185578273763 21.2404525843284 13.6517246761355 21.6448803713065 13.9847042297487 21.8470942647956 L 20.4442953020134 25.6217641418984 C 21.1102544092399 26.0261919288765 21.9093803652255 26.2284058223656 22.6418916809739 26.2284058223656 C 23.2412361479632 26.2284058223656 23.7739971905728 26.0935860280659 24.373341657562 25.8913721345768 C 25.6386140159201 25.3521561492199 26.6375214609021 24.2736609866643 26.9705010145154 22.8581637322409 L 31.8318401748088 4.05227163775821 Z " fill-rule="nonzero" fill="#aaaaaa" stroke="none" transform="matrix(1 0 0 1 84 394 )" />
|
||||
<path d="M 31.8318401748088 4.05227163775821 C 32.0982363040425 2.9064139719341 31.8318401748088 1.82791880937854 31.0327142188232 1.0190632354223 L 30.899547370064 0.884275037043493 C 30.0338067738411 0.142813562276649 28.8351178398627 -0.126794430401814 27.769626970501 0.277633356576309 L 1.66483533635087 10.5231162294082 C 0.732542531606056 10.8601499171969 0.133198064616825 11.7363995903425 0.0665834243795847 12.7474690577878 C 0 13.7585385252332 0.466146402372405 14.7022138934891 1.33188699859529 15.1740357796566 L 6.85915405025753 18.4768837705918 C 7.19213360387077 18.6790976640809 7.59169658186359 18.5442778697812 7.79147807086 18.2072441819925 C 7.99125955985641 17.8702420901246 7.85806149523958 17.4658143031465 7.525113157484 17.2636004096575 L 1.9978148899641 14.0281781138325 C 1.59825191197128 13.7585385252332 1.33188699859529 13.354110738255 1.39847042297487 12.8822888520875 C 1.46505384735446 12.41046696592 1.73144997658811 12.0060391789419 2.19759637896051 11.8038252854528 L 28.3023880131107 1.55831081670008 C 28.7019509911035 1.42349102240042 29.1015139690963 1.42349102240042 29.4344623068519 1.55831081670008 L 10.1888559388169 18.5442778697812 C 9.5229280474481 19.1509195502484 9.12336506945528 20.0271692233941 9.12336506945528 20.97084459165 L 9.12336506945528 28.1831506580668 C 9.12336506945528 28.5875784450449 9.38972998283128 28.8571864377234 9.7892929608241 28.8571864377234 C 10.1888559388169 28.8571864377234 10.4552208521929 28.5875784450449 10.4552208521929 28.1831506580668 L 10.4552208521929 20.97084459165 C 10.4552208521929 20.4315970103722 10.6550023411893 19.8923810250153 11.1211799594194 19.5553473372265 L 30.4333697518339 2.43456048984573 C 30.6331512408303 2.83898827682385 30.6331512408303 3.24341606380197 30.5665678164508 3.64784385078009 L 25.7052286561573 22.4537359452628 C 25.4388325269237 23.3974113135187 24.7729046355549 24.2062668874749 23.9071952551896 24.5433005752637 C 23.0414858748244 24.8803342630524 21.9759637896051 24.8803026671315 21.1102544092399 24.3410866817746 L 14.6506321211175 20.6338109038612 C 14.3176837833619 20.4315970103722 13.9181208053691 20.5664168046718 13.7183393163727 20.9034504924606 C 13.5185578273763 21.2404525843284 13.6517246761355 21.6448803713065 13.9847042297487 21.8470942647956 L 20.4442953020134 25.6217641418984 C 21.1102544092399 26.0261919288765 21.9093803652255 26.2284058223656 22.6418916809739 26.2284058223656 C 23.2412361479632 26.2284058223656 23.7739971905728 26.0935860280659 24.373341657562 25.8913721345768 C 25.6386140159201 25.3521561492199 26.6375214609021 24.2736609866643 26.9705010145154 22.8581637322409 L 31.8318401748088 4.05227163775821 Z " fill-rule="nonzero" stroke="none" transform="matrix(1 0 0 1 84 394 )" />
|
||||
</g>
|
||||
</svg>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="32px" height="36px" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="matrix(1 0 0 1 -84 -488 )">
|
||||
<path d="M 18.6666666545139 13.4556212879068 L 23.999999984375 13.4556212879068 L 23.999999984375 8.13017750092455 C 23.999999984375 7.63998393215635 24.3979690984866 7.24260352949335 24.8888888796296 7.24260352949335 C 25.3798086607727 7.24260352949335 25.7777777748843 7.63998393215635 25.7777777748843 8.13017750092455 L 25.7777777748843 13.4556212879068 L 31.1111111047454 13.4556212879068 C 31.6020308858885 13.4556212879068 32 13.8530016905698 32 14.343195259338 C 32 14.8333888281062 31.6020308858885 15.2307692307692 31.1111111047454 15.2307692307692 L 25.7777777748843 15.2307692307692 L 25.7777777748843 20.5562130177515 C 25.7777777748843 21.0464065865197 25.3798086607727 21.4437869891827 24.8888888796296 21.4437869891827 C 24.3979690984866 21.4437869891827 23.999999984375 21.0464065865197 23.999999984375 20.5562130177515 L 23.999999984375 15.2307692307692 L 18.6666666545139 15.2307692307692 C 18.1757468733708 15.2307692307692 17.7777777592593 14.8333888281062 17.7777777592593 14.343195259338 C 17.7777777592593 13.8530016905698 18.1757468733708 13.4556212879068 18.6666666545139 13.4556212879068 Z M 30 20.6840236686391 L 30.2222221886574 20.6831361085429 C 30.2222221886574 20.1929425397747 30.620191302769 19.7955621371117 31.1111110839121 19.7955621371117 C 31.6020308650551 19.7955621371117 31.9999999791667 20.1929425397747 31.9999999791667 20.6831361085429 L 32 33.2662721754808 C 31.9995564818193 34.7365396105881 30.8057791101131 35.928192063087 29.3333334351962 35.928192063087 C 28.8188541791035 35.928192063087 28.3153585793775 35.779587327387 27.8835555235133 35.5002958441198 L 16.5048888642546 28.1378698086169 C 16.2109336845382 27.9478214882398 15.8326218362668 27.9478214882398 15.5386666565504 28.1378698086169 L 4.11377778898842 35.5082840098003 C 3.68254972175569 35.7864761256624 3.1800650159474 35.9344576611834 2.66666655930324 35.9344576611834 C 1.19420033215083 35.9344576611834 0.000414442319860577 34.7427731863621 0 33.2724852209689 L 0 6.35502959966716 C 0 2.92367461115139 2.78578377079869 0.142011820451183 6.22222220428241 0.142011820451183 L 25.7777777748843 0.142011820451183 C 29.214216208368 0.142011820451183 31.9999999791667 2.92367461115139 31.9999999791667 6.35502955806213 L 31.9999999791667 8.18343193879438 C 31.9999999791667 8.67362550756258 31.6020308650551 9.07100591022559 31.1111110839121 9.07100591022559 C 30.620191302769 9.07100591022559 30.2222221886574 8.67362550756259 30.2222221886574 8.18343193879438 L 30.2222221886574 6.35502959966716 C 30.2222221886574 3.90406178356279 28.2323766528219 1.91715978629143 25.7777777748843 2 L 6.22222220428241 2 C 3.76762332634482 1.91715978629143 1.77777779050926 3.90406178356279 2 6.35502959966716 L 2 33.2724852209689 C 1.77777776933179 33.2725643174599 1.77777775874305 33.2726434139586 1.77777775874305 33.2727225104524 C 1.77777775874305 33.7629160677317 2.17574686352721 34.1602964610811 2.66666663316435 34.1602964610811 C 2.83791950301204 34.1602964610811 3.00552670215961 34.1109001074683 3.14933333128299 34.0180473511464 L 14.5742221988449 26.6467455482618 C 15.4564039377868 26.0777934671316 16.5908684453466 26.0788359085129 17.471999988625 26.6494082701553 L 28.8497777728843 34.0118343056583 C 28.9937759684371 34.1050539462454 29.1617203167725 34.1546583128729 29.3333336863881 34.1546583128729 C 29.8242534560252 34.1546583128729 30.2222225608094 33.7572779195235 30.2222225608094 33.2670843622442 C 30.2222225608094 33.2668136332811 30.2222224367587 33.2665429043305 30 33.2662721754808 L 30 20.6840236686391 Z " fill-rule="nonzero" fill="#aaaaaa" stroke="none" transform="matrix(1 0 0 1 84 488 )" />
|
||||
<path d="M 18.6666666545139 13.4556212879068 L 23.999999984375 13.4556212879068 L 23.999999984375 8.13017750092455 C 23.999999984375 7.63998393215635 24.3979690984866 7.24260352949335 24.8888888796296 7.24260352949335 C 25.3798086607727 7.24260352949335 25.7777777748843 7.63998393215635 25.7777777748843 8.13017750092455 L 25.7777777748843 13.4556212879068 L 31.1111111047454 13.4556212879068 C 31.6020308858885 13.4556212879068 32 13.8530016905698 32 14.343195259338 C 32 14.8333888281062 31.6020308858885 15.2307692307692 31.1111111047454 15.2307692307692 L 25.7777777748843 15.2307692307692 L 25.7777777748843 20.5562130177515 C 25.7777777748843 21.0464065865197 25.3798086607727 21.4437869891827 24.8888888796296 21.4437869891827 C 24.3979690984866 21.4437869891827 23.999999984375 21.0464065865197 23.999999984375 20.5562130177515 L 23.999999984375 15.2307692307692 L 18.6666666545139 15.2307692307692 C 18.1757468733708 15.2307692307692 17.7777777592593 14.8333888281062 17.7777777592593 14.343195259338 C 17.7777777592593 13.8530016905698 18.1757468733708 13.4556212879068 18.6666666545139 13.4556212879068 Z M 30 20.6840236686391 L 30.2222221886574 20.6831361085429 C 30.2222221886574 20.1929425397747 30.620191302769 19.7955621371117 31.1111110839121 19.7955621371117 C 31.6020308650551 19.7955621371117 31.9999999791667 20.1929425397747 31.9999999791667 20.6831361085429 L 32 33.2662721754808 C 31.9995564818193 34.7365396105881 30.8057791101131 35.928192063087 29.3333334351962 35.928192063087 C 28.8188541791035 35.928192063087 28.3153585793775 35.779587327387 27.8835555235133 35.5002958441198 L 16.5048888642546 28.1378698086169 C 16.2109336845382 27.9478214882398 15.8326218362668 27.9478214882398 15.5386666565504 28.1378698086169 L 4.11377778898842 35.5082840098003 C 3.68254972175569 35.7864761256624 3.1800650159474 35.9344576611834 2.66666655930324 35.9344576611834 C 1.19420033215083 35.9344576611834 0.000414442319860577 34.7427731863621 0 33.2724852209689 L 0 6.35502959966716 C 0 2.92367461115139 2.78578377079869 0.142011820451183 6.22222220428241 0.142011820451183 L 25.7777777748843 0.142011820451183 C 29.214216208368 0.142011820451183 31.9999999791667 2.92367461115139 31.9999999791667 6.35502955806213 L 31.9999999791667 8.18343193879438 C 31.9999999791667 8.67362550756258 31.6020308650551 9.07100591022559 31.1111110839121 9.07100591022559 C 30.620191302769 9.07100591022559 30.2222221886574 8.67362550756259 30.2222221886574 8.18343193879438 L 30.2222221886574 6.35502959966716 C 30.2222221886574 3.90406178356279 28.2323766528219 1.91715978629143 25.7777777748843 2 L 6.22222220428241 2 C 3.76762332634482 1.91715978629143 1.77777779050926 3.90406178356279 2 6.35502959966716 L 2 33.2724852209689 C 1.77777776933179 33.2725643174599 1.77777775874305 33.2726434139586 1.77777775874305 33.2727225104524 C 1.77777775874305 33.7629160677317 2.17574686352721 34.1602964610811 2.66666663316435 34.1602964610811 C 2.83791950301204 34.1602964610811 3.00552670215961 34.1109001074683 3.14933333128299 34.0180473511464 L 14.5742221988449 26.6467455482618 C 15.4564039377868 26.0777934671316 16.5908684453466 26.0788359085129 17.471999988625 26.6494082701553 L 28.8497777728843 34.0118343056583 C 28.9937759684371 34.1050539462454 29.1617203167725 34.1546583128729 29.3333336863881 34.1546583128729 C 29.8242534560252 34.1546583128729 30.2222225608094 33.7572779195235 30.2222225608094 33.2670843622442 C 30.2222225608094 33.2668136332811 30.2222224367587 33.2665429043305 30 33.2662721754808 L 30 20.6840236686391 Z " fill-rule="nonzero" stroke="none" transform="matrix(1 0 0 1 84 488 )" />
|
||||
</g>
|
||||
</svg>
|
Binary file not shown.
After Width: | Height: | Size: 216 KiB |
Binary file not shown.
After Width: | Height: | Size: 83 KiB |
|
@ -31,4 +31,9 @@ interface PaginationProps {
|
|||
defineProps<PaginationProps>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss">
|
||||
.el-pagination__total,
|
||||
.el-pagination__jump {
|
||||
color: #fff !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<div class="header-left">
|
||||
<img class="logo" src="@/assets/images/logo.png" />
|
||||
<!-- <div class="left-title">
|
||||
<div class="left-title">
|
||||
<div class="title">船货信息智慧共享服务平台</div>
|
||||
<div class="text">Intelligent sharing service platform for ship and cargo information</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div
|
||||
|
@ -54,7 +54,7 @@ const menuList = ref<menuListType[]>([
|
|||
icon: 'API',
|
||||
},
|
||||
{
|
||||
path: '/enterprise/employee',
|
||||
path: '/setting',
|
||||
title: '设置',
|
||||
icon: 'Setting',
|
||||
},
|
||||
|
|
|
@ -16,6 +16,6 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: var(--el-bg-color-page);
|
||||
background-color: #555;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
<template>
|
||||
<template v-for="subItem in menuList" :key="subItem.path">
|
||||
<el-sub-menu v-if="subItem.children && subItem.children.length > 0" :index="subItem.path">
|
||||
<template #title>
|
||||
<el-icon v-if="subItem.meta?.native">
|
||||
<component :is="subItem.meta?.icon"></component>
|
||||
</el-icon>
|
||||
<svg-icon :icon="subItem.meta?.icon" className="side-icon" v-else></svg-icon>
|
||||
<span>{{ subItem.meta?.title }}</span>
|
||||
</template>
|
||||
<!-- 有children递归本次组件 -->
|
||||
<SubMenu :menuList="subItem.children" />
|
||||
</el-sub-menu>
|
||||
|
||||
<el-menu-item v-else :index="subItem.path">
|
||||
<el-icon v-if="subItem.meta?.native">
|
||||
<component :is="subItem.meta?.icon"></component>
|
||||
</el-icon>
|
||||
<svg-icon :icon="subItem.meta?.icon" className="side-icon" v-else></svg-icon>
|
||||
<template #title>
|
||||
<span>{{ subItem.meta?.title }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
// 获取父组件传递的值
|
||||
defineProps({
|
||||
menuList: {
|
||||
type: Array<RouteRecordRaw>,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.side-icon {
|
||||
margin-right: 10px;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
|
@ -1,23 +1,62 @@
|
|||
<template>
|
||||
<div class="sidebar">
|
||||
<img class="side-logo" src="@/assets/images/logo.png" />
|
||||
<el-scrollbar>
|
||||
<el-menu :default-active="activeMenu" background-color="#333" text-color="#fff" router>
|
||||
<SubMenu :menuList="menuList"></SubMenu>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
<div
|
||||
class="side-item"
|
||||
v-for="item in menuList"
|
||||
:key="item.path"
|
||||
:class="{ 'side-item-active': activeMenu === item.path }"
|
||||
@click="onClickMenu(item)"
|
||||
>
|
||||
<svg-icon :icon="item.icon" className="side-icon"></svg-icon>
|
||||
<span>{{ item.title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { filterRoutes, generateMenus } from '@/utils/routers';
|
||||
import SubMenu from './components/SubMenu.vue';
|
||||
import { getAdImageAPI } from '@/api/ApiManage';
|
||||
|
||||
// 获取路由携带的参数和路径
|
||||
const route = useRoute();
|
||||
|
||||
interface menuListType {
|
||||
path: string;
|
||||
title: string;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
// 侧边导航菜单
|
||||
const menuList = ref<menuListType[]>([
|
||||
{
|
||||
path: '/boat',
|
||||
title: '船舶信息',
|
||||
icon: 'BoatInfo',
|
||||
},
|
||||
{
|
||||
path: '/manifest',
|
||||
title: '舱单信息',
|
||||
icon: 'ManifestInfo',
|
||||
},
|
||||
{
|
||||
path: '/send',
|
||||
title: '发布信息',
|
||||
icon: 'SendInfo',
|
||||
},
|
||||
{
|
||||
path: '/subscribe',
|
||||
title: '订阅信息',
|
||||
icon: 'SubscribeInfo',
|
||||
},
|
||||
{
|
||||
path: '/history',
|
||||
title: '历史数据',
|
||||
icon: 'History',
|
||||
},
|
||||
]);
|
||||
|
||||
// 默认激活菜单
|
||||
const activeMenu = computed(() => {
|
||||
const { path } = route;
|
||||
|
@ -27,10 +66,19 @@ const activeMenu = computed(() => {
|
|||
// 获取路由实例
|
||||
const router = useRouter();
|
||||
|
||||
// 筛选符合条件的路由
|
||||
const menuList = computed(() => {
|
||||
const fRoutes = filterRoutes(router.getRoutes());
|
||||
return generateMenus(fRoutes);
|
||||
// 切换菜单
|
||||
const onClickMenu = (item: menuListType) => {
|
||||
router.push(item.path);
|
||||
};
|
||||
|
||||
// 获取广告图
|
||||
const getAdImage = async () => {
|
||||
const { data } = await getAdImageAPI();
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await getAdImage();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -41,6 +89,8 @@ const menuList = computed(() => {
|
|||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
@ -50,5 +100,30 @@ const menuList = computed(() => {
|
|||
width: 100%;
|
||||
height: 170px;
|
||||
}
|
||||
.side-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
font-size: 18px;
|
||||
color: #d7d7d7;
|
||||
background-color: #333;
|
||||
border-bottom: 1px solid #555c64;
|
||||
.side-icon {
|
||||
margin-bottom: 6px;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
.side-item-active {
|
||||
color: #ff0;
|
||||
background-color: #555;
|
||||
}
|
||||
.side-item:hover {
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
background-color: #000;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -43,5 +43,8 @@ import Sidebar from './Sidebar/index.vue';
|
|||
color: #fff;
|
||||
background-color: #9c000c;
|
||||
}
|
||||
.el-main {
|
||||
background-color: #555;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,24 +1,11 @@
|
|||
import { App } from 'vue';
|
||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
||||
import Layout from '@/layouts/index.vue';
|
||||
import boatRoutes from './modules/boat';
|
||||
import enterpriseRoutes from './modules/enterprise';
|
||||
import historyRoutes from './modules/history';
|
||||
import manifestRoutes from './modules/manifest';
|
||||
import sendRoutes from './modules/send';
|
||||
import subscriptionRoutes from './modules/subscription';
|
||||
|
||||
/**
|
||||
* 异步路由组件
|
||||
*/
|
||||
export const asyncRoutes = [
|
||||
...boatRoutes,
|
||||
...manifestRoutes,
|
||||
...enterpriseRoutes,
|
||||
...sendRoutes,
|
||||
...subscriptionRoutes,
|
||||
...historyRoutes,
|
||||
];
|
||||
export const asyncRoutes = [];
|
||||
|
||||
/**
|
||||
* 公共路由
|
||||
|
@ -68,19 +55,61 @@ export const constantRoutes: Array<RouteRecordRaw> = [
|
|||
path: '/notice',
|
||||
name: 'Notice',
|
||||
component: () => import('@/views/Notice/index.vue'),
|
||||
meta: { title: '公告', roles: ['test2'] },
|
||||
meta: { title: '公告' },
|
||||
},
|
||||
{
|
||||
path: '/api',
|
||||
name: 'Api',
|
||||
component: () => import('@/views/ApiManage/index.vue'),
|
||||
meta: { title: 'API', roles: ['test2'] },
|
||||
meta: { title: 'API' },
|
||||
},
|
||||
{
|
||||
path: '/setting',
|
||||
name: 'Setting',
|
||||
component: () => import('@/views/Setting/index.vue'),
|
||||
meta: { title: '设置' },
|
||||
},
|
||||
{
|
||||
path: '/help',
|
||||
name: 'HelpCenter',
|
||||
component: () => import('@/views/Help/index.vue'),
|
||||
meta: { title: '帮助', roles: ['test2'] },
|
||||
meta: { title: '帮助' },
|
||||
},
|
||||
{
|
||||
path: '/boat',
|
||||
name: 'BoatInfo',
|
||||
component: () => import('@/views/Boat/index.vue'),
|
||||
meta: {
|
||||
title: '船舶信息',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/manifest',
|
||||
name: 'Manifest',
|
||||
component: () => import('@/views/Manifest/index.vue'),
|
||||
meta: { title: '舱单信息' },
|
||||
},
|
||||
{
|
||||
path: '/send',
|
||||
name: 'sendInfo',
|
||||
component: () => import('@/views/Send/index.vue'),
|
||||
meta: { title: '发布信息' },
|
||||
},
|
||||
{
|
||||
path: '/subscribe',
|
||||
name: 'Subscribe',
|
||||
component: () => import('@/views/Subscription/index.vue'),
|
||||
meta: { title: '订阅信息' },
|
||||
},
|
||||
{
|
||||
path: '/history',
|
||||
name: 'History',
|
||||
component: () => import('@/views/History/index.vue'),
|
||||
meta: {
|
||||
title: '历史数据',
|
||||
icon: 'History',
|
||||
native: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
import { RouteRecordRaw } from 'vue-router';
|
||||
import Layout from '@/layouts/index.vue';
|
||||
|
||||
/**
|
||||
* 船期信息路由
|
||||
*/
|
||||
const boatRoutes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/boat',
|
||||
component: Layout,
|
||||
redirect: '/boat/info',
|
||||
name: 'Boat',
|
||||
children: [
|
||||
{
|
||||
path: '/boat/info',
|
||||
name: 'BoatInfo',
|
||||
component: () => import('@/views/Boat/Infos/index.vue'),
|
||||
meta: {
|
||||
title: '船期管理',
|
||||
icon: 'BoatInfo',
|
||||
native: false,
|
||||
roles: ['test2'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default boatRoutes;
|
|
@ -1,41 +0,0 @@
|
|||
import { RouteRecordRaw } from 'vue-router';
|
||||
import Layout from '@/layouts/index.vue';
|
||||
|
||||
/**
|
||||
* 企业管理路由
|
||||
*/
|
||||
const enterpriseRoutes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/enterprise',
|
||||
component: Layout,
|
||||
redirect: '/enterprise/manage',
|
||||
name: 'Enterprise',
|
||||
// meta: {
|
||||
// title: '企业中心',
|
||||
// icon: 'Setting',
|
||||
// roles: ['test2'], // 测试权限
|
||||
// },
|
||||
children: [
|
||||
{
|
||||
path: '/enterprise/manage',
|
||||
name: 'CompanyManage',
|
||||
component: () => import('@/views/Enterprise/Manage/index.vue'),
|
||||
// meta: { title: '企业管理', icon: 'Menu', roles: ['test2'] },
|
||||
},
|
||||
{
|
||||
path: '/enterprise/employee',
|
||||
name: 'EmployeeManage',
|
||||
component: () => import('@/views/Enterprise/Employee/index.vue'),
|
||||
// meta: { title: '员工管理', icon: 'Menu', roles: ['test2'] },
|
||||
},
|
||||
// {
|
||||
// path: '/enterprise/register',
|
||||
// name: 'CompanyRegister',
|
||||
// component: () => import('@/views/Enterprise/Company/index.vue'),
|
||||
// meta: { title: '企业注册', icon: 'Menu', roles: ['test2'] },
|
||||
// },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default enterpriseRoutes;
|
|
@ -1,24 +0,0 @@
|
|||
import { RouteRecordRaw } from 'vue-router';
|
||||
import Layout from '@/layouts/index.vue';
|
||||
|
||||
/**
|
||||
* 帮助信息路由
|
||||
*/
|
||||
const helpRoutes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/help',
|
||||
component: Layout,
|
||||
redirect: '/help/center',
|
||||
name: 'help',
|
||||
children: [
|
||||
{
|
||||
path: '/help/center',
|
||||
name: 'HelpCenter',
|
||||
component: () => import('@/views/Help/index.vue'),
|
||||
meta: { title: '帮助信息', icon: 'Menu', roles: ['test2'] },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default helpRoutes;
|
|
@ -1,32 +0,0 @@
|
|||
import { RouteRecordRaw } from 'vue-router';
|
||||
import Layout from '@/layouts/index.vue';
|
||||
|
||||
/**
|
||||
* 历史数据路由
|
||||
*/
|
||||
const historyRoutes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/history',
|
||||
component: Layout,
|
||||
redirect: '/history/mine',
|
||||
// meta: {
|
||||
// title: '历史数据',
|
||||
// icon: 'History',
|
||||
// native: false,
|
||||
// },
|
||||
children: [
|
||||
{
|
||||
path: '/history/mine',
|
||||
name: 'Mine',
|
||||
component: () => import('@/views/History/index.vue'),
|
||||
meta: {
|
||||
title: '历史数据',
|
||||
icon: 'History',
|
||||
native: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default historyRoutes;
|
|
@ -1,35 +0,0 @@
|
|||
import { RouteRecordRaw } from 'vue-router';
|
||||
import Layout from '@/layouts/index.vue';
|
||||
|
||||
/**
|
||||
* 舱单路由
|
||||
*/
|
||||
const manifestRoutes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/manifest',
|
||||
component: Layout,
|
||||
redirect: '/manifest/manage',
|
||||
name: 'Manifest',
|
||||
// meta: {
|
||||
// title: '舱单管理',
|
||||
// icon: 'Setting',
|
||||
// roles: ['test2'], // 测试权限
|
||||
// },
|
||||
children: [
|
||||
{
|
||||
path: '/manifest/manage',
|
||||
name: 'ManifestManage',
|
||||
component: () => import('@/views/Manifest/Manage/index.vue'),
|
||||
meta: { title: '舱单信息', icon: 'ManifestInfo', native: false },
|
||||
},
|
||||
{
|
||||
path: '/manifest/detail',
|
||||
name: 'ManifestDetail',
|
||||
component: () => import('@/views/Manifest/Detail/index.vue'),
|
||||
// meta: { title: '舱单明细', icon: 'Menu', roles: ['test2'] },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default manifestRoutes;
|
|
@ -1,31 +0,0 @@
|
|||
import { RouteRecordRaw } from 'vue-router';
|
||||
import Layout from '@/layouts/index.vue';
|
||||
|
||||
/**
|
||||
* 订阅信息路由
|
||||
*/
|
||||
const subscriptionRoutes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/subscribe',
|
||||
component: Layout,
|
||||
redirect: '/subscribe/manage',
|
||||
name: 'Subscribe',
|
||||
meta: { title: '订阅管理', icon: 'SubscribeInfo', native: false },
|
||||
children: [
|
||||
{
|
||||
path: '/subscribe/publish',
|
||||
name: 'SubscribePublish',
|
||||
component: () => import('@/views/Subscription/Publish/index.vue'),
|
||||
meta: { title: '我的订阅', icon: 'Menu', native: true, roles: ['test2'] },
|
||||
},
|
||||
{
|
||||
path: '/subscribe/receive',
|
||||
name: 'SubscribeReceive',
|
||||
component: () => import('@/views/Subscription/Receive/index.vue'),
|
||||
meta: { title: '收到订阅', icon: 'Menu', native: true, roles: ['test2'] },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default subscriptionRoutes;
|
|
@ -1,35 +0,0 @@
|
|||
import { RouteRecordRaw } from 'vue-router';
|
||||
import Layout from '@/layouts/index.vue';
|
||||
|
||||
/**
|
||||
* 系统设置路由
|
||||
*/
|
||||
const systemRoutes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: '/system',
|
||||
component: Layout,
|
||||
redirect: '/system/user',
|
||||
name: 'System',
|
||||
meta: {
|
||||
title: '系统管理',
|
||||
icon: 'Setting',
|
||||
roles: ['test2'], // 测试权限
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '/system/user',
|
||||
name: 'User',
|
||||
component: () => import('@/views/System/Users/index.vue'),
|
||||
meta: { title: '用户管理', icon: 'Menu', roles: ['test2'] },
|
||||
},
|
||||
{
|
||||
path: '/system/role',
|
||||
name: 'Roles',
|
||||
component: () => import('@/views/System/Roles/index.vue'),
|
||||
meta: { title: '角色管理', icon: 'Menu', roles: ['test2'] },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default systemRoutes;
|
|
@ -1,8 +1,24 @@
|
|||
.el-table__header th {
|
||||
font-weight: bold;
|
||||
color: #252525;
|
||||
background: #fafafa;
|
||||
color: #fff;
|
||||
background: #005478;
|
||||
}
|
||||
.el-table .el-table__header th {
|
||||
background: var(--el-fill-color-light) !important;
|
||||
background: #005478 !important;
|
||||
}
|
||||
.el-table,
|
||||
.el-table__expanded-cell {
|
||||
background-color: #555;
|
||||
}
|
||||
.el-table tr {
|
||||
color: #fff;
|
||||
background-color: #555;
|
||||
}
|
||||
.el-table__body tr.hover-row > td.el-table__cell {
|
||||
color: #000;
|
||||
background-color: #ffc;
|
||||
}
|
||||
.el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell {
|
||||
color: #000;
|
||||
background-color: #ffc;
|
||||
}
|
||||
|
|
|
@ -45,12 +45,3 @@ body {
|
|||
padding: 20px;
|
||||
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
.card {
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
overflow-x: hidden;
|
||||
background-color: var(--el-bg-color);
|
||||
border: 1px solid var(--el-border-color-light);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ export interface EmployeeType {
|
|||
nickname: string;
|
||||
username: string;
|
||||
phone: string;
|
||||
dept: string;
|
||||
job: string;
|
||||
wharfId: number;
|
||||
userId: number;
|
||||
password: string;
|
||||
|
|
|
@ -25,6 +25,7 @@ export interface BoatInfoType {
|
|||
shipStatus: string;
|
||||
tradeType: string;
|
||||
loadPortId: number | string;
|
||||
loadPort: PortType;
|
||||
dischargePortId: number | string;
|
||||
ship: ShipType;
|
||||
route: BoatRouteType;
|
||||
|
@ -80,6 +81,31 @@ export interface LoadWharfType {
|
|||
port: PortType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 码头简介类型
|
||||
*/
|
||||
export interface LoadInfoType {
|
||||
id: number;
|
||||
createBy: number;
|
||||
createDate: string;
|
||||
updateBy: number;
|
||||
updateDate: string;
|
||||
version: number;
|
||||
name: string;
|
||||
portId: number;
|
||||
address: string;
|
||||
longitude: number;
|
||||
latitude: number;
|
||||
berthageNum: number;
|
||||
transitCapacity: number;
|
||||
storageCapacity: number;
|
||||
handlingCapacity: number;
|
||||
photo: string;
|
||||
intro: string;
|
||||
status: string;
|
||||
port: PortType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 码头分页列表类型
|
||||
*/
|
||||
|
@ -268,3 +294,18 @@ export interface ProvinceCityType {
|
|||
code: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 车架号查询结果类型
|
||||
*/
|
||||
export interface vinSearchType {
|
||||
id: number;
|
||||
createBy: number;
|
||||
createDate: string;
|
||||
updateBy: number;
|
||||
updateDate: string;
|
||||
version: number;
|
||||
scheduleId: number;
|
||||
shipStatus: string;
|
||||
schedule: BoatInfoType;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { PageRowsType } from '.';
|
||||
|
||||
/**
|
||||
* 帮助中心类型
|
||||
*/
|
||||
|
@ -31,6 +33,13 @@ export interface ApiManageType {
|
|||
resp: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* api接口分页类型
|
||||
*/
|
||||
export interface ApiManagePageType extends PageRowsType {
|
||||
apiType: '基础数据' | '信息发布' | '信息订阅' | '信息查询';
|
||||
}
|
||||
|
||||
/**
|
||||
* 首页数据统计接口
|
||||
*/
|
||||
|
@ -60,3 +69,17 @@ export interface OutImportVoyages {
|
|||
fields: any[];
|
||||
datas: any[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 协议类型
|
||||
*/
|
||||
export interface agreeTextType {
|
||||
id: number;
|
||||
createBy: number;
|
||||
createDate: string;
|
||||
updateBy: number;
|
||||
updateDate: string;
|
||||
version: number;
|
||||
content: string;
|
||||
textType: string;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ export interface roleType {
|
|||
* 添加角色操作权限
|
||||
*/
|
||||
export interface rolePremType {
|
||||
roleId: number;
|
||||
perms: any[];
|
||||
userId: number | string;
|
||||
perms: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,6 +51,6 @@ export const checkStatus = (status: number, message?: string | Array<string>): v
|
|||
if (message) {
|
||||
errMsg = typeof message === 'string' ? message : message[0];
|
||||
}
|
||||
ElMessage.error('请求失败!');
|
||||
ElMessage.error(errMsg || '请求失败!');
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,119 +1,82 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="`${dialogProps.title}码头`"
|
||||
width="80%"
|
||||
@close="onCloseDialog"
|
||||
>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
label-width="auto"
|
||||
:rules="formRules"
|
||||
:disabled="dialogProps.isView"
|
||||
:model="dialogProps.row"
|
||||
:hide-required-asterisk="dialogProps.isView"
|
||||
>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="dialogProps.row!.name" placeholder="请输入名称" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 接口地址 -->
|
||||
<el-form-item label="接口地址" prop="url">
|
||||
<el-input v-model="dialogProps.row!.url" placeholder="请输入接口地址" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 功能描述 -->
|
||||
<el-form-item label="功能描述" prop="remark">
|
||||
<el-input v-model="dialogProps.row!.remark" placeholder="请输入功能描述" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 接口参数 -->
|
||||
<el-form-item label="接口参数" prop="req">
|
||||
<el-input v-model="dialogProps.row!.req" placeholder="请输入接口参数" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 接口返回 -->
|
||||
<el-form-item label="接口返回" prop="resp">
|
||||
<el-input v-model="dialogProps.row!.resp" placeholder="请输入接口返回" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-dialog v-model="dialogVisible" title="查看接口" width="80%" @close="onCloseDialog">
|
||||
<div class="content">
|
||||
<div class="item">
|
||||
<div class="title">接口名称:</div>
|
||||
<div class="text">{{ dialogProps?.name }}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="title">接口地址:</div>
|
||||
<div class="text">{{ dialogProps?.url }}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="title">接口功能:</div>
|
||||
<div class="text">{{ dialogProps?.remark }}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="title">接口参数:</div>
|
||||
<div class="text">{{ dialogProps?.req }}</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="title">接口返回:</div>
|
||||
<div class="text">{{ dialogProps?.resp }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button v-show="!dialogProps.isView" type="primary" @click="onClickConfirm(ruleFormRef)">
|
||||
确认
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, FormInstance, FormRules } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import {} from 'element-plus';
|
||||
import { ref } from 'vue';
|
||||
import { postApiGetAPI } from '@/api/ApiManage';
|
||||
import { ApiManageType } from '@/types/help';
|
||||
|
||||
interface DialogPropsType {
|
||||
title: string;
|
||||
isView: boolean;
|
||||
row: Partial<ApiManageType>;
|
||||
api?: (params: any) => Promise<any>;
|
||||
getTableList?: () => void;
|
||||
}
|
||||
|
||||
// 是否显示dialog
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
// 父组件传递的值
|
||||
const dialogProps = ref<DialogPropsType>({
|
||||
isView: false,
|
||||
title: '',
|
||||
row: {},
|
||||
});
|
||||
const dialogProps = ref<ApiManageType>();
|
||||
|
||||
// 获取接口详情
|
||||
const getApiManageData = async (id: string | number) => {
|
||||
const { data } = await postApiGetAPI({ id });
|
||||
dialogProps.value = data;
|
||||
};
|
||||
|
||||
// 显示dialog,新增/编辑订阅
|
||||
const isShowDialog = (params: DialogPropsType) => {
|
||||
dialogProps.value = params;
|
||||
const isShowDialog = async (params: ApiManageType) => {
|
||||
params.id && (await getApiManageData(params.id));
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 向父组件暴露该方法
|
||||
defineExpose({ isShowDialog });
|
||||
|
||||
const formRules = reactive<FormRules>({
|
||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||
url: [{ required: true, message: '请输入接口地址', trigger: 'blur' }],
|
||||
remark: [{ required: true, message: '请输入功能描述', trigger: 'blur' }],
|
||||
req: [{ required: true, message: '请输入接口参数', trigger: 'blur' }],
|
||||
resp: [{ required: true, message: '请输入接口返回', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 表单节点
|
||||
const ruleFormRef = ref<FormInstance>();
|
||||
|
||||
// dialog 关闭事件
|
||||
const onCloseDialog = () => {
|
||||
// 重置表单
|
||||
ruleFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
// 新增/编辑
|
||||
const onClickConfirm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
try {
|
||||
await dialogProps.value.api!(dialogProps.value.row);
|
||||
ElMessage({
|
||||
message: `${dialogProps.value.title}成功`,
|
||||
type: 'success',
|
||||
});
|
||||
dialogProps.value.getTableList!();
|
||||
} finally {
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
font-size: 16px;
|
||||
line-height: 27px;
|
||||
.title {
|
||||
font-weight: 700;
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,22 +1,30 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="footer">
|
||||
<div class="footer-util">滚装船货信息平台API开放接口文档</div>
|
||||
<div class="footer-util">
|
||||
<div class="title">滚装船货信息平台API开放接口文档</div>
|
||||
<div class="api-btn">
|
||||
<div
|
||||
class="btn"
|
||||
:class="{ 'btn-active': currentApiType === item }"
|
||||
v-for="item in apiTypeList"
|
||||
:key="item"
|
||||
@click="onClickChangeApiType(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
<el-table
|
||||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="name" label="名称" align="center" width="180" />
|
||||
<el-table-column prop="url" label="接口地址" align="center" width="150" />
|
||||
<el-table-column prop="remark" label="功能描述" align="center" width="200" />
|
||||
<el-table-column prop="req" label="接口参数" align="center" width="150" />
|
||||
<el-table-column prop="resp" label="接口返回" align="center" width="150" />
|
||||
<el-table-column prop="createDate" label="创建时间" align="center" width="180" />
|
||||
<el-table-column prop="remark" label="功能描述" align="center" />
|
||||
<el-table-column prop="operator" label="操作" width="200px" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
|
@ -24,7 +32,7 @@
|
|||
size="small"
|
||||
icon="View"
|
||||
link
|
||||
@click="onClickOpenDialog('查看', scope.row)"
|
||||
@click="onClickOpenDialog(scope.row)"
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
|
@ -47,18 +55,38 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { postApiPageAPI, postApiSaveAPI } from '@/api/ApiManage';
|
||||
import { postApiPageAPI } from '@/api/ApiManage';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
import { ApiManageType } from '@/types/help';
|
||||
import ApiDialog from './ApiDialog.vue';
|
||||
|
||||
type apiInterface = '基础数据' | '信息发布' | '信息订阅' | '信息查询';
|
||||
|
||||
// api类型列表
|
||||
const apiTypeList = ref<apiInterface[]>(['基础数据', '信息发布', '信息订阅', '信息查询']);
|
||||
const currentApiType = ref<apiInterface>('基础数据');
|
||||
const onClickChangeApiType = async (item: apiInterface) => {
|
||||
if (item === currentApiType.value) return;
|
||||
|
||||
currentApiType.value = item;
|
||||
// 添加查询参数
|
||||
tableState.value.searchParam = {
|
||||
apiType: item,
|
||||
};
|
||||
await searchTable();
|
||||
};
|
||||
|
||||
// 获取列表表格数据
|
||||
const { getTableList, tableState, tableChangeCurrent, tableChangeSize } = useTable({
|
||||
const { getTableList, tableState, searchTable, tableChangeCurrent, tableChangeSize } = useTable({
|
||||
api: postApiPageAPI,
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
tableState.value.searchInitParam = {
|
||||
apiType: currentApiType.value,
|
||||
};
|
||||
|
||||
await getTableList();
|
||||
});
|
||||
|
||||
|
@ -66,15 +94,8 @@ const tableLoading = ref(false);
|
|||
|
||||
// 新增/编辑企业
|
||||
const apiDialogRef = ref<InstanceType<typeof ApiDialog> | null>(null);
|
||||
const onClickOpenDialog = (title: string, row: Partial<ApiManageType> = {}) => {
|
||||
const params = {
|
||||
title,
|
||||
isView: title === '查看',
|
||||
row: { ...row },
|
||||
api: postApiSaveAPI,
|
||||
getTableList,
|
||||
};
|
||||
apiDialogRef.value?.isShowDialog(params);
|
||||
const onClickOpenDialog = (row: ApiManageType) => {
|
||||
apiDialogRef.value?.isShowDialog(row);
|
||||
};
|
||||
|
||||
// 改变每页显示条目个数
|
||||
|
@ -99,7 +120,6 @@ const handleCurrentChange = async (val: number) => {
|
|||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
}
|
||||
|
@ -111,18 +131,44 @@ const handleCurrentChange = async (val: number) => {
|
|||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
font-size: 30px;
|
||||
color: #fff;
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.api-btn {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
color: #d7d7d7;
|
||||
background-color: rgb(51 51 51 / 100%);
|
||||
border-radius: 75px;
|
||||
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
|
||||
}
|
||||
.btn-active {
|
||||
color: #000;
|
||||
background-color: #f2f2f2;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer-table {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="Manage">
|
||||
<BoatTable />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import BoatTable from './components/BoatTable.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -18,6 +18,9 @@
|
|||
<el-button icon="Refresh" @click="onClickResetForm(tableFormRef)">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div>
|
||||
<el-button type="success" @click="onClickExport">船期导出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<!-- 表格 -->
|
||||
|
@ -26,7 +29,6 @@
|
|||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="enterprise.name" label="企业" align="center" width="150" />
|
||||
|
@ -61,7 +63,7 @@
|
|||
<el-table-column prop="loadPort.name" label="装货港口" align="center" width="150" />
|
||||
<el-table-column prop="dischargePort.name" label="卸货港口" align="center" width="150" />
|
||||
<el-table-column prop="createDate" label="创建时间" align="center" width="180" />
|
||||
<!-- <el-table-column prop="operator" label="操作" width="200px" align="center" fixed="right">
|
||||
<el-table-column prop="operator" label="操作" width="200px" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
|
@ -73,7 +75,7 @@
|
|||
查看
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
|
@ -90,9 +92,13 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import dayjs from 'dayjs';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { getSailSchedulePageAPI } from '@/api/Boat/info';
|
||||
import {
|
||||
getSailScheduleExportAPI,
|
||||
getSailScheduleGetAPI,
|
||||
getSailSchedulePageAPI,
|
||||
} from '@/api/Boat/info';
|
||||
import { postShipListAPI } from '@/api/Ship';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import RemoteSelect from '@/components/RemoteSelect/index.vue';
|
||||
|
@ -151,11 +157,55 @@ const onClickResetForm = async (formEl: FormInstance | undefined) => {
|
|||
formEl.resetFields();
|
||||
};
|
||||
|
||||
const onClickExport = () => {
|
||||
ElMessageBox.confirm(`你确定要导出船期信息吗?`, '温馨提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
draggable: true,
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
let params: any = {
|
||||
rows: tableState.value.pageAble.rows,
|
||||
page: tableState.value.pageAble.page,
|
||||
};
|
||||
if (searchTableForm.shipId) {
|
||||
params.shipId = searchTableForm.shipId;
|
||||
}
|
||||
if (searchTableForm.voyage) {
|
||||
params.voyage = searchTableForm.voyage;
|
||||
}
|
||||
const { data } = await getSailScheduleExportAPI(params);
|
||||
const blob = new Blob([data], {
|
||||
type: 'application/vnd.ms-excel;charset=utf-8',
|
||||
});
|
||||
const downloadUrl = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = downloadUrl;
|
||||
link.download = '船期信息.xlsx';
|
||||
link.click();
|
||||
ElMessage({
|
||||
message: '导出成功',
|
||||
type: 'success',
|
||||
});
|
||||
} catch (error) {
|
||||
ElMessage({
|
||||
message: '导出失败',
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('用户点击了取消');
|
||||
});
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
// const onClickOpenDetail = async (row: BoatInfoType) => {
|
||||
// const { data } = await getSailScheduleGetAPI({ id: row.id });
|
||||
// console.log('🚀 ~ file: BoatTable.vue:146 ~ onClickOpenDetail ~ data:', data);
|
||||
// };
|
||||
const onClickOpenDetail = async (row: BoatInfoType) => {
|
||||
const { data } = await getSailScheduleGetAPI({ id: row.id });
|
||||
console.log('🚀 ~ file: BoatTable.vue:146 ~ onClickOpenDetail ~ data:', data);
|
||||
};
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
|
@ -177,11 +227,8 @@ const handleCurrentChange = async (val: number) => {
|
|||
width: 100%;
|
||||
.header {
|
||||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
justify-content: space-between;
|
||||
padding: 0 16px;
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
|
@ -191,9 +238,6 @@ const handleCurrentChange = async (val: number) => {
|
|||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
|
@ -0,0 +1,92 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<div class="title">{{ currentSubscribeNav }}</div>
|
||||
<div class="api-btn">
|
||||
<div
|
||||
class="btn"
|
||||
:class="{ 'btn-active': currentSubscribeNav === item }"
|
||||
v-for="item in subscribeNavList"
|
||||
:key="item"
|
||||
@click="onClickChangeSubscribeType(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<BoatTable v-if="currentSubscribeNav === '船期信息'" />
|
||||
<!-- <ManifestDetailTable v-if="currentSubscribeNav === '船图查询'" /> -->
|
||||
<!-- <ReceiveTable v-if="currentSubscribeNav === '船位跟踪'" /> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
// import ManifestDetailTable from './components/ManifestDetailTable.vue';
|
||||
import BoatTable from './components/BoatTable.vue';
|
||||
|
||||
// 订阅导航列表
|
||||
const subscribeNavList = ref(['船期信息', '船图查询', '船位跟踪']);
|
||||
const currentSubscribeNav = ref('船期信息');
|
||||
const onClickChangeSubscribeType = async (item: string) => {
|
||||
if (item === currentSubscribeNav.value) return;
|
||||
currentSubscribeNav.value = item;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.header {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 15px;
|
||||
color: #fff;
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.api-btn {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
color: #d7d7d7;
|
||||
background-color: rgb(51 51 51 / 100%);
|
||||
border-radius: 75px;
|
||||
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
|
||||
}
|
||||
.btn-active {
|
||||
color: #000;
|
||||
background-color: #f2f2f2;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,19 +0,0 @@
|
|||
<template>
|
||||
<div class="manage">
|
||||
<CompanyRegister :isShowBackBtn="false" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import CompanyRegister from '@/views/Login/register.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manage {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 25px;
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="manage">
|
||||
<EmployeeTable />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import EmployeeTable from './components/EmployeeTable.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -1,239 +0,0 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="`${dialogProps.title}企业`"
|
||||
width="80%"
|
||||
@close="onCloseDialog"
|
||||
>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
label-width="auto"
|
||||
:rules="formRules"
|
||||
:disabled="dialogProps.isView"
|
||||
:model="dialogProps.row"
|
||||
:hide-required-asterisk="dialogProps.isView"
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="企业类型" prop="enterpriseType" required>
|
||||
<el-select
|
||||
v-model="dialogProps.row!.enterpriseType"
|
||||
placeholder="请选择企业类型"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in companyTypeList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="港口" prop="portId" required>
|
||||
<RemoteSelect
|
||||
v-model:value="dialogProps.row!.portId"
|
||||
placeholder="请选择港口"
|
||||
:api="postPortListAPI"
|
||||
:disabled="dialogProps.isView"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="企业全称" prop="name">
|
||||
<el-input v-model="dialogProps.row!.name" placeholder="请输入企业全称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="企业统一社会信用代码" prop="code">
|
||||
<el-input v-model="dialogProps.row!.code" placeholder="请输入企业统一社会信用代码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="合同编号" prop="contractNo">
|
||||
<el-input v-model="dialogProps.row!.contractNo" placeholder="请输入合同编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="法定代表人" prop="legalPerson">
|
||||
<el-input v-model="dialogProps.row!.legalPerson" placeholder="请输入法定代表人" />
|
||||
</el-form-item>
|
||||
<el-form-item label="地址" prop="address">
|
||||
<el-input v-model="dialogProps.row!.address" placeholder="请输入企业地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="企业状态">
|
||||
<el-tag v-if="dialogProps.row!.enterpriseStatus === '正常'" type="success">
|
||||
{{ dialogProps.row!.enterpriseStatus }}
|
||||
</el-tag>
|
||||
<el-tag v-else-if="dialogProps.row!.enterpriseStatus === '待审核'" type="danger">
|
||||
{{ dialogProps.row!.enterpriseStatus }}
|
||||
</el-tag>
|
||||
<el-tag v-else-if="dialogProps.row!.enterpriseStatus === '已注册'" type="primary">
|
||||
{{ dialogProps.row!.enterpriseStatus }}
|
||||
</el-tag>
|
||||
<el-tag v-else type="info">{{ dialogProps.row!.enterpriseStatus }}</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="营业执照" prop="licensePhoto">
|
||||
<UploadImg
|
||||
v-model:imageID="dialogProps.row!.licensePhoto"
|
||||
width="135px"
|
||||
height="135px"
|
||||
:file-size="3"
|
||||
:fileNo="dialogProps.row!.code"
|
||||
:companyID="dialogProps.row!.id"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系人" prop="linkman">
|
||||
<el-input v-model="dialogProps.row!.linkman" placeholder="请输入联系人姓名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="dialogProps.row!.phone" placeholder="请填写手机号码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证" prop="idPhoto">
|
||||
<UploadImg
|
||||
v-model:imageID="dialogProps.row!.idPhoto"
|
||||
width="135px"
|
||||
height="135px"
|
||||
:file-size="3"
|
||||
:imgType="1"
|
||||
:fileNo="dialogProps.row!.phone"
|
||||
:companyID="dialogProps.row!.id"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button
|
||||
v-if="dialogProps.row!.enterpriseStatus === '待审核'"
|
||||
type="success"
|
||||
@click="onClickRegPass(dialogProps.row.id!)"
|
||||
>审核通过</el-button
|
||||
>
|
||||
<el-button v-show="!dialogProps.isView" type="primary" @click="onClickConfirm(ruleFormRef)"
|
||||
>确认</el-button
|
||||
>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { postEnterpriseRegPassAPI } from '@/api/Enterprise/company';
|
||||
import { postPortListAPI } from '@/api/Port';
|
||||
import RemoteSelect from '@/components/RemoteSelect/index.vue';
|
||||
import UploadImg from '@/components/Upload/img.vue';
|
||||
import { EnterpriseType } from '@/types/boatInfo';
|
||||
|
||||
interface DialogPropsType {
|
||||
title: string;
|
||||
isView: boolean;
|
||||
row: Partial<EnterpriseType>;
|
||||
api?: (params: any) => Promise<any>;
|
||||
getTableList?: () => void;
|
||||
}
|
||||
|
||||
// 企业列表
|
||||
const companyTypeList = [
|
||||
{
|
||||
value: '港口码头',
|
||||
label: '港口码头',
|
||||
},
|
||||
{
|
||||
value: '船公司',
|
||||
label: '船公司',
|
||||
},
|
||||
{
|
||||
value: '货主',
|
||||
label: '货主',
|
||||
},
|
||||
{
|
||||
value: '船代',
|
||||
label: '船代',
|
||||
},
|
||||
{
|
||||
value: '货贷',
|
||||
label: '货贷',
|
||||
},
|
||||
];
|
||||
|
||||
// 是否显示dialog
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
// 父组件传递的值
|
||||
const dialogProps = ref<DialogPropsType>({
|
||||
isView: false,
|
||||
title: '',
|
||||
row: {},
|
||||
});
|
||||
|
||||
// 显示dialog,新增/编辑订阅
|
||||
const isShowDialog = (params: DialogPropsType) => {
|
||||
dialogProps.value = params;
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 向父组件暴露该方法
|
||||
defineExpose({ isShowDialog });
|
||||
|
||||
// 校验规则
|
||||
const formRules = reactive<FormRules>({
|
||||
name: [{ required: true, message: '请输入企业全称', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入企业统一社会信用代码', trigger: 'blur' }],
|
||||
address: [{ required: true, message: '请输入企业地址', trigger: 'blur' }],
|
||||
legalPerson: [{ required: true, message: '请输入法定代表人', trigger: 'blur' }],
|
||||
contractNo: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
linkman: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
|
||||
phone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
|
||||
portId: [{ required: true, message: '请选择港口', trigger: 'blur' }],
|
||||
licensePhoto: [{ required: true, message: '请上传营业执照', trigger: 'blur' }],
|
||||
idPhoto: [{ required: true, message: '请上传身份证照片', trigger: 'blur' }],
|
||||
enterpriseType: [{ required: true, message: '请选择企业类型', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 表单节点
|
||||
const ruleFormRef = ref<FormInstance>();
|
||||
|
||||
// dialog 关闭事件
|
||||
const onCloseDialog = () => {
|
||||
// 重置表单
|
||||
ruleFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
// 审核通过
|
||||
const onClickRegPass = (id: number) => {
|
||||
ElMessageBox.confirm('确定审核通过吗?', '温馨提示', {
|
||||
confirmButtonText: '确认',
|
||||
cancelButtonText: '取消',
|
||||
type: 'info',
|
||||
}).then(async () => {
|
||||
try {
|
||||
await postEnterpriseRegPassAPI([id]);
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: '审核通过',
|
||||
});
|
||||
dialogProps.value.getTableList!();
|
||||
} finally {
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 新增/编辑用户
|
||||
const onClickConfirm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
try {
|
||||
await dialogProps.value.api!(dialogProps.value.row);
|
||||
ElMessage({
|
||||
message: `${dialogProps.value.title}成功`,
|
||||
type: 'success',
|
||||
});
|
||||
dialogProps.value.getTableList!();
|
||||
} finally {
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -1,300 +0,0 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<el-form :inline="true" :model="searchTableForm" ref="tableFormRef">
|
||||
<el-form-item prop="enterpriseStatus">
|
||||
<el-select
|
||||
v-model="searchTableForm.enterpriseStatus"
|
||||
placeholder="请选择状态"
|
||||
style="width: 120px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in companyTypeList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="key">
|
||||
<el-input v-model="searchTableForm.key" placeholder="单位名称或税号" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="onClickSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="onClickResetForm(tableFormRef)">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<!-- <div class="footer-util">
|
||||
<el-button type="primary" icon="Plus" @click="onClickOpenDrawer('新增')">
|
||||
新增订阅
|
||||
</el-button>
|
||||
</div> -->
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
<el-table
|
||||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="name" label="企业全称" align="center" width="180" />
|
||||
<el-table-column prop="legalPerson" label="法定代表人" align="center" width="100" />
|
||||
<el-table-column prop="code" label="企业统一社会信用代码" align="center" width="200" />
|
||||
<el-table-column prop="address" label="地址" align="center" width="180" />
|
||||
<el-table-column prop="enterpriseType" label="企业类型" align="center" width="180" />
|
||||
<el-table-column prop="enterpriseStatus" label="企业状态" align="center" width="120">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.enterpriseStatus === '正常'" type="success">
|
||||
{{ scope.row.enterpriseStatus }}
|
||||
</el-tag>
|
||||
<el-tag v-else-if="scope.row.enterpriseStatus === '待审核'" type="danger">
|
||||
{{ scope.row.enterpriseStatus }}
|
||||
</el-tag>
|
||||
<el-tag v-else-if="scope.row.enterpriseStatus === '已注册'" type="primary">
|
||||
{{ scope.row.enterpriseStatus }}
|
||||
</el-tag>
|
||||
<el-tag v-else type="info">{{ scope.row.enterpriseStatus }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="linkman" label="联系人" align="center" width="120" />
|
||||
<el-table-column prop="phone" label="手机号" align="center" width="120" />
|
||||
<el-table-column prop="createDate" label="创建时间" align="center" width="180" />
|
||||
<el-table-column prop="operator" label="操作" width="200px" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="View"
|
||||
link
|
||||
@click="onClickOpenDialog('查看', scope.row)"
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="Edit"
|
||||
link
|
||||
@click="onClickOpenDialog('编辑', scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
size="small"
|
||||
icon="User"
|
||||
link
|
||||
@click="onClickOpenEmployee(scope.row)"
|
||||
>
|
||||
员工
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
icon="Delete"
|
||||
link
|
||||
@click="onClickDel(scope.row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<div class="footer-pagination">
|
||||
<Pagination
|
||||
:pageAble="tableState.pageAble"
|
||||
:handle-size-change="handleSizeChange"
|
||||
:handle-current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<CompanyDialog ref="companyDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import {
|
||||
postEnterpriseDeleteAPI,
|
||||
postEnterprisePageAPI,
|
||||
postEnterpriseSaveAPI,
|
||||
} from '@/api/Enterprise/company';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
import { EnterpriseType } from '@/types/boatInfo';
|
||||
import CompanyDialog from './CompanyDialog.vue';
|
||||
|
||||
// 获取列表表格数据
|
||||
const { getTableList, tableState, searchTable, resetTable, tableChangeCurrent, tableChangeSize } =
|
||||
useTable({
|
||||
api: postEnterprisePageAPI,
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await getTableList();
|
||||
});
|
||||
|
||||
// 查询条件
|
||||
const searchTableForm = reactive({
|
||||
key: '',
|
||||
enterpriseStatus: '',
|
||||
});
|
||||
|
||||
// 企业状态
|
||||
const companyTypeList = [
|
||||
{
|
||||
value: '待审核',
|
||||
label: '待审核',
|
||||
},
|
||||
{
|
||||
value: '正常',
|
||||
label: '正常',
|
||||
},
|
||||
{
|
||||
value: '已关闭',
|
||||
label: '已关闭',
|
||||
},
|
||||
{
|
||||
value: '已注册',
|
||||
label: '已注册',
|
||||
},
|
||||
];
|
||||
|
||||
// 表格是否加载
|
||||
const tableLoading = ref(false);
|
||||
|
||||
// 查询表单节点
|
||||
const tableFormRef = ref<FormInstance>();
|
||||
|
||||
// 查询
|
||||
const onClickSearch = async () => {
|
||||
tableLoading.value = true;
|
||||
|
||||
// 添加查询参数
|
||||
tableState.value.searchParam = searchTableForm;
|
||||
|
||||
// 查询表格
|
||||
await searchTable();
|
||||
tableLoading.value = false;
|
||||
};
|
||||
|
||||
// 重置
|
||||
const onClickResetForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await resetTable();
|
||||
formEl.resetFields();
|
||||
};
|
||||
|
||||
// 新增/编辑企业
|
||||
const companyDialogRef = ref<InstanceType<typeof CompanyDialog> | null>(null);
|
||||
const onClickOpenDialog = (title: string, row: Partial<EnterpriseType> = {}) => {
|
||||
const params = {
|
||||
title,
|
||||
isView: title === '查看',
|
||||
row: { ...row },
|
||||
api: postEnterpriseSaveAPI,
|
||||
getTableList,
|
||||
};
|
||||
companyDialogRef.value?.isShowDialog(params);
|
||||
};
|
||||
|
||||
// 路由
|
||||
const router = useRouter();
|
||||
|
||||
// 员工
|
||||
const onClickOpenEmployee = (row: EnterpriseType) => {
|
||||
router.push({
|
||||
path: '/enterprise/employee',
|
||||
query: {
|
||||
enterpriseId: row.id,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 删除
|
||||
const onClickDel = (row: EnterpriseType) => {
|
||||
ElMessageBox.confirm(`你确定要删除企业 ${row.name} 吗?`, '温馨提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
draggable: true,
|
||||
})
|
||||
.then(async () => {
|
||||
await postEnterpriseDeleteAPI([row.id]);
|
||||
// 更新表格
|
||||
await getTableList();
|
||||
ElMessage({
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('用户点击了取消');
|
||||
});
|
||||
};
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
await tableChangeSize(val);
|
||||
};
|
||||
|
||||
// 当前页数改变
|
||||
const handleCurrentChange = async (val: number) => {
|
||||
await tableChangeCurrent(val);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
.header {
|
||||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.footer-table {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
}
|
||||
.footer-pagination {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="manage">
|
||||
<CompanyTable />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import CompanyTable from './components/CompanyTable.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,103 @@
|
|||
<template>
|
||||
<div class="agree">
|
||||
<div class="agree-content">
|
||||
<div class="title">{{ agreeText?.textType }}</div>
|
||||
<div class="content" v-html="agreeText?.content"></div>
|
||||
</div>
|
||||
<div class="agree-btn" v-if="textType === 'AGREEMENT' && !isAgree">
|
||||
<el-checkbox v-model="checked" size="large">
|
||||
<div class="btn-text">我已经完整阅读,并同意用户协议</div>
|
||||
</el-checkbox>
|
||||
|
||||
<el-button type="primary" @click="onClickAgree">同意,并不再提示</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { postTextAgreeAPI, postTextGetAPI, postTextIsAgreeAPI } from '@/api/Help';
|
||||
import { agreeTextType } from '@/types/help';
|
||||
|
||||
interface propsType {
|
||||
textType: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<propsType>(), {
|
||||
textType: '',
|
||||
});
|
||||
|
||||
// 协议规则内容
|
||||
const agreeText = ref<agreeTextType>();
|
||||
|
||||
// 判断用户是否同意了协议
|
||||
const isAgree = ref(false);
|
||||
const checked = ref(false);
|
||||
|
||||
// 获取协议规则
|
||||
const getAgreeText = async () => {
|
||||
const { data } = await postTextGetAPI({ textType: props.textType });
|
||||
agreeText.value = data;
|
||||
// 判断是用户协议还是共享规则
|
||||
if (props.textType === 'AGREEMENT') {
|
||||
// 判断用户是否同意了协议
|
||||
const { data: isAgreeData } = await postTextIsAgreeAPI();
|
||||
isAgree.value = isAgreeData;
|
||||
}
|
||||
};
|
||||
|
||||
// 同意协议
|
||||
const onClickAgree = async () => {
|
||||
if (checked.value) {
|
||||
await postTextAgreeAPI();
|
||||
isAgree.value = true;
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: '请勾选同意用户协议',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await getAgreeText();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.agree {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.agree-content {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
.title {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 50px;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
}
|
||||
.agree-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
.btn-text {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,116 +0,0 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:title="`${dialogProps.title}`"
|
||||
width="80%"
|
||||
@close="onCloseDialog"
|
||||
>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
label-width="auto"
|
||||
:rules="formRules"
|
||||
:disabled="dialogProps.isView"
|
||||
:model="dialogProps.row"
|
||||
:hide-required-asterisk="dialogProps.isView"
|
||||
>
|
||||
<el-form-item label="序号" prop="serial">
|
||||
<el-input v-model="dialogProps.row!.serial" placeholder="请输入序号" type="number" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 名称 -->
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="dialogProps.row!.name" placeholder="请输入名称" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 备注 -->
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="dialogProps.row!.remark" placeholder="请输入备注" type="textarea" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 类型 -->
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select v-model="dialogProps.row!.type" placeholder="请选择类型">
|
||||
<el-option label="主题" value="主题" />
|
||||
<el-option label="问题" value="问题" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button v-show="!dialogProps.isView" type="primary" @click="onClickConfirm(ruleFormRef)">
|
||||
确认
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, FormInstance, FormRules } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { HelpType } from '@/types/help';
|
||||
|
||||
interface DialogPropsType {
|
||||
title: string;
|
||||
isView: boolean;
|
||||
row: Partial<HelpType>;
|
||||
api?: (params: any) => Promise<any>;
|
||||
getTableList?: () => void;
|
||||
}
|
||||
|
||||
// 是否显示dialog
|
||||
const dialogVisible = ref(false);
|
||||
|
||||
// 父组件传递的值
|
||||
const dialogProps = ref<DialogPropsType>({
|
||||
isView: false,
|
||||
title: '',
|
||||
row: {},
|
||||
});
|
||||
|
||||
// 显示dialog,新增/编辑订阅
|
||||
const isShowDialog = (params: DialogPropsType) => {
|
||||
dialogProps.value = params;
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 向父组件暴露该方法
|
||||
defineExpose({ isShowDialog });
|
||||
|
||||
const formRules = reactive<FormRules>({
|
||||
serial: [{ required: true, message: '请输入序号', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
|
||||
remark: [{ required: true, message: '请输入备注', trigger: 'blur' }],
|
||||
type: [{ required: true, message: '请选择类型', trigger: 'change' }],
|
||||
});
|
||||
|
||||
// 表单节点
|
||||
const ruleFormRef = ref<FormInstance>();
|
||||
|
||||
// dialog 关闭事件
|
||||
const onCloseDialog = () => {
|
||||
// 重置表单
|
||||
ruleFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
// 新增/编辑
|
||||
const onClickConfirm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
try {
|
||||
await dialogProps.value.api!(dialogProps.value.row);
|
||||
ElMessage({
|
||||
message: `${dialogProps.value.title}成功`,
|
||||
type: 'success',
|
||||
});
|
||||
dialogProps.value.getTableList!();
|
||||
} finally {
|
||||
dialogVisible.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -1,135 +1,141 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="footer">
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
<el-table
|
||||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
<div class="notify">
|
||||
<div class="list">
|
||||
<ul
|
||||
class="list-wrap"
|
||||
v-infinite-scroll="helpListLoad"
|
||||
:infinite-scroll-disabled="disabled"
|
||||
:infinite-scroll-distance="100"
|
||||
>
|
||||
<el-table-column prop="serial" label="序号" align="center" width="80" />
|
||||
<el-table-column prop="name" label="名称" align="center" width="180" />
|
||||
<el-table-column prop="remark" label="备注" align="center" width="200" />
|
||||
<el-table-column prop="type" label="状态" align="center" width="120" />
|
||||
<el-table-column prop="createDate" label="创建时间" align="center" width="180" />
|
||||
<el-table-column prop="operator" label="操作" width="200px" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="View"
|
||||
link
|
||||
@click="onClickOpenDialog('查看', scope.row)"
|
||||
<li
|
||||
v-for="item in helpDocsList"
|
||||
:key="item.id"
|
||||
class="list-item"
|
||||
@click="onClickOpenDialog(item)"
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<div class="footer-pagination">
|
||||
<Pagination
|
||||
:pageAble="tableState.pageAble"
|
||||
:handle-size-change="handleSizeChange"
|
||||
:handle-current-change="handleCurrentChange"
|
||||
/>
|
||||
<div class="item-icon"></div>
|
||||
<div class="item-title">{{ item.name }}</div>
|
||||
<div class="item-date">{{ item.createDate }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="content">
|
||||
<div class="title">{{ helpDocsData?.name }}</div>
|
||||
<div class="wrap" v-html="helpDocsData?.remark"></div>
|
||||
</div>
|
||||
</div>
|
||||
<HelpDialog ref="helpDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { postHelpPageAPI, postHelpSaveAPI } from '@/api/Help';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
import { computed, ref } from 'vue';
|
||||
import { postHelpGetAPI, postHelpPageAPI } from '@/api/Help';
|
||||
import { HelpType } from '@/types/help';
|
||||
import HelpDialog from './HelpDialog.vue';
|
||||
|
||||
const helpDocsList = ref<HelpType[]>([]);
|
||||
const helpDocsData = ref<HelpType>();
|
||||
|
||||
// 分页参数-当前页数
|
||||
const currentPage = ref(1);
|
||||
|
||||
// 加载更多状态
|
||||
const loadMoreState = ref('loading');
|
||||
const disabled = computed(() => loadMoreState.value === 'finished');
|
||||
|
||||
// 获取列表表格数据
|
||||
const { getTableList, tableState, tableChangeCurrent, tableChangeSize } = useTable({
|
||||
api: postHelpPageAPI,
|
||||
});
|
||||
const getHelpDocsList = async () => {
|
||||
const { data } = await postHelpPageAPI({
|
||||
page: currentPage.value,
|
||||
rows: 10,
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await getTableList();
|
||||
});
|
||||
|
||||
// 表格是否加载
|
||||
const tableLoading = ref(false);
|
||||
|
||||
// 新增/编辑企业
|
||||
const helpDialogRef = ref<InstanceType<typeof HelpDialog> | null>(null);
|
||||
const onClickOpenDialog = (title: string, row: Partial<HelpType> = {}) => {
|
||||
const params = {
|
||||
title,
|
||||
isView: title === '查看',
|
||||
row: { ...row },
|
||||
api: postHelpSaveAPI,
|
||||
getTableList,
|
||||
};
|
||||
helpDialogRef.value?.isShowDialog(params);
|
||||
helpDocsList.value = [...helpDocsList.value, ...data.records];
|
||||
currentPage.value++;
|
||||
// 检查是否到达最后一页或当前数据不足一页
|
||||
if (currentPage.value >= Number(data.pages) || data.records.length < 10) {
|
||||
loadMoreState.value = 'finished';
|
||||
} else {
|
||||
loadMoreState.value = 'loading';
|
||||
}
|
||||
};
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
await tableChangeSize(val);
|
||||
const helpListLoad = async () => {
|
||||
await getHelpDocsList();
|
||||
};
|
||||
|
||||
// 当前页数改变
|
||||
const handleCurrentChange = async (val: number) => {
|
||||
await tableChangeCurrent(val);
|
||||
const onClickOpenDialog = async (row: HelpType) => {
|
||||
const { data } = await postHelpGetAPI({ id: row.id });
|
||||
helpDocsData.value = data;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
.notify {
|
||||
width: 100%;
|
||||
.header {
|
||||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
color: #fff;
|
||||
.list {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.list-wrap {
|
||||
box-sizing: border-box;
|
||||
width: 30%;
|
||||
height: 500px;
|
||||
overflow: auto;
|
||||
.list-item {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 10px 0;
|
||||
overflow: hidden;
|
||||
.item-icon {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 10px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 15px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.footer-table {
|
||||
position: relative;
|
||||
.item-title {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.footer-pagination {
|
||||
.item-date {
|
||||
margin-left: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
margin-left: 20px;
|
||||
font-size: 21px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
.title {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
justify-content: center;
|
||||
padding: 16px;
|
||||
font-size: 23px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.wrap {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding-top: 20px;
|
||||
height: calc(100% - 70px);
|
||||
padding: 0 16px 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,92 @@
|
|||
<template>
|
||||
<div class="manage">
|
||||
<HelpTable />
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<div class="title">帮助信息</div>
|
||||
<div class="api-btn">
|
||||
<div
|
||||
class="btn"
|
||||
:class="{ 'btn-active': currentNav === item }"
|
||||
v-for="item in helpDocsList"
|
||||
:key="item"
|
||||
@click="onClickChangeNav(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<HelpTable v-if="currentNav === '分类主题'" />
|
||||
<AgreeText v-if="currentNav === '用户协议'" textType="AGREEMENT" />
|
||||
<AgreeText v-if="currentNav === '共享规则'" textType="RULE" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import AgreeText from './components/AgreeText.vue';
|
||||
import HelpTable from './components/HelpTable.vue';
|
||||
|
||||
// 帮助文档列表
|
||||
const helpDocsList = ref(['分类主题', '用户协议', '共享规则']);
|
||||
const currentNav = ref('分类主题');
|
||||
const onClickChangeNav = (item: string) => {
|
||||
if (item === currentNav.value) return;
|
||||
currentNav.value = item;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manage {
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.header {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 15px;
|
||||
color: #fff;
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.api-btn {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
color: #d7d7d7;
|
||||
background-color: rgb(51 51 51 / 100%);
|
||||
border-radius: 75px;
|
||||
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
|
||||
}
|
||||
.btn-active {
|
||||
color: #000;
|
||||
background-color: #f2f2f2;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<!-- <div class="header">
|
||||
<el-form :inline="true" :model="searchTableForm" ref="tableFormRef">
|
||||
<el-form-item>
|
||||
<RemoteSelect
|
||||
|
@ -18,7 +18,7 @@
|
|||
<el-button icon="Refresh" @click="onClickResetForm(tableFormRef)">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="footer">
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
|
@ -26,7 +26,6 @@
|
|||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="enterprise.name" label="企业" align="center" width="150" />
|
||||
|
@ -76,55 +75,23 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { getHistoryListAPI } from '@/api/Boat/info';
|
||||
import { postShipListAPI } from '@/api/Ship';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { getPublishHistoryListAPI } from '@/api/Boat/info';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import RemoteSelect from '@/components/RemoteSelect/index.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
|
||||
// 获取用户列表表格数据
|
||||
const { getTableList, tableState, searchTable, resetTable, tableChangeCurrent, tableChangeSize } =
|
||||
useTable({
|
||||
api: getHistoryListAPI,
|
||||
});
|
||||
const { getTableList, tableState, tableChangeCurrent, tableChangeSize } = useTable({
|
||||
api: getPublishHistoryListAPI,
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await getTableList();
|
||||
});
|
||||
|
||||
// 查询条件
|
||||
const searchTableForm = reactive({
|
||||
shipId: '',
|
||||
voyage: '',
|
||||
});
|
||||
|
||||
// 表格是否加载
|
||||
const tableLoading = ref(false);
|
||||
|
||||
// 查询表单节点
|
||||
const tableFormRef = ref<FormInstance>();
|
||||
|
||||
// 查询
|
||||
const onClickSearch = async () => {
|
||||
tableLoading.value = true;
|
||||
|
||||
// 添加查询参数
|
||||
tableState.value.searchParam = searchTableForm;
|
||||
|
||||
// 查询表格
|
||||
await searchTable();
|
||||
tableLoading.value = false;
|
||||
};
|
||||
|
||||
// 重置
|
||||
const onClickResetForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await resetTable();
|
||||
formEl.resetFields();
|
||||
};
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
await tableChangeSize(val);
|
||||
|
@ -147,9 +114,7 @@ const handleCurrentChange = async (val: number) => {
|
|||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
|
@ -159,9 +124,7 @@ const handleCurrentChange = async (val: number) => {
|
|||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
|
@ -0,0 +1,148 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<!-- <div class="header">
|
||||
<el-form :inline="true" :model="searchTableForm" ref="tableFormRef">
|
||||
<el-form-item>
|
||||
<RemoteSelect
|
||||
v-model:value="searchTableForm.shipId"
|
||||
placeholder="请选择船舶"
|
||||
style="width: 120px"
|
||||
:api="postShipListAPI"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input v-model="searchTableForm.voyage" placeholder="请输入航次" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="onClickSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="onClickResetForm(tableFormRef)">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div> -->
|
||||
<div class="footer">
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
<el-table
|
||||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="enterprise.name" label="企业" align="center" width="150" />
|
||||
<el-table-column prop="ship.name" label="船舶" align="center" width="150" />
|
||||
<el-table-column prop="voyage" label="航次" align="center" width="180" />
|
||||
<el-table-column prop="shipRoute.name" label="航线" align="center" width="150" />
|
||||
<el-table-column prop="loadWharf.name" label="装货码头" align="center" width="150" />
|
||||
<el-table-column prop="dischargeWharf.name" label="卸货码头" align="center" width="150" />
|
||||
<el-table-column prop="carNumPlan" label="计划商品车数量" align="center" width="180" />
|
||||
<el-table-column prop="spareNumPlan" label="计划件杂货数量" align="center" width="180" />
|
||||
<el-table-column prop="carNumActual" label="实际商品车数量" align="center" width="180" />
|
||||
<el-table-column
|
||||
prop="spareNumActual"
|
||||
label="实际件杂货数量"
|
||||
align="center"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="departureDatePlan"
|
||||
label="计划离泊时间"
|
||||
align="center"
|
||||
width="200"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="departureDateActual"
|
||||
label="实际离泊时间"
|
||||
align="center"
|
||||
width="200"
|
||||
/>
|
||||
<el-table-column prop="shipStatus" label="船舶状态" align="center" width="150" />
|
||||
<el-table-column prop="tradeType" label="贸易类型" align="center" width="150" />
|
||||
<el-table-column prop="loadPort.name" label="装货港口" align="center" width="150" />
|
||||
<el-table-column prop="dischargePort.name" label="卸货港口" align="center" width="150" />
|
||||
<el-table-column prop="createDate" label="创建时间" align="center" width="180" />
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<div class="footer-pagination">
|
||||
<Pagination
|
||||
:pageAble="tableState.pageAble"
|
||||
:handle-size-change="handleSizeChange"
|
||||
:handle-current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { getReceiveHistoryListAPI } from '@/api/Boat/info';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
|
||||
// 获取用户列表表格数据
|
||||
const { getTableList, tableState, tableChangeCurrent, tableChangeSize } = useTable({
|
||||
api: getReceiveHistoryListAPI,
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await getTableList();
|
||||
});
|
||||
|
||||
// 表格是否加载
|
||||
const tableLoading = ref(false);
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
await tableChangeSize(val);
|
||||
};
|
||||
|
||||
// 当前页数改变
|
||||
const handleCurrentChange = async (val: number) => {
|
||||
await tableChangeCurrent(val);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
.header {
|
||||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
border-radius: 4px;
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.footer-table {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
}
|
||||
.footer-pagination {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,18 +1,91 @@
|
|||
<template>
|
||||
<div class="manage">
|
||||
<HistoryTable />
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<div class="title">历史船货信息</div>
|
||||
<div class="api-btn">
|
||||
<div
|
||||
class="btn"
|
||||
:class="{ 'btn-active': currentHistoryNav === item }"
|
||||
v-for="item in historyNavList"
|
||||
:key="item"
|
||||
@click="onClickChangeHistoryNav(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<PublishTable v-if="currentHistoryNav === '我发布的'" />
|
||||
<ReceiveTable v-if="currentHistoryNav === '我收到的'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import HistoryTable from './components/HistoryTable.vue';
|
||||
import { ref } from 'vue';
|
||||
import PublishTable from './components/PublishTable.vue';
|
||||
import ReceiveTable from './components/ReceiveTable.vue';
|
||||
|
||||
// 历史导航列表
|
||||
const historyNavList = ref(['我发布的', '我收到的']);
|
||||
const currentHistoryNav = ref('我发布的');
|
||||
const onClickChangeHistoryNav = (item: string) => {
|
||||
if (currentHistoryNav.value === item) return;
|
||||
currentHistoryNav.value = item;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manage {
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.header {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 15px;
|
||||
color: #fff;
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.api-btn {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
color: #d7d7d7;
|
||||
background-color: rgb(51 51 51 / 100%);
|
||||
border-radius: 75px;
|
||||
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
|
||||
}
|
||||
.btn-active {
|
||||
color: #000;
|
||||
background-color: #f2f2f2;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
<template>
|
||||
<div class="card">
|
||||
<div class="card-title">{{ title }}</div>
|
||||
<div class="card-text number">{{ number }}</div>
|
||||
<div class="card-text">
|
||||
<div>{{ totalTitle }}</div>
|
||||
<div>{{ totalNumber }}</div>
|
||||
</div>
|
||||
<div class="card-text">{{ number }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -13,38 +9,36 @@
|
|||
defineProps<{
|
||||
title: string;
|
||||
number: number;
|
||||
totalTitle: string;
|
||||
totalNumber: number;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
color: #020817;
|
||||
background-color: #fff;
|
||||
border: 1px solid #e4e4e7;
|
||||
height: 88px;
|
||||
margin: 20px 0;
|
||||
font-size: 32px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
border: 5px solid #d7d7d7;
|
||||
border-radius: 8px;
|
||||
.card-title {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
position: absolute;
|
||||
top: -14px; /* 使标题悬浮在边框上方 */
|
||||
left: 20px; /* 根据需要调整水平位置 */
|
||||
padding: 0 8px; /* 增加一点内边距 */
|
||||
font-size: 15px;
|
||||
color: #fff;
|
||||
background-color: #555;
|
||||
}
|
||||
.card-text {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
padding: 0 10px 10px;
|
||||
}
|
||||
.number {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
height: 100%;
|
||||
color: #80ffff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -22,9 +22,6 @@ defineProps({
|
|||
<style lang="scss" scoped>
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #e4e4e7;
|
||||
border-radius: 8px;
|
||||
height: 200px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,94 +1,151 @@
|
|||
<template>
|
||||
<div class="home">
|
||||
<!-- <div class="home-search">
|
||||
<div class="home-search">
|
||||
<el-form :inline="true" :model="searchTableForm" ref="searchTableFormRef">
|
||||
<el-form-item label="车架号" prop="name">
|
||||
<el-input v-model="searchTableForm.name" placeholder="请输入车架号" />
|
||||
<el-form-item
|
||||
prop="vin"
|
||||
:rules="[{ required: true, message: '请输入车架号', trigger: 'blur' }]"
|
||||
>
|
||||
<template #label>
|
||||
<div class="search-label">车架号</div>
|
||||
</template>
|
||||
<el-input v-model="searchTableForm.vin" placeholder="请输入车架号" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search">查询</el-button>
|
||||
<el-button type="primary" icon="Search" @click="onClickSearch(searchTableFormRef)"
|
||||
>查询</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<template v-if="!isShowVinDialog">
|
||||
<div class="home-header">
|
||||
<el-row :gutter="20">
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="2">
|
||||
<Card
|
||||
title="年度船舶艘次"
|
||||
:number="tableData.yearVoyages"
|
||||
totalTitle="累计船舶艘次"
|
||||
:totalNumber="tableData.totalVoyages"
|
||||
></Card>
|
||||
<el-col :xs="24" :sm="12" :md="6" :lg="3" :xl="3">
|
||||
<Card title="累计船舶艘次" :number="tableData.totalVoyages"></Card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="2">
|
||||
<Card
|
||||
title="本港年度艘次"
|
||||
:number="tableData.yearPortVoyages"
|
||||
totalTitle="本港船舶艘次"
|
||||
:totalNumber="tableData.totalPortVoyages"
|
||||
></Card>
|
||||
<el-col :xs="24" :sm="12" :md="6" :lg="3" :xl="3">
|
||||
<Card title="年度船舶艘次" :number="tableData.yearVoyages"></Card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="2">
|
||||
<Card
|
||||
title="年度货物数量"
|
||||
:number="tableData.yearCargos"
|
||||
totalTitle="累计货物数量"
|
||||
:totalNumber="tableData.totalCargos"
|
||||
></Card>
|
||||
<el-col :xs="24" :sm="12" :md="6" :lg="3" :xl="3">
|
||||
<Card title="本港船舶艘次" :number="tableData.totalPortVoyages"></Card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="2">
|
||||
<Card
|
||||
title="本港年度货物"
|
||||
:number="tableData.yearPortCargos"
|
||||
totalTitle="本港货物累计"
|
||||
:totalNumber="tableData.totalPortCargos"
|
||||
></Card>
|
||||
<el-col :xs="24" :sm="12" :md="6" :lg="3" :xl="3">
|
||||
<Card title="本港年度艘次" :number="tableData.yearPortVoyages"></Card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="6" :lg="3" :xl="3">
|
||||
<Card title="累计货物数量" :number="tableData.totalCargos"></Card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="6" :lg="3" :xl="3">
|
||||
<Card title="年度货物数量" :number="tableData.yearCargos"></Card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="6" :lg="3" :xl="3">
|
||||
<Card title="本港货物累计" :number="tableData.totalPortCargos"></Card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="6" :lg="3" :xl="3">
|
||||
<Card title="本港年度货物" :number="tableData.yearPortCargos"></Card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
|
||||
<div class="home-content">
|
||||
<el-row :gutter="32">
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="4" class="charts">
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="4" class="charts">
|
||||
<HomeChart :option="outImportVoyages" />
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="4" class="charts">
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="4" class="charts">
|
||||
<HomeChart :option="outExportVoyages" />
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="4" class="charts">
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="4" class="charts">
|
||||
<HomeChart :option="inTotalVoyages" />
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="4" class="charts">
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="4" class="charts">
|
||||
<HomeChart :option="inYearVoyages" />
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="4" class="charts">
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="4" class="charts">
|
||||
<HomeChart :option="outImportCargos" />
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="4" class="charts">
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="4" class="charts">
|
||||
<HomeChart :option="outExportCargos" />
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="4" class="charts">
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="4" class="charts">
|
||||
<HomeChart :option="inTotalCargos" />
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="8" :lg="8" :xl="4" class="charts">
|
||||
<el-col :xs="24" :sm="24" :md="6" :lg="6" :xl="4" class="charts">
|
||||
<HomeChart :option="inYearCargos" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="home-footer">
|
||||
<div class="notice">最新公告:{{ noticeData?.title }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="home-vin" v-else>
|
||||
<div class="vin-title">
|
||||
<div class="text">{{ searchTableForm.vin }}</div>
|
||||
的航运物流跟踪
|
||||
</div>
|
||||
<div class="vin-table" v-for="(item, index) in vinData" :key="index">
|
||||
<div>{{ item.schedule.createDate }}</div>
|
||||
<div>{{ item.schedule.loadPort.name }}</div>
|
||||
<div>{{ item.shipStatus }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { ElMessage, FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { getStatisticsAPI } from '@/api/ApiManage';
|
||||
import { getVinSearchAPI } from '@/api/Boat/info';
|
||||
import { noticePageAPI } from '@/api/Notice';
|
||||
import { vinSearchType } from '@/types/boatInfo';
|
||||
import { OutImportVoyages } from '@/types/help';
|
||||
import { NoticeType } from '@/types/notice';
|
||||
import Card from './components/Card.vue';
|
||||
import HomeChart from './components/HomeChart.vue';
|
||||
|
||||
// 查询条件
|
||||
// const searchTableForm = reactive({
|
||||
// name: '',
|
||||
// });
|
||||
const searchTableFormRef = ref();
|
||||
const searchTableForm = reactive({
|
||||
vin: '',
|
||||
});
|
||||
|
||||
const vinData = ref<vinSearchType[]>([]);
|
||||
const isShowVinDialog = ref(false);
|
||||
|
||||
// 车架号查询
|
||||
const onClickSearch = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
const { data } = await getVinSearchAPI({ vin: searchTableForm.vin });
|
||||
if (data.length > 0) {
|
||||
vinData.value = data;
|
||||
isShowVinDialog.value = true;
|
||||
} else {
|
||||
ElMessage({
|
||||
type: 'warning',
|
||||
message: '未查询到数据',
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const noticeData = ref<NoticeType>();
|
||||
|
||||
// 获取公告
|
||||
const getNoticeList = async () => {
|
||||
const { data } = await noticePageAPI({
|
||||
page: 1,
|
||||
rows: 10,
|
||||
});
|
||||
if (data.records.length > 0) {
|
||||
noticeData.value = data.records[0];
|
||||
}
|
||||
};
|
||||
|
||||
// 首页数据
|
||||
const tableData = ref({
|
||||
|
@ -107,6 +164,9 @@ const outImportVoyages = ref({
|
|||
title: {
|
||||
text: '外贸进口艘次',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
bottom: '2%',
|
||||
|
@ -143,6 +203,9 @@ const outExportVoyages = ref({
|
|||
title: {
|
||||
text: '外贸出口艘次',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
bottom: '2%',
|
||||
|
@ -174,11 +237,14 @@ const outExportVoyages = ref({
|
|||
},
|
||||
});
|
||||
|
||||
// 外贸累计艘次
|
||||
// 内贸累计艘次
|
||||
const inTotalVoyages = ref({
|
||||
title: {
|
||||
text: '外贸累计艘次',
|
||||
text: '内贸累计艘次',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
bottom: '2%',
|
||||
|
@ -210,11 +276,14 @@ const inTotalVoyages = ref({
|
|||
},
|
||||
});
|
||||
|
||||
// 外贸年度艘次
|
||||
// 内贸年度艘次
|
||||
const inYearVoyages = ref({
|
||||
title: {
|
||||
text: '外贸年度艘次',
|
||||
text: '内贸年度艘次',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
bottom: '2%',
|
||||
|
@ -251,6 +320,9 @@ const outImportCargos = ref({
|
|||
title: {
|
||||
text: '外贸进口货物',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
bottom: '2%',
|
||||
|
@ -287,6 +359,9 @@ const outExportCargos = ref({
|
|||
title: {
|
||||
text: '外贸出口货物',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
bottom: '2%',
|
||||
|
@ -323,6 +398,9 @@ const inTotalCargos = ref({
|
|||
title: {
|
||||
text: '内贸累计货物',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
bottom: '2%',
|
||||
|
@ -359,6 +437,9 @@ const inYearCargos = ref({
|
|||
title: {
|
||||
text: '内贸年度货物',
|
||||
left: 'center',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
bottom: '2%',
|
||||
|
@ -419,6 +500,7 @@ const handlePieData = (data: OutImportVoyages) => {
|
|||
|
||||
onMounted(async () => {
|
||||
await getHomeStatistics();
|
||||
await getNoticeList();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -428,11 +510,15 @@ onMounted(async () => {
|
|||
height: 100%;
|
||||
.home-search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.search-label {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.home-header {
|
||||
width: 100%;
|
||||
|
@ -444,5 +530,63 @@ onMounted(async () => {
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
.home-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
.notice {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 60%;
|
||||
height: 40px;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
color: #aaa;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
background-color: rgb(68 68 68 / 100%);
|
||||
border-radius: 36px;
|
||||
}
|
||||
}
|
||||
.home-vin {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: calc(100% - 70px);
|
||||
.vin-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 600px;
|
||||
height: 60px;
|
||||
margin-bottom: 40px;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
background-color: rgb(127 127 127 / 100%);
|
||||
border-radius: 38px;
|
||||
.text {
|
||||
margin-right: 6px;
|
||||
font-size: 32px;
|
||||
font-style: italic;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
.vin-table {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 80%;
|
||||
height: 50px;
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
background-color: rgb(255 255 255 / 0%);
|
||||
border-bottom: 1px solid rgb(215 215 215 / 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,25 +1,33 @@
|
|||
<template>
|
||||
<div class="login-container">
|
||||
<!-- 暗黑模式切换 开始 -->
|
||||
<SwitchDark></SwitchDark>
|
||||
<!-- 暗黑模式切换 结束 -->
|
||||
|
||||
<!-- 登录 -->
|
||||
<div class="login-box">
|
||||
<div class="login-welcome" v-if="currentPage === 0">
|
||||
<img src="../../assets/images/welcome.png" alt="welcome" />
|
||||
<div class="login">
|
||||
<div class="login-header">
|
||||
<img class="logo" src="@/assets/images/logo.png" />
|
||||
<div class="left-title">
|
||||
<div class="title">船货信息智慧共享服务平台</div>
|
||||
<div class="text">Intelligent sharing service platform for ship and cargo information</div>
|
||||
</div>
|
||||
<div class="login-form" v-if="currentPage === 0">
|
||||
<div class="login-logo">
|
||||
<img class="logo-icon" src="../../assets/images/logo.png" alt="logo" />
|
||||
<span class="logo-text">船货信息智慧共享服务平台</span>
|
||||
</div>
|
||||
<!-- 登录功能 开始 -->
|
||||
<div class="login-content">
|
||||
<div class="login-box" v-if="currentPage === 0">
|
||||
<div class="login-welcome">
|
||||
<div class="pc">
|
||||
<div class="logo-title">滚装码头专业版</div>
|
||||
<img src="@/assets/images/login-pc.png" />
|
||||
</div>
|
||||
<div class="mini">
|
||||
<div class="logo-title">Mini APP</div>
|
||||
<img src="@/assets/images/login.png" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="login-form">
|
||||
<el-form ref="loginFormRef" :model="loginForm" :rules="loginRules">
|
||||
<!-- 用户名 开始 -->
|
||||
<div class="form-title">
|
||||
<div class="form-title-left">欢迎使用</div>
|
||||
<div class="form-title-right" @click="onClickChangePage(1)">企业入驻</div>
|
||||
</div>
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
placeholder="请输入用户名"
|
||||
placeholder="请输入登录账号(手机账号)"
|
||||
autocomplete="on"
|
||||
style="position: relative"
|
||||
v-model="loginForm.username"
|
||||
|
@ -30,9 +38,7 @@
|
|||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<!-- 用户名 结束 -->
|
||||
|
||||
<!-- 密码 开始 -->
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
placeholder="请输入密码"
|
||||
|
@ -45,29 +51,139 @@
|
|||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<!-- 密码 结束 -->
|
||||
|
||||
<div class="login-btn">
|
||||
<el-button
|
||||
type="primary"
|
||||
type="success"
|
||||
style="width: 100%; height: 100%"
|
||||
:loading="loading"
|
||||
@click="onClickSubmit(loginFormRef)"
|
||||
>
|
||||
登录
|
||||
</el-button>
|
||||
|
||||
<el-button style="width: 100%; height: 100%" @click="onClickChangePage(1)">
|
||||
企业入驻
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
<!-- 登录功能 结束 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 企业入驻 -->
|
||||
<div class="login-form1" v-if="currentPage === 1">
|
||||
<CompanyRegister @go-to-login="onClickChangePage(0)" />
|
||||
<div class="register" v-if="currentPage === 1">
|
||||
<div class="register-header">入驻企业登记信息</div>
|
||||
<div class="register-box">
|
||||
<div class="register-welcome">
|
||||
<div class="pc">
|
||||
<div class="logo-title">滚装码头专业版</div>
|
||||
<img src="@/assets/images/login-pc.png" />
|
||||
</div>
|
||||
<div class="mini">
|
||||
<div class="logo-title">Mini APP</div>
|
||||
<img src="@/assets/images/login.png" />
|
||||
</div>
|
||||
</div>
|
||||
<el-form ref="registerFormRef" :rules="formRules" :model="ruleForm" class="register-form">
|
||||
<div class="form-left">
|
||||
<div class="form-wrap">
|
||||
<div class="form-title">基本信息</div>
|
||||
<el-row :gutter="30">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="enterpriseType">
|
||||
<el-select
|
||||
v-model="ruleForm.enterpriseType"
|
||||
placeholder="请选择企业类型"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in companyTypeList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="portId">
|
||||
<RemoteSelect
|
||||
v-model:value="ruleForm.portId"
|
||||
placeholder="请选择港口"
|
||||
:api="postPortListAPI"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item prop="name">
|
||||
<el-input v-model="ruleForm.name" placeholder="请输入企业全称" />
|
||||
</el-form-item>
|
||||
<el-row :gutter="30">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="code">
|
||||
<el-input v-model="ruleForm.code" placeholder="请输入企业统一社会信用代码" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="legalPerson">
|
||||
<el-input v-model="ruleForm.legalPerson" placeholder="请输入法定代表人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-form-item prop="contractNo">
|
||||
<el-input v-model="ruleForm.contractNo" placeholder="请输入合同编号" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="address">
|
||||
<el-input v-model="ruleForm.address" placeholder="请输入企业地址" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="licensePhoto">
|
||||
<el-input v-model="ruleForm.licensePhoto" disabled placeholder="请上传营业执照">
|
||||
<template #append>
|
||||
<UploadImg v-model:imageID="ruleForm.licensePhoto" :file-no="ruleForm.code" />
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="form-submit">
|
||||
<el-button
|
||||
type="primary"
|
||||
:loading="submitLoading"
|
||||
@click="onClickSubmitRegister(registerFormRef)"
|
||||
>
|
||||
提交
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-right">
|
||||
<div class="form-title">联系人 / 管理员</div>
|
||||
<el-form-item prop="linkman">
|
||||
<el-input v-model="ruleForm.linkman" placeholder="请输入联系人姓名" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="phone">
|
||||
<el-input v-model="ruleForm.phone" placeholder="请填写登录账号(手机号码)" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="idPhoto">
|
||||
<el-input v-model="ruleForm.idPhoto" disabled placeholder="请上传身份证照片">
|
||||
<template #append>
|
||||
<UploadImg
|
||||
v-model:imageID="ruleForm.idPhoto"
|
||||
:img-type="1"
|
||||
:file-no="ruleForm.phone"
|
||||
/>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input v-model="ruleForm.password" placeholder="请输入登录密码" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item prop="confirmPassword">
|
||||
<el-input
|
||||
v-model="ruleForm.confirmPassword"
|
||||
placeholder="请再次输入密码"
|
||||
show-password
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -75,13 +191,16 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { ElNotification } from 'element-plus';
|
||||
import { ElMessage, ElNotification } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import SwitchDark from '@/components/SwitchDark/index.vue';
|
||||
import { postEnterpriseRegAPI } from '@/api/Enterprise/company';
|
||||
import { postPortListAPI } from '@/api/Port';
|
||||
import RemoteSelect from '@/components/RemoteSelect/index.vue';
|
||||
import { useUserStore } from '@/store/modules/user';
|
||||
import { getTimeStateStr } from '@/utils';
|
||||
import CompanyRegister from './register.vue';
|
||||
import { validPhone } from '@/utils/validate';
|
||||
import UploadImg from './components/Upload.vue';
|
||||
|
||||
// 当前页
|
||||
const currentPage = ref(0);
|
||||
|
@ -96,14 +215,8 @@ const loginFormRef = ref<FormInstance>();
|
|||
|
||||
// 校验规则
|
||||
const loginRules = reactive<FormRules>({
|
||||
username: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||
{ min: 4, message: '用户名长度不能小于4位', trigger: 'blur' },
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
{ min: 4, max: 16, message: '密码长度不符合规范,密码长度 4 - 16 位', trigger: 'blur' },
|
||||
],
|
||||
username: [{ required: true, message: '请填写登录账号', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 用户账户密码
|
||||
|
@ -143,26 +256,153 @@ const onClickSubmit = (formEl: FormInstance | undefined) => {
|
|||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 企业列表
|
||||
const companyTypeList = [
|
||||
{
|
||||
value: '港口码头',
|
||||
label: '港口码头',
|
||||
},
|
||||
{
|
||||
value: '船公司',
|
||||
label: '船公司',
|
||||
},
|
||||
{
|
||||
value: '货主',
|
||||
label: '货主',
|
||||
},
|
||||
{
|
||||
value: '船代',
|
||||
label: '船代',
|
||||
},
|
||||
{
|
||||
value: '货贷',
|
||||
label: '货贷',
|
||||
},
|
||||
];
|
||||
|
||||
// 表单
|
||||
const ruleForm = reactive({
|
||||
name: '',
|
||||
code: '',
|
||||
address: '',
|
||||
legalPerson: '',
|
||||
contractNo: '',
|
||||
linkman: '',
|
||||
phone: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
portId: '',
|
||||
licensePhoto: '',
|
||||
idPhoto: '',
|
||||
enterpriseType: '',
|
||||
});
|
||||
|
||||
// 表单校验
|
||||
const registerFormRef = ref<FormInstance>();
|
||||
|
||||
const validatePass2 = (_: any, value: any, callback: any) => {
|
||||
if (value === '') {
|
||||
callback(new Error('请再次输入密码'));
|
||||
} else if (value !== ruleForm.password) {
|
||||
callback(new Error('两次密码不一致!'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
const checkPhone = (_: any, value: string, callback: any) => {
|
||||
if (!validPhone(value)) {
|
||||
// 返回一个错误提示
|
||||
callback(new Error('请输入正确的手机号码'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
// 校验规则
|
||||
const formRules = reactive<FormRules>({
|
||||
name: [{ required: true, message: '请输入企业全称', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入企业统一社会信用代码', trigger: 'blur' }],
|
||||
address: [{ required: true, message: '请输入企业地址', trigger: 'blur' }],
|
||||
legalPerson: [{ required: true, message: '请输入法定代表人', trigger: 'blur' }],
|
||||
contractNo: [{ required: true, message: '请输入合同编号', trigger: 'blur' }],
|
||||
linkman: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
|
||||
phone: [
|
||||
{ required: true, message: '请输入手机号', trigger: 'blur' },
|
||||
{ validator: checkPhone, trigger: 'blur' },
|
||||
],
|
||||
portId: [{ required: true, message: '请选择港口', trigger: 'blur' }],
|
||||
licensePhoto: [{ required: true, message: '请上传营业执照', trigger: 'blur' }],
|
||||
idPhoto: [{ required: true, message: '请上传身份证照片', trigger: 'blur' }],
|
||||
enterpriseType: [{ required: true, message: '请选择企业类型', trigger: 'blur' }],
|
||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||
confirmPassword: [{ required: true, validator: validatePass2, trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 按钮加载状态
|
||||
const submitLoading = ref(false);
|
||||
|
||||
// 企业入驻
|
||||
const onClickSubmitRegister = (formEl: FormInstance | undefined) => {
|
||||
// 进行表单校验
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
try {
|
||||
submitLoading.value = true; // 按钮进入加载状态
|
||||
// 通过验证
|
||||
await postEnterpriseRegAPI(ruleForm);
|
||||
|
||||
ElMessage({
|
||||
message: '企业注册成功',
|
||||
type: 'success',
|
||||
});
|
||||
} finally {
|
||||
submitLoading.value = false; // 关闭按钮加载状态
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.login-container {
|
||||
position: relative;
|
||||
.login {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(180deg, rgb(51 51 51 / 100%) 0%, rgb(242 242 242 / 100%) 100%);
|
||||
.login-header {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
padding: 0 20px;
|
||||
background-color: rgb(156 0 12 / 100%);
|
||||
.logo {
|
||||
width: 80px;
|
||||
height: 50px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
.left-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #fff;
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
}
|
||||
.text {
|
||||
font-size: 15px;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
.login-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 550px;
|
||||
height: 100%;
|
||||
min-height: 500px;
|
||||
background-image: url('@/assets/images/login_bg.svg');
|
||||
background-position: 50%;
|
||||
background-size: 100% 100%;
|
||||
background-size: cover;
|
||||
.dark {
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
right: 3.2%;
|
||||
}
|
||||
width: 100%;
|
||||
height: calc(100% - 70px);
|
||||
.login-box {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
|
@ -170,33 +410,68 @@ const onClickSubmit = (formEl: FormInstance | undefined) => {
|
|||
justify-content: space-around;
|
||||
width: 96%;
|
||||
height: 94%;
|
||||
padding: 0 4% 0 20px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
.login-welcome {
|
||||
width: 750px;
|
||||
display: flex;
|
||||
.pc {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.logo-title {
|
||||
font-size: 32px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
}
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
width: 500px;
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
.mini {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
height: 445px;
|
||||
margin-left: 10px;
|
||||
.logo-title {
|
||||
margin-bottom: 20px;
|
||||
font-size: 32px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
}
|
||||
img {
|
||||
width: 160px;
|
||||
height: 330px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.login-form {
|
||||
box-sizing: border-box;
|
||||
padding: 40px 45px 25px;
|
||||
border-radius: 10px;
|
||||
.login-logo {
|
||||
width: 400px;
|
||||
padding: 60px 45px;
|
||||
background-color: #fff;
|
||||
border-radius: 7px;
|
||||
box-shadow: 0 0 13px rgb(0 0 0 / 34.9%);
|
||||
.form-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 40px;
|
||||
.logo-icon {
|
||||
width: 70px;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 700;
|
||||
.form-title-left {
|
||||
font-size: 38px;
|
||||
}
|
||||
.logo-text {
|
||||
padding-left: 25px;
|
||||
font-size: 48px;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
.form-title-right {
|
||||
font-size: 20px;
|
||||
color: #027db4;
|
||||
cursor: pointer;
|
||||
}
|
||||
.form-title-right:hover {
|
||||
color: rgb(217 0 27);
|
||||
}
|
||||
}
|
||||
:deep(.el-form-item) {
|
||||
|
@ -221,11 +496,111 @@ const onClickSubmit = (formEl: FormInstance | undefined) => {
|
|||
margin: 20px 0;
|
||||
}
|
||||
}
|
||||
.login-form1 {
|
||||
}
|
||||
.register {
|
||||
box-sizing: border-box;
|
||||
width: 70%;
|
||||
padding: 40px 45px 25px;
|
||||
border-radius: 10px;
|
||||
width: 96%;
|
||||
height: 94%;
|
||||
background-color: #fff;
|
||||
.register-header {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 40px 0;
|
||||
font-size: 39px;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
.register-box {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 0 20px;
|
||||
.register-welcome {
|
||||
display: flex;
|
||||
.pc {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.logo-title {
|
||||
font-size: 32px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
}
|
||||
img {
|
||||
width: 320px;
|
||||
height: 256px;
|
||||
}
|
||||
}
|
||||
.mini {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
height: 445px;
|
||||
margin-left: 10px;
|
||||
.logo-title {
|
||||
margin-bottom: 20px;
|
||||
font-size: 32px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
}
|
||||
img {
|
||||
width: 100px;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.register-form {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: space-between;
|
||||
padding: 40px;
|
||||
.form-left {
|
||||
width: 49%;
|
||||
.form-wrap {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 20px 30px;
|
||||
border: 1px dashed #ddd;
|
||||
border-radius: 8px;
|
||||
.form-title {
|
||||
position: absolute;
|
||||
top: -14px; /* 使标题悬浮在边框上方 */
|
||||
left: 20px; /* 根据需要调整水平位置 */
|
||||
padding: 0 8px; /* 增加一点内边距 */
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
background: #fff; /* 设置背景覆盖边框 */
|
||||
}
|
||||
}
|
||||
.form-submit {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
.form-right {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 49%;
|
||||
padding: 20px 30px;
|
||||
border: 1px dashed #ddd;
|
||||
border-radius: 8px;
|
||||
.form-title {
|
||||
position: absolute;
|
||||
top: -14px; /* 使标题悬浮在边框上方 */
|
||||
left: 20px; /* 根据需要调整水平位置 */
|
||||
padding: 0 8px; /* 增加一点内边距 */
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
background: #fff; /* 设置背景覆盖边框 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="manage">
|
||||
<ManifestDetailTable />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ManifestDetailTable from './components/ManifestDetailTable.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="manage">
|
||||
<ManifestTable />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ManifestTable from './components/ManifestTable.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -3,7 +3,11 @@
|
|||
<div class="header">
|
||||
<el-form :inline="true" :model="searchTableForm" ref="tableFormRef">
|
||||
<el-form-item prop="name">
|
||||
<el-input v-model="searchTableForm.billNo" placeholder="请输入提单号" />
|
||||
<el-input
|
||||
v-model="searchTableForm.billNo"
|
||||
placeholder="请输入提单号"
|
||||
style="width: 120px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="onClickSearch">查询</el-button>
|
||||
|
@ -12,14 +16,12 @@
|
|||
</el-form>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="footer-util">舱单明细</div>
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
<el-table
|
||||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="manifest.name" label="舱单" align="center" width="150" />
|
||||
|
@ -56,24 +58,32 @@
|
|||
<script lang="ts" setup>
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { getManifestDetailPageAPI } from '@/api/Manifest/detail';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
|
||||
// 路由参数
|
||||
const route = useRoute();
|
||||
// 接受父组件参数
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
manifestId: string;
|
||||
}>(),
|
||||
{
|
||||
manifestId: '',
|
||||
}
|
||||
);
|
||||
|
||||
// 获取列表表格数据
|
||||
const { getTableList, tableState, searchTable, resetTable, tableChangeCurrent, tableChangeSize } =
|
||||
useTable({
|
||||
api: getManifestDetailPageAPI,
|
||||
initParam: {
|
||||
manifestId: [route.query.manifestId as string],
|
||||
},
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
if (props.manifestId) {
|
||||
tableState.value.searchInitParam = {
|
||||
manifestId: [props.manifestId],
|
||||
};
|
||||
}
|
||||
await getTableList();
|
||||
});
|
||||
|
||||
|
@ -107,28 +117,6 @@ const onClickResetForm = async (formEl: FormInstance | undefined) => {
|
|||
formEl.resetFields();
|
||||
};
|
||||
|
||||
// 删除
|
||||
// const onClickDel = (row: EmployeeType) => {
|
||||
// ElMessageBox.confirm(`你确定要删除员工 ${row.name} 吗?`, '温馨提示', {
|
||||
// confirmButtonText: '确定',
|
||||
// cancelButtonText: '取消',
|
||||
// type: 'warning',
|
||||
// draggable: true,
|
||||
// })
|
||||
// .then(async () => {
|
||||
// await postEmployeeDeleteAPI([row.id]);
|
||||
// // 更新表格
|
||||
// await getTableList();
|
||||
// ElMessage({
|
||||
// message: '删除成功',
|
||||
// type: 'success',
|
||||
// });
|
||||
// })
|
||||
// .catch(() => {
|
||||
// console.log('用户点击了取消');
|
||||
// });
|
||||
// };
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
await tableChangeSize(val);
|
||||
|
@ -149,11 +137,8 @@ const handleCurrentChange = async (val: number) => {
|
|||
width: 100%;
|
||||
.header {
|
||||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
justify-content: space-between;
|
||||
padding: 0 16px;
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
|
@ -163,9 +148,6 @@ const handleCurrentChange = async (val: number) => {
|
|||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
|
@ -5,33 +5,19 @@
|
|||
<el-form-item>
|
||||
<RemoteSelect
|
||||
v-model:value="searchTableForm.shipId"
|
||||
placeholder="请选择船舶"
|
||||
placeholder="请选择船名"
|
||||
:api="postShipListAPI"
|
||||
style="width: 120px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input v-model="searchTableForm.voyage" placeholder="请输入航次" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-select
|
||||
v-model="searchTableForm.goodsStatus"
|
||||
placeholder="货物状态"
|
||||
style="width: 120px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in goodsStatusList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="onClickSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="onClickResetForm(tableFormRef)">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div>
|
||||
<el-button type="success" @click="onClickExport">舱单导出</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<!-- 表格 -->
|
||||
|
@ -40,7 +26,6 @@
|
|||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="schedule.name" label="船期" align="center" width="120" />
|
||||
|
@ -87,10 +72,9 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { getManifestPageAPI } from '@/api/Manifest';
|
||||
import { getManifestFileExportAPI, getManifestPageAPI } from '@/api/Manifest';
|
||||
import { postShipListAPI } from '@/api/Ship';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import RemoteSelect from '@/components/RemoteSelect/index.vue';
|
||||
|
@ -107,25 +91,6 @@ onMounted(async () => {
|
|||
await getTableList();
|
||||
});
|
||||
|
||||
const goodsStatusList = [
|
||||
{
|
||||
value: '有计划',
|
||||
label: '有计划',
|
||||
},
|
||||
{
|
||||
value: '已靠港',
|
||||
label: '已靠港',
|
||||
},
|
||||
{
|
||||
value: '作业中',
|
||||
label: '作业中',
|
||||
},
|
||||
{
|
||||
value: '已离港',
|
||||
label: '已离港',
|
||||
},
|
||||
];
|
||||
|
||||
// 查询条件
|
||||
const searchTableForm = reactive({
|
||||
scheduleId: '',
|
||||
|
@ -161,40 +126,54 @@ const onClickResetForm = async (formEl: FormInstance | undefined) => {
|
|||
formEl.resetFields();
|
||||
};
|
||||
|
||||
// 路由
|
||||
const router = useRouter();
|
||||
|
||||
// 查看明细
|
||||
const onClickOpenDetail = (row: ManifestType) => {
|
||||
router.push({
|
||||
path: '/Manifest/detail',
|
||||
query: {
|
||||
manifestId: row.id,
|
||||
},
|
||||
// 导出舱单
|
||||
const onClickExport = () => {
|
||||
ElMessageBox.confirm(`你确定要导出舱单信息吗?`, '温馨提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
draggable: true,
|
||||
})
|
||||
.then(async () => {
|
||||
try {
|
||||
let params: any = {
|
||||
rows: tableState.value.pageAble.rows,
|
||||
page: tableState.value.pageAble.page,
|
||||
};
|
||||
if (searchTableForm.shipId) {
|
||||
params.shipId = searchTableForm.shipId;
|
||||
}
|
||||
const { data } = await getManifestFileExportAPI(params);
|
||||
const blob = new Blob([data], {
|
||||
type: 'application/vnd.ms-excel;charset=utf-8',
|
||||
});
|
||||
const downloadUrl = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = downloadUrl;
|
||||
link.download = '舱单信息.xlsx';
|
||||
link.click();
|
||||
ElMessage({
|
||||
message: '导出成功',
|
||||
type: 'success',
|
||||
});
|
||||
} catch (error) {
|
||||
ElMessage({
|
||||
message: '导出失败',
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('用户点击了取消');
|
||||
});
|
||||
};
|
||||
|
||||
// 删除
|
||||
// const onClickDel = (row: ManifestType) => {
|
||||
// ElMessageBox.confirm(`你确定要删除舱单吗?`, '温馨提示', {
|
||||
// confirmButtonText: '确定',
|
||||
// cancelButtonText: '取消',
|
||||
// type: 'warning',
|
||||
// draggable: true,
|
||||
// })
|
||||
// .then(async () => {
|
||||
// await postManifestDeleteAPI([row.id]);
|
||||
// // 更新表格
|
||||
// await getTableList();
|
||||
// ElMessage({
|
||||
// message: '删除成功',
|
||||
// type: 'success',
|
||||
// });
|
||||
// })
|
||||
// .catch(() => {
|
||||
// console.log('用户点击了取消');
|
||||
// });
|
||||
// };
|
||||
const emits = defineEmits(['ManifestID']);
|
||||
|
||||
// 查看明细
|
||||
const onClickOpenDetail = (row: ManifestType) => {
|
||||
emits('ManifestID', row);
|
||||
};
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
|
@ -216,11 +195,8 @@ const handleCurrentChange = async (val: number) => {
|
|||
width: 100%;
|
||||
.header {
|
||||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
justify-content: space-between;
|
||||
padding: 0 16px;
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
|
@ -230,9 +206,6 @@ const handleCurrentChange = async (val: number) => {
|
|||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
|
@ -0,0 +1,103 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<div class="title">{{ currentSubscribeNav }}</div>
|
||||
<div class="api-btn">
|
||||
<div
|
||||
class="btn"
|
||||
:class="{ 'btn-active': currentSubscribeNav === item }"
|
||||
v-for="item in subscribeNavList"
|
||||
:key="item"
|
||||
@click="onClickChangeSubscribeType(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<ManifestTable v-if="currentSubscribeNav === '舱单信息'" @ManifestID="onClickOpenDetail" />
|
||||
<ManifestDetailTable :manifestId="manifestID" v-if="currentSubscribeNav === '提单明细'" />
|
||||
<!-- <ReceiveTable v-if="currentSubscribeNav === '积载图'" /> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ManifestType } from '@/types/manifest';
|
||||
import ManifestDetailTable from './components/ManifestDetailTable.vue';
|
||||
import ManifestTable from './components/ManifestTable.vue';
|
||||
|
||||
const manifestID = ref();
|
||||
|
||||
// 订阅导航列表
|
||||
const subscribeNavList = ref(['舱单信息', '提单明细', '积载图']);
|
||||
const currentSubscribeNav = ref('舱单信息');
|
||||
const onClickChangeSubscribeType = async (item: string) => {
|
||||
if (item === currentSubscribeNav.value) return;
|
||||
currentSubscribeNav.value = item;
|
||||
if (item === '提单明细') {
|
||||
manifestID.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
const onClickOpenDetail = (row: ManifestType) => {
|
||||
manifestID.value = row.id;
|
||||
currentSubscribeNav.value = '提单明细';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.header {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 15px;
|
||||
color: #fff;
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.api-btn {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
color: #d7d7d7;
|
||||
background-color: rgb(51 51 51 / 100%);
|
||||
border-radius: 75px;
|
||||
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
|
||||
}
|
||||
.btn-active {
|
||||
color: #000;
|
||||
background-color: #f2f2f2;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="notify">
|
||||
<div class="title">平台公告</div>
|
||||
<div class="list">
|
||||
<div class="list-title">平台公告</div>
|
||||
<ul
|
||||
class="list-wrap"
|
||||
v-infinite-scroll="noticeListLoad"
|
||||
|
@ -14,17 +14,21 @@
|
|||
class="list-item"
|
||||
@click="onClickOpenDialog(item)"
|
||||
>
|
||||
<div class="item-icon"></div>
|
||||
<div class="item-title">{{ item.title }}</div>
|
||||
<div class="item-date">{{ item.createDate }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<el-dialog v-model="isShowNotice" width="70%" top="50px">
|
||||
|
||||
<div class="content">
|
||||
<div class="border1"></div>
|
||||
<div class="border2"></div>
|
||||
<div class="border3"></div>
|
||||
<div class="border4"></div>
|
||||
<div class="title">{{ noticeViewData?.title }}</div>
|
||||
<div class="wrap" v-html="noticeViewData?.content"></div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -79,16 +83,8 @@ const onClickOpenDialog = async (row: NoticeType) => {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
.list {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
color: #303133;
|
||||
background-color: #fff;
|
||||
border: 1px solid #e4ede7;
|
||||
border-radius: 4px;
|
||||
.list-title {
|
||||
color: #fff;
|
||||
.title {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
|
@ -97,10 +93,16 @@ const onClickOpenDialog = async (row: NoticeType) => {
|
|||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.list {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: calc(100% - 100px);
|
||||
.list-wrap {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: calc(100% - 50px);
|
||||
width: 30%;
|
||||
height: 500px;
|
||||
overflow: auto;
|
||||
.list-item {
|
||||
box-sizing: border-box;
|
||||
|
@ -109,7 +111,13 @@ const onClickOpenDialog = async (row: NoticeType) => {
|
|||
width: 100%;
|
||||
padding: 10px 0;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px dashed #e4e4e7;
|
||||
.item-icon {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 10px;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.item-title {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
@ -123,21 +131,63 @@ const onClickOpenDialog = async (row: NoticeType) => {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
margin-left: 20px;
|
||||
font-size: 21px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
background-color: #333;
|
||||
border: 5px solid #fff;
|
||||
border-radius: 9px;
|
||||
.title {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 16px;
|
||||
font-size: 23px;
|
||||
font-weight: 700;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
.wrap {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: calc(100% - 70px);
|
||||
padding: 0 16px 20px;
|
||||
}
|
||||
.border1 {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 10%;
|
||||
width: 80%;
|
||||
height: 5px;
|
||||
background-color: #333;
|
||||
}
|
||||
.border2 {
|
||||
position: absolute;
|
||||
top: 10%;
|
||||
left: -5px;
|
||||
width: 5px;
|
||||
height: 80%;
|
||||
background-color: #333;
|
||||
}
|
||||
.border3 {
|
||||
position: absolute;
|
||||
top: 10%;
|
||||
left: 100%;
|
||||
width: 5px;
|
||||
height: 80%;
|
||||
background-color: #333;
|
||||
}
|
||||
.border4 {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 10%;
|
||||
width: 80%;
|
||||
height: 5px;
|
||||
background-color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
<template>
|
||||
<div class="send">
|
||||
<el-steps class="header" :active="currentActive" finish-status="success">
|
||||
<el-step title="发布船期信息" />
|
||||
<el-step title="发布舱单信息" />
|
||||
<el-step title="提交舱单明细" />
|
||||
</el-steps>
|
||||
<div class="content">
|
||||
<div class="content-left">
|
||||
<div class="left-icon">{{ currentActive }}</div>
|
||||
<div class="left-title">{{ currentTitle[currentActive - 1] }}</div>
|
||||
</div>
|
||||
<div class="content-right">
|
||||
<BoatInfoSend @updateBoatID="onUpdateBoatID" v-if="currentActive === 1" />
|
||||
<ManifestSend
|
||||
:scheduleId="manifestProps?.scheduleId"
|
||||
:voyage="manifestProps?.voyage"
|
||||
:loadPortId="manifestProps?.loadPortId"
|
||||
:dischargePortId="manifestProps?.dischargePortId"
|
||||
@updateBoatID="onUpdateManifest"
|
||||
v-if="currentActive === 2"
|
||||
/>
|
||||
<ManifestDetailSend
|
||||
:manifestId="manifestDetailProps?.manifestId"
|
||||
:billNo="manifestDetailProps?.billNo"
|
||||
:brandId="manifestDetailProps?.brandId"
|
||||
:model="manifestDetailProps?.model"
|
||||
v-if="currentActive === 3"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import BoatInfoSend from './BoatInfoSend.vue';
|
||||
import ManifestDetailSend from './ManifestDetailSend.vue';
|
||||
import ManifestSend from './ManifestSend.vue';
|
||||
|
||||
// 当前选中的步骤
|
||||
const currentActive = ref(1);
|
||||
const currentTitle = ref(['发布船期信息', '发布舱单信息', '提交舱单明细']);
|
||||
|
||||
interface manifestPropsType {
|
||||
scheduleId: string;
|
||||
voyage: string;
|
||||
loadPortId: number | string;
|
||||
dischargePortId: string | number;
|
||||
}
|
||||
|
||||
const manifestProps = ref<manifestPropsType>();
|
||||
// 发布船期信息
|
||||
const onUpdateBoatID = (params: manifestPropsType) => {
|
||||
manifestProps.value = params;
|
||||
currentActive.value = 2;
|
||||
};
|
||||
|
||||
interface manifestDetailPropsType {
|
||||
manifestId: string | number;
|
||||
billNo?: string;
|
||||
brandId?: string;
|
||||
model?: string;
|
||||
}
|
||||
const manifestDetailProps = ref<manifestDetailPropsType>();
|
||||
const onUpdateManifest = (params: manifestDetailPropsType) => {
|
||||
manifestDetailProps.value = params;
|
||||
currentActive.value = 3;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.send {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: calc(100% - 70px);
|
||||
.content-left {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 30%;
|
||||
height: 100%;
|
||||
padding: 40px 0 0 20px;
|
||||
background-color: #027db4;
|
||||
.left-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin-right: 10px;
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
line-height: 64px;
|
||||
color: #d9001b;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.left-title {
|
||||
height: 64px;
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
line-height: 64px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.content-right {
|
||||
box-sizing: border-box;
|
||||
width: 70%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,176 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="footer">
|
||||
<div class="footer-util">
|
||||
<div class="title">我最近发布的信息</div>
|
||||
<el-button type="primary" icon="Plus" @click="onClickSendInfo"> 新增发布 </el-button>
|
||||
</div>
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
<el-table
|
||||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="enterprise.name" label="企业" align="center" width="150" />
|
||||
<el-table-column prop="ship.name" label="船舶" align="center" width="150" />
|
||||
<el-table-column prop="voyage" label="航次" align="center" width="180" />
|
||||
<el-table-column prop="shipRoute.name" label="航线" align="center" width="150" />
|
||||
<el-table-column prop="loadWharf.name" label="装货码头" align="center" width="150" />
|
||||
<el-table-column prop="dischargeWharf.name" label="卸货码头" align="center" width="150" />
|
||||
<el-table-column prop="carNumPlan" label="计划商品车数量" align="center" width="180" />
|
||||
<el-table-column prop="spareNumPlan" label="计划件杂货数量" align="center" width="180" />
|
||||
<el-table-column prop="carNumActual" label="实际商品车数量" align="center" width="180" />
|
||||
<el-table-column
|
||||
prop="spareNumActual"
|
||||
label="实际件杂货数量"
|
||||
align="center"
|
||||
width="180"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="departureDatePlan"
|
||||
label="计划离泊时间"
|
||||
align="center"
|
||||
width="200"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="departureDateActual"
|
||||
label="实际离泊时间"
|
||||
align="center"
|
||||
width="200"
|
||||
/>
|
||||
<el-table-column prop="tradeType" label="贸易类型" align="center" width="150" />
|
||||
<el-table-column prop="loadPort.name" label="装货港口" align="center" width="150" />
|
||||
<el-table-column prop="dischargePort.name" label="卸货港口" align="center" width="150" />
|
||||
<el-table-column prop="shipStatus" label="当前状态" align="center" width="150" />
|
||||
<el-table-column prop="createDate" label="创建时间" align="center" width="180" />
|
||||
<el-table-column prop="operator" label="操作" width="200px" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="View"
|
||||
link
|
||||
@click="onClickOpenDetail(scope.row)"
|
||||
>
|
||||
查看
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<div class="footer-pagination">
|
||||
<Pagination
|
||||
:pageAble="tableState.pageAble"
|
||||
:handle-size-change="handleSizeChange"
|
||||
:handle-current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import dayjs from 'dayjs';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { getSailScheduleGetAPI, getSailSchedulePageAPI } from '@/api/Boat/info';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
import { PageRowsResult } from '@/types';
|
||||
import { BoatInfoType } from '@/types/boatInfo';
|
||||
|
||||
const handleTableData = (data: PageRowsResult<BoatInfoType>) => {
|
||||
const { records } = data;
|
||||
for (const item of records) {
|
||||
item.departureDatePlan = dayjs(item.departureDatePlan).format('YYYY-MM-DD HH:mm:ss');
|
||||
item.departureDateActual = dayjs(item.departureDateActual).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
// 获取用户列表表格数据
|
||||
const { getTableList, tableState, tableChangeCurrent, tableChangeSize } = useTable({
|
||||
api: getSailSchedulePageAPI,
|
||||
dataCallBack: handleTableData,
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await getTableList();
|
||||
});
|
||||
|
||||
// 表格是否加载
|
||||
const tableLoading = ref(false);
|
||||
|
||||
const emits = defineEmits(['sendInfo']);
|
||||
|
||||
// 新增发布
|
||||
const onClickSendInfo = () => {
|
||||
emits('sendInfo');
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const onClickOpenDetail = async (row: BoatInfoType) => {
|
||||
const { data } = await getSailScheduleGetAPI({ id: row.id });
|
||||
console.log('🚀 ~ file: BoatTable.vue:146 ~ onClickOpenDetail ~ data:', data);
|
||||
};
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
await tableChangeSize(val);
|
||||
};
|
||||
|
||||
// 当前页数改变
|
||||
const handleCurrentChange = async (val: number) => {
|
||||
await tableChangeCurrent(val);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0 16px;
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15px;
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 400;
|
||||
color: #80ffff;
|
||||
}
|
||||
}
|
||||
.footer-table {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
}
|
||||
.footer-pagination {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,84 +1,80 @@
|
|||
<template>
|
||||
<div class="send">
|
||||
<el-steps class="header" :active="currentActive" finish-status="success">
|
||||
<el-step title="发布船期信息" />
|
||||
<el-step title="发布舱单信息" />
|
||||
<el-step title="提交舱单明细" />
|
||||
</el-steps>
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<div class="title">发布船货信息</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<BoatInfoSend @updateBoatID="onUpdateBoatID" v-if="currentActive === 1" />
|
||||
<ManifestSend
|
||||
:scheduleId="manifestProps?.scheduleId"
|
||||
:voyage="manifestProps?.voyage"
|
||||
:loadPortId="manifestProps?.loadPortId"
|
||||
:dischargePortId="manifestProps?.dischargePortId"
|
||||
@updateBoatID="onUpdateManifest"
|
||||
v-if="currentActive === 2"
|
||||
/>
|
||||
<ManifestDetailSend
|
||||
:manifestId="manifestDetailProps?.manifestId"
|
||||
:billNo="manifestDetailProps?.billNo"
|
||||
:brandId="manifestDetailProps?.brandId"
|
||||
:model="manifestDetailProps?.model"
|
||||
v-if="currentActive === 3"
|
||||
/>
|
||||
<SendTable v-if="currentSubscribeNav === '船货信息'" @sendInfo="onClickSendInfo" />
|
||||
<Send v-if="currentSubscribeNav === '发布信息'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import BoatInfoSend from './components/BoatInfoSend.vue';
|
||||
import ManifestDetailSend from './components/ManifestDetailSend.vue';
|
||||
import ManifestSend from './components/ManifestSend.vue';
|
||||
import Send from './components/Send.vue';
|
||||
import SendTable from './components/SendTable.vue';
|
||||
|
||||
// 当前选中的步骤
|
||||
const currentActive = ref(1);
|
||||
// 订阅导航列表
|
||||
const currentSubscribeNav = ref('船货信息');
|
||||
|
||||
interface manifestPropsType {
|
||||
scheduleId: string;
|
||||
voyage: string;
|
||||
loadPortId: number | string;
|
||||
dischargePortId: string | number;
|
||||
}
|
||||
|
||||
const manifestProps = ref<manifestPropsType>();
|
||||
// 发布船期信息
|
||||
const onUpdateBoatID = (params: manifestPropsType) => {
|
||||
manifestProps.value = params;
|
||||
currentActive.value = 2;
|
||||
};
|
||||
|
||||
interface manifestDetailPropsType {
|
||||
manifestId: string | number;
|
||||
billNo?: string;
|
||||
brandId?: string;
|
||||
model?: string;
|
||||
}
|
||||
const manifestDetailProps = ref<manifestDetailPropsType>();
|
||||
const onUpdateManifest = (params: manifestDetailPropsType) => {
|
||||
manifestDetailProps.value = params;
|
||||
currentActive.value = 3;
|
||||
// 新增发布
|
||||
const onClickSendInfo = () => {
|
||||
currentSubscribeNav.value = '发布信息';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.send {
|
||||
box-sizing: border-box;
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 15px;
|
||||
color: #fff;
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.api-btn {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
color: #d7d7d7;
|
||||
background-color: rgb(51 51 51 / 100%);
|
||||
border-radius: 75px;
|
||||
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
|
||||
}
|
||||
.btn-active {
|
||||
color: #000;
|
||||
background-color: #f2f2f2;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: calc(100% - 70px);
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -21,34 +21,26 @@
|
|||
:disabled="dialogProps.isView"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="码头">
|
||||
<el-select
|
||||
v-model="dialogProps.row!.wharfId"
|
||||
placeholder="请选择港口"
|
||||
style="width: 100%"
|
||||
clearable
|
||||
filterable
|
||||
remote
|
||||
reserve-keyword
|
||||
remote-show-suffix
|
||||
:remote-method="onRemoteWharf"
|
||||
:loading="wharfLoading"
|
||||
<el-form-item label="码头" prop="wharfId" required>
|
||||
<RemoteSelect
|
||||
v-model:value="dialogProps.row!.wharfId"
|
||||
placeholder="请选择码头"
|
||||
:api="postWharfListAPI"
|
||||
:disabled="dialogProps.isView"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in wharfList"
|
||||
:key="item.id"
|
||||
:label="item.text"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="dialogProps.row!.name" placeholder="请输入姓名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="昵称">
|
||||
<el-input v-model="dialogProps.row!.nickname" placeholder="请输入昵称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门" prop="dept">
|
||||
<el-input v-model="dialogProps.row!.dept" placeholder="请输入部门" />
|
||||
</el-form-item>
|
||||
<el-form-item label="职位" prop="job">
|
||||
<el-input v-model="dialogProps.row!.job" placeholder="请输入职位" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名" prop="username">
|
||||
<el-input v-model="dialogProps.row!.username" placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
|
@ -74,6 +66,7 @@
|
|||
import { ElMessage, FormInstance, FormRules } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { postEnterpriseListAPI } from '@/api/Enterprise/company';
|
||||
import { postWharfListAPI } from '@/api/Wharf';
|
||||
import RemoteSelect from '@/components/RemoteSelect/index.vue';
|
||||
import { EmployeeType } from '@/types/Enterprise';
|
||||
|
||||
|
@ -109,7 +102,9 @@ const formRules = reactive<FormRules>({
|
|||
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
||||
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
||||
enterpriseId: [{ required: true, message: '请选择企业', trigger: 'blur' }],
|
||||
// password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||
wharfId: [{ required: true, message: '请选择码头', trigger: 'blur' }],
|
||||
job: [{ required: true, message: '请输入职位', trigger: 'blur' }],
|
||||
dept: [{ required: true, message: '请输入部门', trigger: 'blur' }],
|
||||
phone: [{ required: true, message: '请输入联系电话', trigger: 'blur' }],
|
||||
});
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
<template>
|
||||
<div class="notify">
|
||||
<div class="list">
|
||||
<div class="list-left">
|
||||
<div class="left-title">在册用户:</div>
|
||||
<div
|
||||
class="list-wrap"
|
||||
v-infinite-scroll="employeeListLoad"
|
||||
:infinite-scroll-disabled="disabled"
|
||||
:infinite-scroll-distance="100"
|
||||
>
|
||||
<div
|
||||
v-for="item in employeeList"
|
||||
:key="item.id"
|
||||
class="list-item"
|
||||
:class="{ 'list-item-active': currentUser.userId === item.id }"
|
||||
@click="onClickOpenDialog(item)"
|
||||
>
|
||||
<div class="item-title">{{ item.name }}</div>
|
||||
<div class="item-date">{{ item.dept }}/{{ item.job }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-right">
|
||||
<div class="right-title">操作权限</div>
|
||||
<div class="content">
|
||||
<div class="content-title" v-if="currentUser.name">{{ currentUser.name }}的操作权限</div>
|
||||
<el-checkbox-group v-model="currentUser.perms">
|
||||
<div class="content-checkbox">
|
||||
<div class="checkbox-title">查看船货信息:</div>
|
||||
<div class="checkbox">
|
||||
<el-checkbox label="船期信息" value="/sail_schedule/page" />
|
||||
<el-checkbox label="舱单信息" value="/manifest/page" />
|
||||
<el-checkbox label="舱单明细" value="/manifest/detail/page" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-checkbox">
|
||||
<div class="checkbox-title">发布船货信息:</div>
|
||||
<div class="checkbox">
|
||||
<el-checkbox label="发布船货信息" value="sail_schedule/save" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-checkbox">
|
||||
<div class="checkbox-title">订阅船货信息:</div>
|
||||
<div class="checkbox">
|
||||
<el-checkbox label="我的订阅" value="/subscribe/publish/page" />
|
||||
<el-checkbox label="收到订阅" value="/subscribe/receive/page" />
|
||||
</div>
|
||||
</div>
|
||||
</el-checkbox-group>
|
||||
|
||||
<div class="content-btn">
|
||||
<el-button type="primary" @click="onClickSubmit"> 提交保存 </el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { computed, ref } from 'vue';
|
||||
import { postEmployeePageAPI } from '@/api/Enterprise/employee';
|
||||
import { getUserRoleMenuListAPI, postRolePremSaveAPI } from '@/api/System/role';
|
||||
import { EmployeeType } from '@/types/Enterprise';
|
||||
|
||||
// 用户列表
|
||||
const employeeList = ref<EmployeeType[]>([]);
|
||||
|
||||
// 分页参数-当前页数
|
||||
const currentPage = ref(1);
|
||||
|
||||
// 加载更多状态
|
||||
const loadMoreState = ref('loading');
|
||||
const disabled = computed(() => loadMoreState.value === 'finished');
|
||||
|
||||
// 获取用户列表
|
||||
const getEmployeeList = async () => {
|
||||
const { data } = await postEmployeePageAPI({
|
||||
page: currentPage.value,
|
||||
rows: 10,
|
||||
});
|
||||
|
||||
employeeList.value = [...employeeList.value, ...data.records];
|
||||
currentPage.value++;
|
||||
// 检查是否到达最后一页或当前数据不足一页
|
||||
if (currentPage.value >= Number(data.pages) || data.records.length < 10) {
|
||||
loadMoreState.value = 'finished';
|
||||
} else {
|
||||
loadMoreState.value = 'loading';
|
||||
}
|
||||
};
|
||||
|
||||
// 当前选中的用户
|
||||
const currentUser = ref<{
|
||||
name: string;
|
||||
userId: number | string;
|
||||
perms: string[];
|
||||
}>({
|
||||
name: '',
|
||||
userId: '',
|
||||
perms: [],
|
||||
});
|
||||
|
||||
// 获取用户权限
|
||||
const onClickOpenDialog = async (row: EmployeeType) => {
|
||||
const { data } = await getUserRoleMenuListAPI({ userId: row.id });
|
||||
currentUser.value.name = row.name;
|
||||
currentUser.value.userId = row.id;
|
||||
currentUser.value.perms = data;
|
||||
};
|
||||
|
||||
// 保存用户权限
|
||||
const onClickSubmit = async () => {
|
||||
// 判断是否选中了用户
|
||||
if (currentUser.value.userId) {
|
||||
await postRolePremSaveAPI({
|
||||
userId: currentUser.value.userId,
|
||||
perms: currentUser.value.perms,
|
||||
});
|
||||
ElMessage({
|
||||
message: '保存成功',
|
||||
type: 'success',
|
||||
});
|
||||
} else {
|
||||
ElMessage({
|
||||
message: '请选择用户',
|
||||
type: 'warning',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const employeeListLoad = async () => {
|
||||
await getEmployeeList();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notify {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
color: #fff;
|
||||
.list {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.list-left {
|
||||
box-sizing: border-box;
|
||||
width: 30%;
|
||||
.left-title {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 40px;
|
||||
}
|
||||
.list-wrap {
|
||||
height: 500px;
|
||||
overflow: auto;
|
||||
.list-item {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
padding: 0 6px;
|
||||
overflow: hidden;
|
||||
border-bottom: 1px solid #fff;
|
||||
.item-title {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.item-date {
|
||||
margin-left: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.list-item:hover {
|
||||
color: #333;
|
||||
background-color: #ffffc9;
|
||||
}
|
||||
.list-item-active {
|
||||
color: #333;
|
||||
background-color: #ffffc9;
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-right {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
margin-left: 20px;
|
||||
.right-title {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 40px;
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
padding: 40px;
|
||||
color: #333;
|
||||
background-color: #fff;
|
||||
border-radius: 6px;
|
||||
.content-title {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 40px;
|
||||
}
|
||||
.content-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
.checkbox-title {
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.checkbox {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -2,51 +2,32 @@
|
|||
<div class="table">
|
||||
<div class="header">
|
||||
<el-form :inline="true" :model="searchTableForm" ref="tableFormRef">
|
||||
<!-- <el-form-item prop="enterpriseId">
|
||||
<RemoteSelect
|
||||
v-model:value="searchTableForm.enterpriseId"
|
||||
placeholder="请选择企业"
|
||||
style="width: 120px"
|
||||
:api="postEnterpriseListAPI"
|
||||
/>
|
||||
</el-form-item> -->
|
||||
<el-form-item prop="wharfId">
|
||||
<RemoteSelect
|
||||
v-model:value="searchTableForm.wharfId"
|
||||
placeholder="请选择码头"
|
||||
:api="postWharfListAPI"
|
||||
style="width: 120px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="name">
|
||||
<el-input v-model="searchTableForm.name" placeholder="姓名" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="searchTableForm.username" placeholder="用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="onClickSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="onClickResetForm(tableFormRef)">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="footer-util">
|
||||
<div>
|
||||
<el-button type="primary" icon="Plus" @click="onClickOpenDialog('新增')">
|
||||
新增员工
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
<el-table
|
||||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="name" label="姓名" align="center" width="180" />
|
||||
<el-table-column prop="enterprise.name" label="企业名称" align="center" width="100" />
|
||||
<el-table-column prop="dept" label="部门" align="center" width="180" />
|
||||
<el-table-column prop="job" label="职位" align="center" width="180" />
|
||||
<el-table-column prop="nickname" label="昵称" align="center" width="180" />
|
||||
<el-table-column prop="username" label="用户名" align="center" width="180" />
|
||||
<el-table-column prop="wharf.name" label="码头" align="center" width="180" />
|
||||
|
@ -71,7 +52,7 @@
|
|||
>
|
||||
查看
|
||||
</el-button>
|
||||
<!-- <el-button
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="Edit"
|
||||
|
@ -79,7 +60,7 @@
|
|||
@click="onClickOpenDialog('编辑', scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button> -->
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
|
@ -110,13 +91,12 @@
|
|||
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import {
|
||||
postEmployeeAddAPI,
|
||||
postEmployeeDeleteAPI,
|
||||
postEmployeePageAPI,
|
||||
postEmployeeSaveAPI,
|
||||
} from '@/api/Enterprise/employee';
|
||||
import { postWharfListAPI } from '@/api/Wharf';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import RemoteSelect from '@/components/RemoteSelect/index.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
import { EmployeeType } from '@/types/Enterprise';
|
||||
import EmployeeDialog from './EmployeeDialog.vue';
|
||||
|
@ -133,10 +113,7 @@ onMounted(async () => {
|
|||
|
||||
// 查询条件
|
||||
const searchTableForm = reactive({
|
||||
// enterpriseId: route.query.enterpriseId as string,
|
||||
name: '',
|
||||
username: '',
|
||||
wharfId: '',
|
||||
});
|
||||
|
||||
// 表格是否加载
|
||||
|
@ -171,8 +148,8 @@ const onClickOpenDialog = (title: string, row: Partial<EmployeeType> = {}) => {
|
|||
const params = {
|
||||
title,
|
||||
isView: title === '查看',
|
||||
row: { ...row },
|
||||
api: postEmployeeSaveAPI,
|
||||
row: title === '新增' ? { password: '123456', ...row } : { ...row },
|
||||
api: title === '新增' ? postEmployeeAddAPI : postEmployeeSaveAPI,
|
||||
getTableList,
|
||||
};
|
||||
employeeDialogRef.value?.isShowDialog(params);
|
||||
|
@ -220,11 +197,8 @@ const handleCurrentChange = async (val: number) => {
|
|||
width: 100%;
|
||||
.header {
|
||||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
justify-content: space-between;
|
||||
padding: 0 16px;
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
|
@ -234,15 +208,6 @@ const handleCurrentChange = async (val: number) => {
|
|||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.footer-table {
|
||||
position: relative;
|
||||
flex: 1;
|
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<div class="notify">
|
||||
<div class="list">
|
||||
<div class="list-wrap">
|
||||
<div class="title">{{ wharfInfo?.name }}</div>
|
||||
<div class="list-item">地理位置:{{ wharfInfo?.address }}</div>
|
||||
<div class="list-item">通过能力:{{ wharfInfo?.transitCapacity }}</div>
|
||||
<div class="list-item">泊位数量:{{ wharfInfo?.berthageNum }}</div>
|
||||
<div class="list-item">堆存能力:{{ wharfInfo?.storageCapacity }}</div>
|
||||
<div class="list-item">接卸能力:{{ wharfInfo?.handlingCapacity }}</div>
|
||||
<div class="list-item">简介:{{ wharfInfo?.intro }}</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<img class="wharfInfo" :src="wharfPhoto" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { getWharfPhotoAPI, postWharfInfoAPI } from '@/api/Wharf';
|
||||
import { LoadInfoType } from '@/types/boatInfo';
|
||||
|
||||
// 码头信息
|
||||
const wharfInfo = ref<LoadInfoType>();
|
||||
const wharfPhoto = ref('');
|
||||
|
||||
// 获取绑定的码头信息
|
||||
const getWharfInfo = async () => {
|
||||
const { data } = await postWharfInfoAPI();
|
||||
wharfInfo.value = data;
|
||||
// 获取码头图片
|
||||
const { data: photo } = await getWharfPhotoAPI(data.portId);
|
||||
|
||||
const arrayBufferToBase64 = (buffer: ArrayBuffer): string => {
|
||||
let binary = '';
|
||||
const bytes = new Uint8Array(buffer);
|
||||
const len = bytes.byteLength;
|
||||
for (let i = 0; i < len; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return btoa(binary);
|
||||
};
|
||||
|
||||
const base64String = arrayBufferToBase64(photo);
|
||||
wharfPhoto.value = `data:image/png;base64,${base64String}`;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await getWharfInfo();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notify {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
color: #fff;
|
||||
.list {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.list-wrap {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
.title {
|
||||
font-size: 26px;
|
||||
font-weight: 700;
|
||||
line-height: 40px;
|
||||
}
|
||||
.list-item {
|
||||
font-size: 20px;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
margin-left: 20px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,93 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<div class="title">用户设置</div>
|
||||
<div class="api-btn">
|
||||
<div
|
||||
class="btn"
|
||||
:class="{ 'btn-active': currentNav === item }"
|
||||
v-for="item in helpDocsList"
|
||||
:key="item"
|
||||
@click="onClickChangeNav(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<Wharf v-if="currentNav === '码头信息'" />
|
||||
<EmployeeTable v-if="currentNav === '用户管理'" />
|
||||
<employeeRole v-if="currentNav === '权限管理'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import employeeRole from './components/EmployeeRole.vue';
|
||||
import EmployeeTable from './components/EmployeeTable.vue';
|
||||
import Wharf from './components/Wharf.vue';
|
||||
|
||||
// 帮助文档列表
|
||||
const helpDocsList = ref(['码头信息', '用户管理', '权限管理']);
|
||||
const currentNav = ref('码头信息');
|
||||
const onClickChangeNav = (item: string) => {
|
||||
if (item === currentNav.value) return;
|
||||
currentNav.value = item;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.header {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 15px;
|
||||
color: #fff;
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.api-btn {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
color: #d7d7d7;
|
||||
background-color: rgb(51 51 51 / 100%);
|
||||
border-radius: 75px;
|
||||
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
|
||||
}
|
||||
.btn-active {
|
||||
color: #000;
|
||||
background-color: #f2f2f2;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="manage">
|
||||
<PublishTable />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import PublishTable from './components/PublishTable.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="manage">
|
||||
<ReceiveTable />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ReceiveTable from './components/ReceiveTable.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -83,10 +83,10 @@
|
|||
</el-form-item>
|
||||
<el-form-item label="订阅状态" prop="subStatus">
|
||||
<el-select v-model="dialogProps.row!.subStatus" placeholder="请选择订阅状态">
|
||||
<el-option label="待接受" value="待接受" />
|
||||
<el-option label="已关闭" value="已关闭" />
|
||||
<el-option label="订阅中" value="订阅中" />
|
||||
<el-option label="已取消" value="已取消" />
|
||||
<el-option label="待接受" value="NO_ACCEPTED" />
|
||||
<el-option label="已关闭" value="CLOSED" />
|
||||
<el-option label="订阅中" value="SUBSCRIBE" />
|
||||
<el-option label="已取消" value="CANCELLED" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<!-- <div class="header">
|
||||
<el-form :inline="true" :model="searchTableForm" ref="tableFormRef">
|
||||
<el-form-item>
|
||||
<RemoteSelect
|
||||
|
@ -31,7 +31,7 @@
|
|||
<el-button icon="Refresh" @click="onClickResetForm(tableFormRef)">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="footer">
|
||||
<div class="footer-util">
|
||||
<el-button type="primary" icon="Plus" @click="onClickOpenDialog('新增')">
|
||||
|
@ -44,7 +44,6 @@
|
|||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="enterprise.name" label="订阅企业" align="center" width="150" />
|
||||
|
@ -127,10 +126,10 @@
|
|||
prop="status"
|
||||
>
|
||||
<el-select v-model="statusForm.status" placeholder="请选择订阅状态">
|
||||
<el-option label="待接受" value="待接受" />
|
||||
<el-option label="已关闭" value="已关闭" />
|
||||
<el-option label="订阅中" value="订阅中" />
|
||||
<el-option label="已取消" value="已取消" />
|
||||
<el-option label="待接受" value="NO_ACCEPTED" />
|
||||
<el-option label="已关闭" value="CLOSED" />
|
||||
<el-option label="订阅中" value="SUBSCRIBE" />
|
||||
<el-option label="已取消" value="CANCELLED" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
@ -148,17 +147,13 @@
|
|||
import dayjs from 'dayjs';
|
||||
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { postEnterpriseListAPI } from '@/api/Enterprise/company';
|
||||
import { postPortListAPI } from '@/api/Port';
|
||||
import {
|
||||
editStatusAPI,
|
||||
publishPageAPI,
|
||||
subscriptionDeleteAPI,
|
||||
subscriptionSaveAPI,
|
||||
} from '@/api/Subscription';
|
||||
import { postWharfListAPI } from '@/api/Wharf';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import RemoteSelect from '@/components/RemoteSelect/index.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
import { PageRowsResult } from '@/types';
|
||||
import { SubscriptionType } from '@/types/subscription';
|
||||
|
@ -175,48 +170,25 @@ const handleTableData = (data: PageRowsResult<SubscriptionType>) => {
|
|||
};
|
||||
|
||||
// 获取列表表格数据
|
||||
const { getTableList, tableState, searchTable, resetTable, tableChangeCurrent, tableChangeSize } =
|
||||
useTable({
|
||||
const { getTableList, tableState, tableChangeCurrent, tableChangeSize } = useTable({
|
||||
api: publishPageAPI,
|
||||
dataCallBack: handleTableData,
|
||||
});
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await getTableList();
|
||||
});
|
||||
|
||||
// 查询条件
|
||||
const searchTableForm = reactive({
|
||||
enterpriseId: '',
|
||||
portId: '',
|
||||
wharfId: '',
|
||||
});
|
||||
// const searchTableForm = reactive({
|
||||
// enterpriseId: '',
|
||||
// portId: '',
|
||||
// wharfId: '',
|
||||
// });
|
||||
|
||||
// 表格是否加载
|
||||
const tableLoading = ref(false);
|
||||
|
||||
// 查询表单节点
|
||||
const tableFormRef = ref<FormInstance>();
|
||||
|
||||
// 查询
|
||||
const onClickSearch = async () => {
|
||||
tableLoading.value = true;
|
||||
|
||||
// 添加查询参数
|
||||
tableState.value.searchParam = searchTableForm;
|
||||
|
||||
// 查询表格
|
||||
await searchTable();
|
||||
tableLoading.value = false;
|
||||
};
|
||||
|
||||
// 重置
|
||||
const onClickResetForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await resetTable();
|
||||
formEl.resetFields();
|
||||
};
|
||||
|
||||
const publishDialogRef = ref<InstanceType<typeof PublishDialog> | null>(null);
|
||||
const onClickOpenDialog = (title: string, row: Partial<SubscriptionType> = {}) => {
|
||||
const params = {
|
||||
|
@ -302,9 +274,7 @@ const handleCurrentChange = async (val: number) => {
|
|||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
|
@ -314,9 +284,7 @@ const handleCurrentChange = async (val: number) => {
|
|||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<!-- <div class="header">
|
||||
<el-form :inline="true" :model="searchTableForm" ref="tableFormRef">
|
||||
<el-form-item>
|
||||
<RemoteSelect
|
||||
|
@ -31,7 +31,7 @@
|
|||
<el-button icon="Refresh" @click="onClickResetForm(tableFormRef)">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div> -->
|
||||
<div class="footer">
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
|
@ -75,14 +75,9 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import dayjs from 'dayjs';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { postEnterpriseListAPI } from '@/api/Enterprise/company';
|
||||
import { postPortListAPI } from '@/api/Port';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { receivePageAPI } from '@/api/Subscription';
|
||||
import { postWharfListAPI } from '@/api/Wharf';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import RemoteSelect from '@/components/RemoteSelect/index.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
import { PageRowsResult } from '@/types';
|
||||
import { SubscriptionType } from '@/types/subscription';
|
||||
|
@ -98,48 +93,20 @@ const handleTableData = (data: PageRowsResult<SubscriptionType>) => {
|
|||
};
|
||||
|
||||
// 获取列表表格数据
|
||||
const { getTableList, tableState, searchTable, resetTable, tableChangeCurrent, tableChangeSize } =
|
||||
useTable({
|
||||
const { getTableList, tableState, tableChangeCurrent, tableChangeSize } = useTable({
|
||||
api: receivePageAPI,
|
||||
dataCallBack: handleTableData,
|
||||
});
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await getTableList();
|
||||
});
|
||||
|
||||
// 查询条件
|
||||
const searchTableForm = reactive({
|
||||
enterpriseId: '',
|
||||
portId: '',
|
||||
wharfId: '',
|
||||
});
|
||||
|
||||
// 表格是否加载
|
||||
const tableLoading = ref(false);
|
||||
|
||||
// 查询表单节点
|
||||
const tableFormRef = ref<FormInstance>();
|
||||
|
||||
// 查询
|
||||
const onClickSearch = async () => {
|
||||
tableLoading.value = true;
|
||||
|
||||
// 添加查询参数
|
||||
tableState.value.searchParam = searchTableForm;
|
||||
|
||||
// 查询表格
|
||||
await searchTable();
|
||||
tableLoading.value = false;
|
||||
};
|
||||
|
||||
// 重置
|
||||
const onClickResetForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await resetTable();
|
||||
formEl.resetFields();
|
||||
};
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
await tableChangeSize(val);
|
||||
|
@ -162,9 +129,7 @@ const handleCurrentChange = async (val: number) => {
|
|||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
|
@ -174,9 +139,7 @@ const handleCurrentChange = async (val: number) => {
|
|||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
|
@ -0,0 +1,91 @@
|
|||
<template>
|
||||
<div class="table">
|
||||
<div class="header">
|
||||
<div class="title">{{ currentSubscribeNav }}清单</div>
|
||||
<div class="api-btn">
|
||||
<div
|
||||
class="btn"
|
||||
:class="{ 'btn-active': currentSubscribeNav === item }"
|
||||
v-for="item in subscribeNavList"
|
||||
:key="item"
|
||||
@click="onClickChangeSubscribeType(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<PublishTable v-if="currentSubscribeNav === '我的订阅'" />
|
||||
<ReceiveTable v-if="currentSubscribeNav === '收到订阅'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import PublishTable from './components/PublishTable.vue';
|
||||
import ReceiveTable from './components/ReceiveTable.vue';
|
||||
|
||||
// 订阅导航列表
|
||||
const subscribeNavList = ref(['我的订阅', '收到订阅']);
|
||||
const currentSubscribeNav = ref('我的订阅');
|
||||
const onClickChangeSubscribeType = async (item: string) => {
|
||||
if (item === currentSubscribeNav.value) return;
|
||||
currentSubscribeNav.value = item;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.header {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 15px;
|
||||
color: #fff;
|
||||
.title {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.api-btn {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
margin-left: 10px;
|
||||
font-size: 18px;
|
||||
color: #d7d7d7;
|
||||
background-color: rgb(51 51 51 / 100%);
|
||||
border-radius: 75px;
|
||||
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
|
||||
}
|
||||
.btn-active {
|
||||
color: #000;
|
||||
background-color: #f2f2f2;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,100 +0,0 @@
|
|||
<template>
|
||||
<el-drawer
|
||||
v-model="drawerVisible"
|
||||
:title="`${drawerProps.title}角色`"
|
||||
size="450px"
|
||||
:destroy-on-close="true"
|
||||
>
|
||||
<el-form
|
||||
ref="roleFormRef"
|
||||
label-width="100px"
|
||||
label-suffix=" :"
|
||||
:disabled="drawerProps.isView"
|
||||
:model="drawerProps.row"
|
||||
:hide-required-asterisk="drawerProps.isView"
|
||||
:rules="roleDrawerRules"
|
||||
>
|
||||
<el-form-item label="角色名称" prop="name" required>
|
||||
<el-input v-model="drawerProps.row!.name" placeholder="请输入角色名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="角色标识" prop="code" required>
|
||||
<el-input v-model="drawerProps.row!.code" placeholder="请输入角色标识,标识唯一" />
|
||||
</el-form-item>
|
||||
<el-form-item label="角色类型" prop="type" required>
|
||||
<el-select v-model="drawerProps.row!.type" placeholder="请选择角色类型" style="width: 100%">
|
||||
<el-option label="系统管理员" value="系统管理员" />
|
||||
<el-option label="普通角色" value="普通角色" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="角色描述">
|
||||
<el-input v-model="drawerProps.row!.remark" type="textarea" placeholder="请输入角色描述" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="drawerVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="onClickConfirm(roleFormRef)">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { roleType } from '@/types/role';
|
||||
|
||||
interface DrawerPropsType {
|
||||
title: string;
|
||||
isView: boolean;
|
||||
row: Partial<roleType>;
|
||||
api?: (params: any) => Promise<any>;
|
||||
getTableList?: () => void;
|
||||
}
|
||||
|
||||
// 是否显示drawer
|
||||
const drawerVisible = ref(false);
|
||||
|
||||
// 父组件传递的值
|
||||
const drawerProps = ref<DrawerPropsType>({
|
||||
isView: false,
|
||||
title: '',
|
||||
row: {},
|
||||
});
|
||||
|
||||
const isShowDrawer = async (item: DrawerPropsType) => {
|
||||
drawerProps.value = item;
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
// 向父组件暴露该方法
|
||||
defineExpose({ isShowDrawer });
|
||||
|
||||
// 表单节点
|
||||
const roleFormRef = ref<FormInstance>();
|
||||
|
||||
// 校验规则
|
||||
const roleDrawerRules = reactive<FormRules>({
|
||||
name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
|
||||
code: [{ required: true, message: '请输入角色标识', trigger: 'blur' }],
|
||||
});
|
||||
|
||||
// 新增/编辑角色
|
||||
const onClickConfirm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
try {
|
||||
// 新增角色
|
||||
await drawerProps.value.api!(drawerProps.value.row);
|
||||
ElMessage({ message: `${drawerProps.value.title}成功`, type: 'success' });
|
||||
drawerProps.value.getTableList!();
|
||||
} finally {
|
||||
drawerVisible.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -1,88 +0,0 @@
|
|||
<template>
|
||||
<div class="roleMenuTree">
|
||||
<div class="title">
|
||||
<span>角色名称</span>
|
||||
<el-input v-model="row!" style="flex: 1" disabled />
|
||||
</div>
|
||||
<el-scrollbar max-height="100%">
|
||||
<el-tree
|
||||
ref="roleMenuTreeRef"
|
||||
:data="menuTreeData"
|
||||
:props="defaultMenuProps"
|
||||
:default-expanded-keys="menuData"
|
||||
show-checkbox
|
||||
highlight-current
|
||||
node-key="url"
|
||||
@check-change="onCheckTreeChange"
|
||||
/>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElTree } from 'element-plus';
|
||||
import { ref } from 'vue';
|
||||
import { menuType } from '@/types/menu';
|
||||
|
||||
/**
|
||||
* 父组件传递值类型
|
||||
*/
|
||||
interface MenuTreePropsType {
|
||||
row: string;
|
||||
menuTreeData: menuType[];
|
||||
menuData: string[];
|
||||
}
|
||||
|
||||
// 接受父组件参数
|
||||
withDefaults(defineProps<MenuTreePropsType>(), {
|
||||
row: '',
|
||||
menuTreeData: () => [],
|
||||
menuData: () => [],
|
||||
});
|
||||
|
||||
// 菜单节点默认配置
|
||||
const defaultMenuProps = {
|
||||
children: 'children',
|
||||
label: 'name',
|
||||
};
|
||||
|
||||
// 菜单权限节点
|
||||
const roleMenuTreeRef = ref<InstanceType<typeof ElTree>>();
|
||||
|
||||
// 监听用户菜单数据-获取并设置用户菜单数据
|
||||
// watch(
|
||||
// () => props.menuData,
|
||||
// () => {
|
||||
// // 在父组件渲染完成后,等待下一个 DOM 更新周期
|
||||
// // nextTick(() => {
|
||||
// // // 在回调函数中处理数据变化的逻辑
|
||||
// // roleMenuTreeRef.value?.setCheckedKeys(props.menuData, true);
|
||||
// // });
|
||||
// },
|
||||
// { immediate: true }
|
||||
// );
|
||||
|
||||
// 选中菜单
|
||||
const emit = defineEmits(['updateMenuData']);
|
||||
|
||||
const onCheckTreeChange = () => {
|
||||
emit('updateMenuData', roleMenuTreeRef.value?.getCheckedKeys());
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.roleMenuTree {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.title {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.el-scrollbar {
|
||||
border: var(--zb-border-light);
|
||||
border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,319 +0,0 @@
|
|||
<template>
|
||||
<div class="role-table">
|
||||
<div class="header">
|
||||
<el-form :inline="true" :model="roleTableForm" ref="roleTableFormRef">
|
||||
<el-form-item label="角色名" prop="name">
|
||||
<el-input v-model="roleTableForm.name" placeholder="请输入角色名称" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="onClickSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="onClickResetForm(roleTableFormRef)">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="footer-util">
|
||||
<el-button type="primary" icon="Plus" @click="onClickOpenDrawer('新增')">
|
||||
新增角色
|
||||
</el-button>
|
||||
</div>
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
<el-table
|
||||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="name" label="角色名称" align="center" width="100" />
|
||||
<el-table-column
|
||||
prop="type"
|
||||
:show-overflow-tooltip="true"
|
||||
width="180"
|
||||
label="角色类型"
|
||||
align="center"
|
||||
/>
|
||||
<el-table-column prop="code" label="角色标识" align="center" width="180" />
|
||||
<el-table-column prop="dstatus" label="状态" align="center" width="100" />
|
||||
<el-table-column prop="remark" label="备注" align="center" width="180" />
|
||||
<el-table-column prop="createDate" label="创建时间" align="center" width="180" />
|
||||
<el-table-column prop="operator" label="操作" width="200px" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="Setting"
|
||||
link
|
||||
@click="onClickOpenMenuDrawer(scope.row)"
|
||||
>
|
||||
设置权限
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="Edit"
|
||||
link
|
||||
@click="onClickOpenDrawer('编辑', scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
icon="Delete"
|
||||
link
|
||||
@click="onClickDel(scope.row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<div class="footer-pagination">
|
||||
<Pagination
|
||||
:pageAble="tableState.pageAble"
|
||||
:handle-size-change="handleSizeChange"
|
||||
:handle-current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<RoleDrawer ref="roleDrawerRef" />
|
||||
|
||||
<el-drawer v-model="menuDrawer" :with-header="false" size="40%" title="角色配置">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane v-for="item in menuList" :key="item.name" :label="item.name">
|
||||
<RoleMenuTree
|
||||
:row="roleName"
|
||||
:menu-tree-data="item.list"
|
||||
:menuData="menuData"
|
||||
@update-menu-data="onUpdateMenuData"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<template #footer>
|
||||
<div style="flex: auto">
|
||||
<el-button @click="menuDrawer = false">取消</el-button>
|
||||
<el-button type="primary" @click="onClickConfirmRoleMenu">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { getAppListAPI, getMenuTreeAPI } from '@/api/System/menu';
|
||||
import {
|
||||
getRoleDeleteAPI,
|
||||
getRoleMenuListAPI,
|
||||
postRolePageAPI,
|
||||
postRolePremSaveAPI,
|
||||
postRoleSaveAPI,
|
||||
} from '@/api/System/role';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
import { menuType } from '@/types/menu';
|
||||
import { rolePremType, roleType } from '@/types/role';
|
||||
import RoleDrawer from './RoleDrawer.vue';
|
||||
import RoleMenuTree from './RoleMenuTree.vue';
|
||||
|
||||
// 获取角色列表表格数据
|
||||
const { getTableList, tableState, searchTable, resetTable, tableChangeCurrent, tableChangeSize } =
|
||||
useTable({
|
||||
api: postRolePageAPI,
|
||||
});
|
||||
|
||||
// 全部菜单列表
|
||||
const menuList = ref<
|
||||
{
|
||||
name: string;
|
||||
list: menuType[];
|
||||
}[]
|
||||
>([]);
|
||||
|
||||
// 获取全部菜单信息
|
||||
const getMenuList = async () => {
|
||||
try {
|
||||
const { data } = await getAppListAPI();
|
||||
if (data.length > 0) {
|
||||
for (const item of data) {
|
||||
const { data: list } = await getMenuTreeAPI({ appName: item });
|
||||
menuList.value.push({ name: item, list });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await getTableList();
|
||||
await getMenuList();
|
||||
});
|
||||
|
||||
// 查询条件
|
||||
const roleTableForm = reactive({
|
||||
name: '',
|
||||
});
|
||||
|
||||
// 查询表单节点
|
||||
const roleTableFormRef = ref<FormInstance>();
|
||||
|
||||
// 表格是否加载
|
||||
const tableLoading = ref(false);
|
||||
|
||||
// 查询
|
||||
const onClickSearch = async () => {
|
||||
tableLoading.value = true;
|
||||
|
||||
// 添加查询参数
|
||||
tableState.value.searchParam = roleTableForm;
|
||||
|
||||
// 查询表格
|
||||
await searchTable();
|
||||
tableLoading.value = false;
|
||||
};
|
||||
|
||||
// 重置
|
||||
const onClickResetForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await resetTable();
|
||||
formEl.resetFields();
|
||||
};
|
||||
|
||||
// 新增/编辑角色
|
||||
const roleDrawerRef = ref<InstanceType<typeof RoleDrawer> | null>(null);
|
||||
const onClickOpenDrawer = (title: string, row: Partial<roleType> = {}) => {
|
||||
const params = {
|
||||
title,
|
||||
isView: title === '查看',
|
||||
row: { ...row },
|
||||
api: postRoleSaveAPI,
|
||||
getTableList: getTableList,
|
||||
};
|
||||
roleDrawerRef.value?.isShowDrawer(params);
|
||||
};
|
||||
|
||||
// 设置权限
|
||||
const menuDrawer = ref(false);
|
||||
|
||||
// 菜单权限表单
|
||||
const roleName = ref('');
|
||||
const activeRow = ref<rolePremType>({
|
||||
roleId: 0,
|
||||
perms: [],
|
||||
});
|
||||
|
||||
// 用户菜单列表
|
||||
const menuData = ref<string[]>([]);
|
||||
|
||||
// 获取用户菜单列表
|
||||
const getUserMenuList = async (roleId: number) => {
|
||||
const { data } = await getRoleMenuListAPI({ roleId });
|
||||
menuData.value = data;
|
||||
};
|
||||
|
||||
// 打开设置权限
|
||||
const onClickOpenMenuDrawer = async (row: roleType) => {
|
||||
roleName.value = row.name;
|
||||
row.id && (await getUserMenuList(row.id));
|
||||
menuDrawer.value = true;
|
||||
};
|
||||
|
||||
const onUpdateMenuData = (data: string[]) => {
|
||||
activeRow.value.perms = data;
|
||||
};
|
||||
|
||||
// 确认角色权限
|
||||
const onClickConfirmRoleMenu = async () => {
|
||||
await postRolePremSaveAPI(activeRow.value);
|
||||
menuDrawer.value = false;
|
||||
ElMessage({
|
||||
message: '设置权限成功',
|
||||
type: 'success',
|
||||
});
|
||||
};
|
||||
// 删除角色
|
||||
const onClickDel = (row: roleType) => {
|
||||
ElMessageBox.confirm(`确定要删除角色 ${row.name} 吗?`, '温馨提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
draggable: true,
|
||||
})
|
||||
.then(async () => {
|
||||
await getRoleDeleteAPI([row.id]);
|
||||
// 更新表格
|
||||
await getTableList();
|
||||
ElMessage({
|
||||
message: '删除角色成功',
|
||||
type: 'success',
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('用户点击了取消');
|
||||
});
|
||||
};
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
await tableChangeSize(val);
|
||||
};
|
||||
|
||||
// 当前页数改变
|
||||
const handleCurrentChange = async (val: number) => {
|
||||
await tableChangeCurrent(val);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.role-table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
.header {
|
||||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.footer-table {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
}
|
||||
.footer-pagination {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="roleManage">
|
||||
<RoleTable />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import RoleTable from './components/RoleTable.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.roleManage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -1,144 +0,0 @@
|
|||
<template>
|
||||
<el-drawer
|
||||
v-model="drawerVisible"
|
||||
:destroy-on-close="true"
|
||||
size="450px"
|
||||
:title="`${drawerProps.title}用户`"
|
||||
>
|
||||
<el-form
|
||||
ref="ruleFormRef"
|
||||
label-width="100px"
|
||||
label-suffix=" :"
|
||||
:rules="userDrawerRules"
|
||||
:disabled="drawerProps.isView"
|
||||
:model="drawerProps.row"
|
||||
:hide-required-asterisk="drawerProps.isView"
|
||||
>
|
||||
<!-- <el-form-item label="用户头像" prop="avatar">
|
||||
<UploadImg
|
||||
v-model:image-url="drawerProps.row!.avatar"
|
||||
width="135px"
|
||||
height="135px"
|
||||
:file-size="3"
|
||||
>
|
||||
<template #empty>
|
||||
<el-icon><Avatar /></el-icon>
|
||||
<span>请上传头像</span>
|
||||
</template>
|
||||
<template #tip> 头像大小不能超过 3M </template>
|
||||
</UploadImg>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item label="用户姓名" prop="name">
|
||||
<el-input v-model="drawerProps.row!.name" placeholder="请填写用户姓名" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="账号" prop="username">
|
||||
<el-input v-model="drawerProps.row!.username" placeholder="请填写账号" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="phone">
|
||||
<el-input v-model="drawerProps.row!.phone" placeholder="请填写手机号" clearable></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱">
|
||||
<el-input v-model="drawerProps.row!.email" placeholder="请填写邮箱" clearable></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="drawerVisible = false">取消</el-button>
|
||||
<el-button v-show="!drawerProps.isView" type="primary" @click="onClickConfirm(ruleFormRef)"
|
||||
>确定</el-button
|
||||
>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { FormInstance, FormRules } from 'element-plus';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { userType } from '@/types/user';
|
||||
import { validPhone } from '@/utils/validate';
|
||||
|
||||
interface DrawerPropsType {
|
||||
title: string;
|
||||
isView: boolean;
|
||||
row: Partial<userType>;
|
||||
api?: (params: any) => Promise<any>;
|
||||
getTableList?: () => void;
|
||||
}
|
||||
|
||||
// 是否显示drawer
|
||||
const drawerVisible = ref(false);
|
||||
|
||||
// 父组件传递的值
|
||||
const drawerProps = ref<DrawerPropsType>({
|
||||
isView: false,
|
||||
title: '',
|
||||
row: {},
|
||||
});
|
||||
|
||||
// 显示drawer,新增/编辑用户
|
||||
const isShowDrawer = (item: DrawerPropsType) => {
|
||||
drawerProps.value = item;
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
// 向父组件暴露该方法
|
||||
defineExpose({ isShowDrawer });
|
||||
|
||||
/**
|
||||
* 手机号校验规则
|
||||
* @param {any} rule 校验规则
|
||||
* @param {string} value 手机号
|
||||
* @param {any} callback 回调函数
|
||||
* @return 是否通过校验
|
||||
*/
|
||||
const checkPhone = (rule: any, value: string, callback: any) => {
|
||||
if (!validPhone(value)) {
|
||||
// 返回一个错误提示
|
||||
callback(new Error('请输入正确的手机号码'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
// 校验规则
|
||||
const userDrawerRules = reactive<FormRules>({
|
||||
username: [
|
||||
{ required: true, message: '请输入账号', trigger: 'blur' },
|
||||
{ min: 4, message: '账号长度不能小于4位', trigger: 'blur' },
|
||||
],
|
||||
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
||||
phone: [
|
||||
{ required: true, message: '请输入手机号', trigger: 'blur' },
|
||||
{ validator: checkPhone, trigger: 'blur' },
|
||||
],
|
||||
});
|
||||
|
||||
// 表单节点
|
||||
const ruleFormRef = ref<FormInstance>();
|
||||
|
||||
// 新增/编辑用户
|
||||
const onClickConfirm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
try {
|
||||
// 用户新增/编辑不需要密码
|
||||
const row = { ...drawerProps.value.row };
|
||||
if (row.password !== undefined) {
|
||||
delete row.password;
|
||||
}
|
||||
await drawerProps.value.api!(row);
|
||||
ElMessage({
|
||||
message: `${drawerProps.value.title}成功`,
|
||||
type: 'success',
|
||||
});
|
||||
drawerProps.value.getTableList!();
|
||||
} finally {
|
||||
drawerVisible.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
|
@ -1,125 +0,0 @@
|
|||
<template>
|
||||
<el-dialog v-model="userRoleDialog" title="关联角色" width="50%" @close="onCloseDialog">
|
||||
<el-form ref="userRoleFormRef" :model="userRoleForm" :rules="userRoleRules" label-width="100px">
|
||||
<el-form-item label="用户名" required>
|
||||
<el-input v-model="userRoleForm.username" disabled placeholder="请输入用户名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户角色" prop="roleIds" required>
|
||||
<el-select
|
||||
v-model="userRoleForm.roleIds"
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
:max-collapse-tags="3"
|
||||
placeholder="请选择角色"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in roleList"
|
||||
:key="item.id"
|
||||
:label="item.text"
|
||||
:value="item.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="userRoleDialog = false">取消</el-button>
|
||||
<el-button type="primary" @click="onClickConfirm(userRoleFormRef)">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, FormInstance, FormRules } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { getRoleListAPI } from '@/api/System/role';
|
||||
import { getUserRoleListAPI, postUserRoleAPI } from '@/api/System/user';
|
||||
import { dictionaryListType } from '@/types';
|
||||
import { userType } from '@/types/user';
|
||||
|
||||
// 表单类型
|
||||
type userRoleFormType = {
|
||||
username: string;
|
||||
userId: number | string;
|
||||
roleIds: number[];
|
||||
};
|
||||
|
||||
// 角色列表
|
||||
const roleList = ref<dictionaryListType[]>([]);
|
||||
|
||||
// 获取角色列表
|
||||
const getRoleList = async () => {
|
||||
const { data } = await getRoleListAPI({});
|
||||
roleList.value = data;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await getRoleList();
|
||||
});
|
||||
|
||||
// 是否显示dialog
|
||||
const userRoleDialog = ref(false);
|
||||
|
||||
// 获取用户角色列表
|
||||
const getUserRoleList = async (userId: string | number) => {
|
||||
const { data } = await getUserRoleListAPI({ userId });
|
||||
userRoleForm.roleIds = data.map((item) => item.id);
|
||||
};
|
||||
|
||||
// 显示dialog,新增/编辑用户
|
||||
const isShowDialog = async (item: userType) => {
|
||||
if (item) {
|
||||
userRoleForm.userId = item.id;
|
||||
userRoleForm.username = item.username;
|
||||
item.id && (await getUserRoleList(item.id));
|
||||
}
|
||||
userRoleDialog.value = true;
|
||||
};
|
||||
|
||||
// 向父组件暴露该方法
|
||||
defineExpose({ isShowDialog });
|
||||
|
||||
// 新增/编辑用户表单
|
||||
const userRoleForm = reactive<userRoleFormType>({
|
||||
username: '', // 用户名
|
||||
userId: '',
|
||||
roleIds: [], // 角色列表
|
||||
});
|
||||
|
||||
// 表单节点
|
||||
const userRoleFormRef = ref<FormInstance>();
|
||||
|
||||
// dialog 关闭事件
|
||||
const onCloseDialog = () => {
|
||||
// 重置表单
|
||||
userRoleFormRef.value?.resetFields();
|
||||
};
|
||||
|
||||
// 校验规则
|
||||
const userRoleRules = reactive<FormRules>({
|
||||
roleIds: [{ required: true, message: '请选择用户角色', trigger: 'change' }],
|
||||
});
|
||||
|
||||
// 分配角色
|
||||
const onClickConfirm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
try {
|
||||
// 分配角色
|
||||
await postUserRoleAPI(userRoleForm);
|
||||
ElMessage({
|
||||
message: '设置用户角色成功',
|
||||
type: 'success',
|
||||
});
|
||||
} finally {
|
||||
userRoleDialog.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -1,245 +0,0 @@
|
|||
<template>
|
||||
<div class="user-table">
|
||||
<div class="header">
|
||||
<el-form :inline="true" :model="userTableForm" ref="userTableFormRef">
|
||||
<el-form-item label="账号" prop="username">
|
||||
<el-input v-model="userTableForm.username" placeholder="请输入账号" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="onClickSearch">查询</el-button>
|
||||
<el-button icon="Refresh" @click="onClickResetForm(userTableFormRef)">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="footer-util">
|
||||
<el-button type="primary" icon="Plus" @click="onClickOpenDrawer('新增')">
|
||||
新增用户
|
||||
</el-button>
|
||||
</div>
|
||||
<!-- 表格 -->
|
||||
<div class="footer-table">
|
||||
<el-table
|
||||
v-loading="tableLoading"
|
||||
:data="tableState.tableData"
|
||||
border
|
||||
stripe
|
||||
style="width: 100%; height: 100%"
|
||||
>
|
||||
<el-table-column prop="username" label="账号" align="center" width="180" />
|
||||
<el-table-column prop="name" label="姓名" align="center" />
|
||||
<el-table-column prop="roleList" label="关联角色" align="center" width="120">
|
||||
<template #default="scope">
|
||||
<div style="display: flex; flex-wrap: wrap">
|
||||
<el-tag
|
||||
v-for="item in scope.row.roleList"
|
||||
:key="item.id"
|
||||
effect="dark"
|
||||
disable-transitions
|
||||
style="margin-right: 6px; margin-bottom: 6px"
|
||||
>
|
||||
{{ item.roleName }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" label="手机号" align="center" width="120" />
|
||||
<el-table-column prop="email" label="邮箱" align="center" width="120" />
|
||||
<el-table-column prop="dstatus" label="用户状态" align="center" width="100" />
|
||||
<el-table-column prop="createDate" label="创建时间" align="center" width="180" />
|
||||
<el-table-column prop="operator" label="操作" width="200px" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="User"
|
||||
link
|
||||
@click="onClickOpenUserRole(scope.row)"
|
||||
>
|
||||
角色
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="Edit"
|
||||
link
|
||||
@click="onClickOpenDrawer('编辑', scope.row)"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
icon="Delete"
|
||||
link
|
||||
@click="onClickDel(scope.row)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<!-- 分页 -->
|
||||
<div class="footer-pagination">
|
||||
<Pagination
|
||||
:pageAble="tableState.pageAble"
|
||||
:handle-size-change="handleSizeChange"
|
||||
:handle-current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<UserDrawer ref="userDrawerRef" />
|
||||
<UserRoleDialog ref="userRoleDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { getUserDeleteAPI, postUserPageAPI, postUserSaveAPI } from '@/api/System/user';
|
||||
import Pagination from '@/components/Pagination/Pagination.vue';
|
||||
import { useTable } from '@/hooks/useTable';
|
||||
import { userType } from '@/types/user';
|
||||
import UserDrawer from './UserDrawer.vue';
|
||||
import UserRoleDialog from './UserRoleDialog.vue';
|
||||
|
||||
// 获取用户列表表格数据
|
||||
const { getTableList, tableState, searchTable, resetTable, tableChangeCurrent, tableChangeSize } =
|
||||
useTable({
|
||||
api: postUserPageAPI,
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await getTableList();
|
||||
});
|
||||
|
||||
// 查询条件
|
||||
const userTableForm = reactive({
|
||||
username: '',
|
||||
});
|
||||
|
||||
// 表格是否加载
|
||||
const tableLoading = ref(false);
|
||||
|
||||
// 查询表单节点
|
||||
const userTableFormRef = ref<FormInstance>();
|
||||
|
||||
// 查询
|
||||
const onClickSearch = async () => {
|
||||
tableLoading.value = true;
|
||||
|
||||
// 添加查询参数
|
||||
tableState.value.searchParam = userTableForm;
|
||||
|
||||
// 查询表格
|
||||
await searchTable();
|
||||
tableLoading.value = false;
|
||||
};
|
||||
|
||||
// 重置
|
||||
const onClickResetForm = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await resetTable();
|
||||
formEl.resetFields();
|
||||
};
|
||||
|
||||
// 设置用户角色
|
||||
const userRoleDialogRef = ref<InstanceType<typeof UserRoleDialog> | null>(null);
|
||||
const onClickOpenUserRole = (row: userType) => {
|
||||
userRoleDialogRef.value?.isShowDialog(row);
|
||||
};
|
||||
|
||||
// 新增/编辑/查看用户 drawer 节点
|
||||
const userDrawerRef = ref<InstanceType<typeof UserDrawer> | null>(null);
|
||||
const onClickOpenDrawer = (title: string, row: Partial<userType> = {}) => {
|
||||
const params = {
|
||||
title,
|
||||
isView: title === '查看',
|
||||
row: { ...row },
|
||||
api: postUserSaveAPI,
|
||||
getTableList: getTableList,
|
||||
};
|
||||
userDrawerRef.value?.isShowDrawer(params);
|
||||
};
|
||||
|
||||
// 删除
|
||||
const onClickDel = (row: userType) => {
|
||||
ElMessageBox.confirm(`你确定要删除用户 ${row.name} 吗?`, '温馨提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning',
|
||||
draggable: true,
|
||||
})
|
||||
.then(async () => {
|
||||
await getUserDeleteAPI([row.id]);
|
||||
// 更新表格
|
||||
await getTableList();
|
||||
ElMessage({
|
||||
message: '删除用户成功',
|
||||
type: 'success',
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('用户点击了取消');
|
||||
});
|
||||
};
|
||||
|
||||
// 改变每页显示条目个数
|
||||
const handleSizeChange = async (val: number) => {
|
||||
await tableChangeSize(val);
|
||||
};
|
||||
|
||||
// 当前页数改变
|
||||
const handleCurrentChange = async (val: number) => {
|
||||
await tableChangeCurrent(val);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-table {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
.header {
|
||||
display: flex;
|
||||
padding: 16px 16px 0;
|
||||
margin-bottom: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
}
|
||||
.footer {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
|
||||
.footer-util {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.footer-table {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
}
|
||||
.footer-pagination {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="userManage">
|
||||
<UserTable />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import UserTable from './components/UserTable.vue';
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.userManage {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue