feat: 更新样式

main
sankeyangshu 2024-11-29 16:52:09 +08:00
parent 1496a8b5b9
commit 22e100136b
39 changed files with 1187 additions and 824 deletions

View File

@ -61,6 +61,7 @@
"axios": "^1.6.8",
"dayjs": "^1.11.11",
"echarts": "^5.5.1",
"el-table-infinite-scroll": "3",
"element-plus": "^2.7.2",
"nprogress": "^0.2.0",
"path-browserify": "^1.0.1",

View File

@ -26,6 +26,9 @@ importers:
echarts:
specifier: ^5.5.1
version: 5.5.1
el-table-infinite-scroll:
specifier: '3'
version: 3.0.6(typescript@5.4.5)
element-plus:
specifier: ^2.7.2
version: 2.7.2(vue@3.4.27(typescript@5.4.5))
@ -1198,6 +1201,9 @@ packages:
resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==}
engines: {node: '>=0.10.0'}
core-js@3.39.0:
resolution: {integrity: sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==}
cors@2.8.5:
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
engines: {node: '>= 0.10'}
@ -1397,6 +1403,9 @@ packages:
echarts@5.5.1:
resolution: {integrity: sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==}
el-table-infinite-scroll@3.0.6:
resolution: {integrity: sha512-rdrEBcSMYpkD0s0jl28KcGZpiIbWzVR2OAf7hBB+c+c08G89jb9d6rOn+y2DuhE1iI1C0pEOlC5/lrP3QceOXg==}
electron-to-chromium@1.4.763:
resolution: {integrity: sha512-k4J8NrtJ9QrvHLRo8Q18OncqBCB7tIUyqxRcJnlonQ0ioHKYB988GcDFF3ZePmnb8eHEopDs/wPHR/iGAFgoUQ==}
@ -4629,6 +4638,8 @@ snapshots:
copy-descriptor@0.1.1: {}
core-js@3.39.0: {}
cors@2.8.5:
dependencies:
object-assign: 4.1.1
@ -4838,6 +4849,15 @@ snapshots:
tslib: 2.3.0
zrender: 5.6.0
el-table-infinite-scroll@3.0.6(typescript@5.4.5):
dependencies:
core-js: 3.39.0
element-plus: 2.7.2(vue@3.4.27(typescript@5.4.5))
vue: 3.4.27(typescript@5.4.5)
transitivePeerDependencies:
- '@vue/composition-api'
- typescript
electron-to-chromium@1.4.763: {}
element-plus@2.7.2(vue@3.4.27(typescript@5.4.5)):

View File

@ -1,4 +1,10 @@
import { loginDataType, userInfoRepType, userPasswordType, userType } from '@/types/user';
import {
loginDataType,
userInfoRepType,
userInfoType,
userPasswordType,
userType,
} from '@/types/user';
import http from '@/utils/request';
// api接口
@ -6,6 +12,7 @@ const api = {
login: '/admin/user/login', // 用户登录接口
userPassword: '/admin/user/password', // 用户修改密码
userGet: '/admin/user/get', // 用户详情
userInfo: '/admin/user/info', // 用户信息
};
/**
@ -38,3 +45,11 @@ export function postUserPasswordAPI(data: userPasswordType) {
export function getUserGetAPI(data: { id: number | string }) {
return http.postParams<userType>(api.userGet, data);
}
/**
*
* @return
*/
export function getUserInfoAPI() {
return http.postParams<userInfoType>(api.userInfo);
}

View File

@ -0,0 +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 -994 -699 )">
<path d="M 32 12.26666665625 L 19.73333334375 12.26666665625 L 19.73333334375 0 L 12.26666665625 0 L 12.26666665625 12.26666665625 L 0 12.26666665625 L 0 19.73333334375 L 12.26666665625 19.73333334375 L 12.26666665625 32 L 19.73333334375 32 L 19.73333334375 19.73333334375 L 32 19.73333334375 L 32 12.26666665625 Z " fill-rule="nonzero" fill="#facd91" stroke="none" transform="matrix(1 0 0 1 994 699 )" />
</g>
</svg>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M8 16.5v.5c1.691-2.578 3.6-3.953 6-4v3c0 .551.511 1 1.143 1c.364 0 .675-.158.883-.391C17.959 14.58 22 10.5 22 10.5s-4.041-4.082-5.975-6.137A1.26 1.26 0 0 0 15.143 4C14.511 4 14 4.447 14 5v3c-4.66 0-6 4.871-6 8.5M5 21h14a1 1 0 0 0 1-1v-6.046c-.664.676-1.364 1.393-2 2.047V19H6V7h7V5H5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1"/></svg>

After

Width:  |  Height:  |  Size: 436 B

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="36px" height="32px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -116 -109 )">
<path d="M 16.4578266189759 6.63061655405405 L 16.4578266189759 1.34535472972973 C 15.9758894954819 -0.864864864864865 14.1445877259036 0.480489864864865 14.1445877259036 0.480489864864865 L 1.42166792168675 11.3393581081081 C -1.37346573795181 13.2612331081081 1.22894390060241 14.7027027027027 1.22894390060241 14.7027027027027 L 13.7590549698795 25.4654560810811 C 16.2650602409639 27.2913006756757 16.4578266189759 24.5045185810811 16.4578266189759 24.5045185810811 L 16.4578266189759 19.603589527027 C 29.1807040662651 15.6636824324324 34.3855233433735 31.4234375 34.3855233433735 31.4234375 C 34.8674604668675 32.2883023648649 35.1566312123494 31.4234375 35.1566312123494 31.4234375 C 40.0722797439759 7.78378378378378 16.4577842620482 6.63061655405405 16.4577842620482 6.63061655405405 Z " fill-rule="nonzero" stroke="none" transform="matrix(1 0 0 1 116 109 )" />
</g>
</svg>

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 440 B

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="135px" height="135px" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1 0 0 1 -33 -708 )">
<image preserveAspectRatio="none" style="overflow:visible" width="135" height="135" xlink:href="data:image/png;base64,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" x="33px" y="708px" />
<path d="M 38 713 L 163 713 L 163 838 L 38 838 L 38 713 Z " stroke-width="10" stroke="#ffffff" fill="none" />
</g>
</svg>

View File

@ -17,18 +17,12 @@
<svg-icon :icon="item.icon" className="icon"></svg-icon>
<span>{{ item.title }}</span>
</div>
<div class="nav-item" @click="onClickLogout">
<svg-icon icon="Logout" className="icon"></svg-icon>
<span>退出</span>
</div>
</div>
</template>
<script lang="ts" setup>
import { ElMessage, ElMessageBox } from 'element-plus';
import { computed, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useUserStore } from '@/store/modules/user';
interface menuListType {
path: string;
@ -63,6 +57,11 @@ const menuList = ref<menuListType[]>([
title: '帮助',
icon: 'Help',
},
{
path: '/user',
title: '用户',
icon: 'user',
},
]);
//
@ -81,24 +80,6 @@ const activeMenu = computed(() => {
const onClickMenu = (item: menuListType) => {
router.push(item.path);
};
// store
const userStore = useUserStore();
const onClickLogout = async () => {
ElMessageBox.confirm('您是否确认退出登录?', '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
userStore.logout(true);
ElMessage({
type: 'success',
message: '退出登录成功!',
});
});
};
</script>
<style lang="scss" scoped>
@ -115,7 +96,9 @@ const onClickLogout = async () => {
flex-direction: column;
color: #fff;
.title {
font-family: 'Arial Negreta cursiva', 'Arial Normal', Arial;
font-size: 24px;
font-style: italic;
font-weight: 700;
}
.text {
@ -131,11 +114,13 @@ const onClickLogout = async () => {
display: flex;
align-items: center;
justify-content: center;
width: 100px;
width: 152px;
height: 100%;
font-size: 18px;
color: #fff;
.icon {
width: 32px;
height: 30px;
margin-right: 6px;
}
}

View File

@ -1,6 +1,6 @@
<template>
<div class="sidebar">
<img class="side-logo" src="@/assets/images/logo.png" />
<img class="side-logo" src="@/assets/images/ad.png" />
<div
class="side-item"
v-for="item in menuList"
@ -11,6 +11,10 @@
<svg-icon :icon="item.icon" className="side-icon"></svg-icon>
<span>{{ item.title }}</span>
</div>
<div class="erCode">
<img class="code" src="@/assets/images/erCode.svg" />
<div class="code-title">Mini APP</div>
</div>
</div>
</template>
@ -94,7 +98,7 @@ onMounted(async () => {
width: 200px;
height: 100%;
overflow: hidden;
background: #333;
background-color: #7f7f7f;
box-shadow: 2px 0 6px rgb(0 21 41 / 35%);
.side-logo {
width: 100%;
@ -112,8 +116,9 @@ onMounted(async () => {
background-color: #333;
border-bottom: 1px solid #555c64;
.side-icon {
width: 32px;
height: 29px;
margin-bottom: 6px;
font-size: 20px;
}
}
.side-item-active {
@ -125,5 +130,25 @@ onMounted(async () => {
cursor: pointer;
background-color: #000;
}
.erCode {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
padding: 20px 0;
.code {
width: 135px;
height: 135px;
}
.code-title {
margin-top: 20px;
font-family: 'Arial Negreta', 'Arial Normal', Arial;
font-size: 24px;
font-style: normal;
font-weight: 700;
color: #d7d7d7;
}
}
}
</style>

View File

@ -1,4 +1,5 @@
import * as ElementPlusIconsVue from '@element-plus/icons-vue'; // 统一导入el-icon图标
import ElTableInfiniteScroll from 'el-table-infinite-scroll';
import ElementPlus from 'element-plus';
import { App } from 'vue';
import 'element-plus/dist/index.css';
@ -9,6 +10,7 @@ import 'element-plus/theme-chalk/dark/css-vars.css'; // 暗黑主题
*/
export default (app: App<Element>) => {
app.use(ElementPlus);
app.use(ElTableInfiniteScroll);
// 统一注册el-icon图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);

View File

@ -75,6 +75,12 @@ export const constantRoutes: Array<RouteRecordRaw> = [
component: () => import('@/views/Help/index.vue'),
meta: { title: '帮助' },
},
{
path: '/user',
name: 'UserCenter',
component: () => import('@/views/User/index.vue'),
meta: { title: '用户' },
},
{
path: '/boat',
name: 'BoatInfo',

View File

@ -1,15 +1,11 @@
import { defineStore } from 'pinia';
import { postLoginAPI } from '@/api/System/user';
import { getUserInfoAPI, postLoginAPI } from '@/api/System/user';
import { router } from '@/router';
import { menuListType } from '@/types/menu';
import { roleResultType } from '@/types/role';
import { loginDataType, userInfoType } from '@/types/user';
interface userStateType {
token: string;
userInfo: userInfoType | {};
roles: roleResultType[];
menus: menuListType[];
routeName: string;
}
@ -21,8 +17,6 @@ export const useUserStore = defineStore({
state: (): userStateType => ({
token: '', // 登录token
userInfo: {}, // 用户信息
roles: [], // 权限角色
menus: [], // 菜单
routeName: '', // 当前页面的 router name用来做按钮权限筛选
}),
@ -33,6 +27,11 @@ export const useUserStore = defineStore({
this.token = value;
},
// 设置用户信息
setUserInfo(value: userInfoType | {}) {
this.userInfo = value;
},
/**
*
*/
@ -42,6 +41,8 @@ export const useUserStore = defineStore({
try {
const { data } = await postLoginAPI({ username: username.trim(), password: password });
this.setToken(data.accessToken); // 保存用户token
const { data: userInfoData } = await getUserInfoAPI();
this.setUserInfo(userInfoData);
resolve();
} catch (error) {
reject(error);

View File

@ -23,15 +23,22 @@ export interface userInfoRepType {
*
*/
export interface userInfoType {
password: string;
id: number;
id: string;
nickname: string;
username: string;
phone: string;
email: string;
userType: number;
status: number;
createtime: string;
updatetime: string;
tenantId: string;
auths: any[];
avatar: string;
deptId: string;
dataScopes: any[];
pkgs: any[];
token: string;
mini: boolean;
openId: string;
enterpriseId: string | number;
enterpriseName: string;
wharfId: string;
wharfName: string | number;
}
/**

View File

@ -1,33 +1,26 @@
<template>
<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 class="content" v-if="dialogVisible">
<div class="item">
<div class="title">接口名称</div>
<div class="text">{{ dialogProps?.name }}</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
</span>
</template>
</el-dialog>
<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>
<script lang="ts" setup>
@ -56,11 +49,6 @@ const isShowDialog = async (params: ApiManageType) => {
//
defineExpose({ isShowDialog });
// dialog
const onCloseDialog = () => {
dialogVisible.value = false;
};
</script>
<style lang="scss" scoped>
@ -73,10 +61,7 @@ const onCloseDialog = () => {
width: 100%;
font-size: 16px;
line-height: 27px;
.title {
font-weight: 700;
color: #000;
}
color: #333;
}
}
</style>

View File

@ -2,6 +2,7 @@
<div class="table">
<div class="footer">
<div class="footer-util">
<svg-icon icon="return" className="side-icon" @click="onClickReturn"></svg-icon>
<div class="title">滚装船货信息平台API开放接口文档</div>
<div class="api-btn">
<div
@ -17,24 +18,13 @@
</div>
<!-- 表格 -->
<div class="footer-table">
<el-table
v-loading="tableLoading"
:data="tableState.tableData"
border
style="width: 100%; height: 100%"
>
<el-table-column prop="name" label="名称" align="center" width="180" />
<el-table v-loading="tableLoading" :data="tableState.tableData" border max-height="180">
<el-table-column prop="name" 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
type="primary"
size="small"
icon="View"
link
@click="onClickOpenDialog(scope.row)"
>
查看
<el-button type="primary" size="small" link @click="onClickOpenDialog(scope.row)">
点击查看
</el-button>
</template>
</el-table-column>
@ -42,25 +32,27 @@
</div>
<!-- 分页 -->
<div class="footer-pagination">
<Pagination
:pageAble="tableState.pageAble"
:handle-size-change="handleSizeChange"
:handle-current-change="handleCurrentChange"
/>
<ApiDialog ref="apiDialogRef" />
</div>
</div>
<ApiDialog ref="apiDialogRef" />
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
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';
const router = useRouter();
//
const onClickReturn = () => {
router.back();
};
type apiInterface = '基础数据' | '信息发布' | '信息订阅' | '信息查询';
// api
@ -78,7 +70,7 @@ const onClickChangeApiType = async (item: apiInterface) => {
};
//
const { getTableList, tableState, searchTable, tableChangeCurrent, tableChangeSize } = useTable({
const { getTableList, tableState, searchTable } = useTable({
api: postApiPageAPI,
});
@ -97,16 +89,6 @@ const apiDialogRef = ref<InstanceType<typeof ApiDialog> | null>(null);
const onClickOpenDialog = (row: ApiManageType) => {
apiDialogRef.value?.isShowDialog(row);
};
//
const handleSizeChange = async (val: number) => {
await tableChangeSize(val);
};
//
const handleCurrentChange = async (val: number) => {
await tableChangeCurrent(val);
};
</script>
<style lang="scss" scoped>
@ -140,13 +122,19 @@ const handleCurrentChange = async (val: number) => {
justify-content: space-between;
margin-bottom: 15px;
color: #fff;
.side-icon {
width: 36px;
height: 32px;
font-weight: 400;
line-height: normal;
color: #b4b4b4;
}
.title {
font-size: 28px;
font-weight: 700;
}
.api-btn {
display: flex;
flex: 1;
align-items: center;
justify-content: space-around;
.btn {
@ -171,15 +159,14 @@ const handleCurrentChange = async (val: number) => {
}
.footer-table {
position: relative;
flex: 1;
}
.footer-pagination {
box-sizing: border-box;
display: flex;
flex-shrink: 0;
justify-content: flex-end;
flex: 1;
width: 100%;
padding-top: 20px;
padding: 20px;
margin-top: 20px;
background-color: #fff;
}
}
}

View File

@ -1,36 +1,10 @@
<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>
<el-button type="success" @click="onClickExport"></el-button>
</div>
</div>
<div class="header">船期信息表</div>
<div class="footer">
<!-- 表格 -->
<div class="footer-table">
<el-table
v-loading="tableLoading"
:data="tableState.tableData"
border
style="width: 100%; height: 100%"
>
<el-table v-loading="tableLoading" :data="tableState.tableData" border max-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" />
@ -80,11 +54,10 @@
</div>
<!-- 分页 -->
<div class="footer-pagination">
<Pagination
:pageAble="tableState.pageAble"
:handle-size-change="handleSizeChange"
:handle-current-change="handleCurrentChange"
/>
<div class="btn-export" @click="onClickExport">
<svg-icon icon="Export" className="icon"></svg-icon>
船期导出
</div>
</div>
</div>
</div>
@ -92,16 +65,13 @@
<script lang="ts" setup>
import dayjs from 'dayjs';
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
import { ElMessage, ElMessageBox } from 'element-plus';
import { onMounted, reactive, ref } from 'vue';
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';
import { useTable } from '@/hooks/useTable';
import { PageRowsResult } from '@/types';
import { BoatInfoType } from '@/types/boatInfo';
@ -116,11 +86,10 @@ const handleTableData = (data: PageRowsResult<BoatInfoType>) => {
};
//
const { getTableList, tableState, searchTable, resetTable, tableChangeCurrent, tableChangeSize } =
useTable({
api: getSailSchedulePageAPI,
dataCallBack: handleTableData,
});
const { getTableList, tableState } = useTable({
api: getSailSchedulePageAPI,
dataCallBack: handleTableData,
});
onMounted(async () => {
await getTableList();
@ -135,28 +104,6 @@ const searchTableForm = reactive({
//
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 onClickExport = () => {
ElMessageBox.confirm(`你确定要导出船期信息吗?`, '温馨提示', {
confirmButtonText: '确定',
@ -206,16 +153,6 @@ 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>
@ -227,8 +164,13 @@ const handleCurrentChange = async (val: number) => {
width: 100%;
.header {
display: flex;
justify-content: space-between;
justify-content: center;
padding: 0 16px;
font-family: 'Arial Negreta', 'Arial Normal', Arial;
font-size: 32px;
font-style: normal;
font-weight: 700;
color: #fff;
}
.footer {
position: relative;
@ -244,17 +186,30 @@ const handleCurrentChange = async (val: number) => {
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;
justify-content: center;
width: 100%;
padding-top: 20px;
margin-top: 40px;
.btn-export {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
height: 60px;
font-size: 21px;
color: #fff;
background-color: rgb(0 128 128 / 100%);
border-radius: 5px;
box-shadow: 5px 5px 5px rgb(0 0 0 / 34.9%);
.icon {
width: 32px;
height: 32px;
margin-right: 10px;
color: #80fffe;
}
}
}
}
}

View File

@ -1,7 +1,10 @@
<template>
<div class="table">
<div class="header">
<div class="title">{{ currentSubscribeNav }}</div>
<div class="title" v-if="currentSubscribeNav === '船期信息'">
<svg-icon icon="BoatList" className="side-icon"></svg-icon>
<div class="text">近期收到 <span>4</span> 条船期信息</div>
</div>
<div class="api-btn">
<div
class="btn"
@ -55,8 +58,25 @@ const onClickChangeSubscribeType = async (item: string) => {
margin-bottom: 15px;
color: #fff;
.title {
display: flex;
font-size: 28px;
font-weight: 700;
.side-icon {
width: 32px;
height: 32px;
margin-right: 10px;
}
.text {
font-family: 'Arial Negreta', 'Arial Normal', Arial;
font-size: 21px;
font-style: normal;
font-weight: 700;
color: #aaa;
span {
margin: 0 4px;
color: #fff;
}
}
}
.api-btn {
display: flex;

View File

@ -9,7 +9,7 @@
<div class="btn-text">我已经完整阅读并同意用户协议</div>
</el-checkbox>
<el-button type="primary" @click="onClickAgree"></el-button>
<div class="btn" @click="onClickAgree"></div>
</div>
</div>
</template>
@ -90,14 +90,30 @@ onMounted(async () => {
}
}
.agree-btn {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 50px;
height: 80px;
.btn-text {
color: #fff;
}
.btn {
position: absolute;
left: 50%;
width: 265px;
height: 50px;
font-size: 21px;
line-height: 50px;
color: #fff;
text-align: center;
background: inherit;
background-color: rgb(1 84 120 / 100%);
border: none;
border-radius: 5px;
box-shadow: 5px 5px 5px rgb(0 0 0 / 85.1%);
transform: translateX(-50%);
}
}
}
</style>

View File

@ -1,23 +1,22 @@
<template>
<div class="notify">
<div class="list">
<ul
<div
class="list-wrap"
v-infinite-scroll="helpListLoad"
:infinite-scroll-disabled="disabled"
:infinite-scroll-distance="100"
>
<li
<div class="list-title">分类主题</div>
<div
v-for="item in helpDocsList"
:key="item.id"
class="list-item"
@click="onClickOpenDialog(item)"
>
<div class="item-icon"></div>
<div class="item-title">{{ item.name }}</div>
<div class="item-date">{{ item.createDate }}</div>
</li>
</ul>
{{ item.serial }} {{ item.name }}
</div>
</div>
<div class="content">
<div class="title">{{ helpDocsData?.name }}</div>
@ -86,6 +85,12 @@ const onClickOpenDialog = async (row: HelpType) => {
width: 30%;
height: 500px;
overflow: auto;
overflow: hidden;
.list-title {
font-size: 21px;
font-weight: 700;
color: #f2f2f2;
}
.list-item {
box-sizing: border-box;
display: flex;
@ -93,24 +98,10 @@ const onClickOpenDialog = async (row: HelpType) => {
width: 100%;
padding: 10px 0;
overflow: hidden;
.item-icon {
width: 10px;
height: 10px;
margin-right: 10px;
background-color: #fff;
border-radius: 50%;
}
.item-title {
flex: 1;
overflow: hidden;
font-size: 16px;
text-overflow: ellipsis;
white-space: nowrap;
}
.item-date {
margin-left: 20px;
font-size: 14px;
}
font-size: 18px;
color: #80ffff;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.content {

View File

@ -1,6 +1,7 @@
<template>
<div class="table">
<div class="header">
<svg-icon icon="return" className="side-icon" @click="onClickReturn"></svg-icon>
<div class="title">帮助信息</div>
<div class="api-btn">
<div
@ -25,9 +26,17 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import AgreeText from './components/AgreeText.vue';
import HelpTable from './components/HelpTable.vue';
const router = useRouter();
//
const onClickReturn = () => {
router.back();
};
//
const helpDocsList = ref(['分类主题', '用户协议', '共享规则']);
const currentNav = ref('分类主题');
@ -54,13 +63,19 @@ const onClickChangeNav = (item: string) => {
padding: 16px 16px 0;
margin-bottom: 15px;
color: #fff;
.side-icon {
width: 36px;
height: 32px;
font-weight: 400;
line-height: normal;
color: #b4b4b4;
}
.title {
font-size: 28px;
font-weight: 700;
}
.api-btn {
display: flex;
flex: 1;
align-items: center;
justify-content: flex-end;
.btn {

View File

@ -1,32 +1,22 @@
<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="header">
<div class="title">我发布的船货信息</div>
<div class="sort">
<el-icon size="19"><CaretBottom /></el-icon>
数据按发布日期时间倒序排列
</div>
</div>
<div class="footer">
<!-- 表格 -->
<div class="footer-table">
<el-table
v-loading="tableLoading"
:data="tableState.tableData"
:data="tableData"
border
style="width: 100%; height: 100%"
max-height="100%"
v-el-table-infinite-scroll="tableDataLoad"
:infinite-scroll-disabled="disabled"
>
<el-table-column prop="enterprise.name" label="企业" align="center" width="150" />
<el-table-column prop="ship.name" label="船舶" align="center" width="150" />
@ -64,42 +54,53 @@
</div>
<!-- 分页 -->
<div class="footer-pagination">
<Pagination
:pageAble="tableState.pageAble"
:handle-size-change="handleSizeChange"
:handle-current-change="handleCurrentChange"
/>
<div class="notice">备注仅显示最近30天信息</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue';
import { computed, ref } from 'vue';
import { getPublishHistoryListAPI } from '@/api/Boat/info';
import Pagination from '@/components/Pagination/Pagination.vue';
import { useTable } from '@/hooks/useTable';
//
const { getTableList, tableState, tableChangeCurrent, tableChangeSize } = useTable({
api: getPublishHistoryListAPI,
});
onMounted(async () => {
await getTableList();
});
import { BoatInfoType } from '@/types/boatInfo';
// TODO:
//
const tableLoading = ref(false);
//
const handleSizeChange = async (val: number) => {
await tableChangeSize(val);
//
const tableData = ref<BoatInfoType[]>([]);
// -
const currentPage = ref(1);
//
const loadMoreState = ref('loading');
const disabled = computed(() => loadMoreState.value === 'finished');
//
const getTableDataList = async () => {
const { data } = await getPublishHistoryListAPI({
page: currentPage.value,
rows: 10,
});
tableLoading.value = false;
tableData.value = [...tableData.value, ...data.records];
currentPage.value++;
//
if (currentPage.value > Number(data.pages) || data.records.length < 10) {
loadMoreState.value = 'finished';
} else {
tableLoading.value = true;
loadMoreState.value = 'loading';
}
};
//
const handleCurrentChange = async (val: number) => {
await tableChangeCurrent(val);
const tableDataLoad = async () => {
await getTableDataList();
};
</script>
@ -112,9 +113,27 @@ const handleCurrentChange = async (val: number) => {
width: 100%;
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 16px 0;
margin-bottom: 16px;
border-radius: 4px;
.title {
font-family: 'Arial Normal', Arial;
font-size: 27px;
font-style: normal;
font-weight: 400;
color: #80ffff;
}
.sort {
display: flex;
align-items: flex-end;
height: 100%;
font-family: 'Arial Normal', Arial;
font-size: 15px;
font-style: normal;
font-weight: 400;
color: #aaa;
}
}
.footer {
position: relative;
@ -134,14 +153,26 @@ const handleCurrentChange = async (val: number) => {
.footer-table {
position: relative;
flex: 1;
overflow: auto;
}
.footer-pagination {
box-sizing: border-box;
display: flex;
flex-shrink: 0;
justify-content: flex-end;
width: 100%;
padding-top: 20px;
align-items: center;
justify-content: center;
.notice {
display: flex;
align-items: center;
justify-content: center;
width: 700px;
height: 40px;
overflow: hidden;
font-size: 16px;
color: #d7d7d7;
text-overflow: ellipsis;
white-space: nowrap;
background-color: rgb(127 127 127 / 100%);
border-radius: 20px;
}
}
}
}

View File

@ -1,33 +1,16 @@
<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="header">
<div class="title">我收到的船货信息</div>
<div class="sort">
<el-icon size="19"><CaretBottom /></el-icon>
数据按发布日期时间倒序排列
</div>
</div>
<div class="footer">
<!-- 表格 -->
<div class="footer-table">
<el-table
v-loading="tableLoading"
:data="tableState.tableData"
border
style="width: 100%; height: 100%"
>
<el-table v-loading="tableLoading" :data="tableState.tableData" border max-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" />
@ -64,11 +47,7 @@
</div>
<!-- 分页 -->
<div class="footer-pagination">
<Pagination
:pageAble="tableState.pageAble"
:handle-size-change="handleSizeChange"
:handle-current-change="handleCurrentChange"
/>
<div class="notice">备注仅显示最近30天信息</div>
</div>
</div>
</div>
@ -77,11 +56,10 @@
<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({
const { getTableList, tableState } = useTable({
api: getReceiveHistoryListAPI,
});
@ -91,16 +69,6 @@ onMounted(async () => {
//
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>
@ -112,9 +80,27 @@ const handleCurrentChange = async (val: number) => {
width: 100%;
.header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 16px 0;
margin-bottom: 16px;
border-radius: 4px;
.title {
font-family: 'Arial Normal', Arial;
font-size: 27px;
font-style: normal;
font-weight: 400;
color: #80ffff;
}
.sort {
display: flex;
align-items: flex-end;
height: 100%;
font-family: 'Arial Normal', Arial;
font-size: 15px;
font-style: normal;
font-weight: 400;
color: #aaa;
}
}
.footer {
position: relative;
@ -136,12 +122,23 @@ const handleCurrentChange = async (val: number) => {
flex: 1;
}
.footer-pagination {
box-sizing: border-box;
display: flex;
flex-shrink: 0;
justify-content: flex-end;
width: 100%;
padding-top: 20px;
align-items: center;
justify-content: center;
.notice {
display: flex;
align-items: center;
justify-content: center;
width: 700px;
height: 40px;
overflow: hidden;
font-size: 16px;
color: #d7d7d7;
text-overflow: ellipsis;
white-space: nowrap;
background-color: rgb(127 127 127 / 100%);
border-radius: 20px;
}
}
}
}

View File

@ -1,6 +1,7 @@
<template>
<div class="table">
<div class="header">
<svg-icon icon="return" className="side-icon" @click="onClickReturn"></svg-icon>
<div class="title">历史船货信息</div>
<div class="api-btn">
<div
@ -24,9 +25,17 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import PublishTable from './components/PublishTable.vue';
import ReceiveTable from './components/ReceiveTable.vue';
const router = useRouter();
//
const onClickReturn = () => {
router.back();
};
//
const historyNavList = ref(['我发布的', '我收到的']);
const currentHistoryNav = ref('我发布的');
@ -53,13 +62,19 @@ const onClickChangeHistoryNav = (item: string) => {
padding: 16px 16px 0;
margin-bottom: 15px;
color: #fff;
.side-icon {
width: 36px;
height: 32px;
font-weight: 400;
line-height: normal;
color: #b4b4b4;
}
.title {
font-size: 28px;
font-weight: 700;
}
.api-btn {
display: flex;
flex: 1;
align-items: center;
justify-content: flex-end;
.btn {

View File

@ -15,13 +15,13 @@ defineProps<{
<style lang="scss" scoped>
.card {
position: relative;
width: 100%;
width: 188px;
height: 88px;
margin: 20px 0;
margin: 20px 20px 20px 0;
font-size: 32px;
font-style: normal;
font-weight: 700;
border: 5px solid #d7d7d7;
border: 4px solid #d7d7d7;
border-radius: 8px;
.card-title {
position: absolute;

View File

@ -21,7 +21,7 @@ defineProps({
<style lang="scss" scoped>
.chart {
width: 100%;
width: 300px;
height: 200px;
}
</style>

View File

@ -7,46 +7,26 @@
:rules="[{ required: true, message: '请输入车架号', trigger: 'blur' }]"
>
<template #label>
<div class="search-label">车架号</div>
<div class="search-label">请输入车架号</div>
</template>
<el-input v-model="searchTableForm.vin" placeholder="请输入车架号" />
<input type="text" v-model="searchTableForm.vin" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="onClickSearch(searchTableFormRef)"
>查询</el-button
>
<div class="search-btn" @click="onClickSearch(searchTableFormRef)"></div>
</el-form-item>
</el-form>
</div>
<template v-if="!isShowVinDialog">
<div class="home-header">
<el-row :gutter="20">
<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="6" :lg="3" :xl="3">
<Card title="年度船舶艘次" :number="tableData.yearVoyages"></Card>
</el-col>
<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="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>
<Card title="累计船舶艘次" :number="tableData.totalVoyages"></Card>
<Card title="年度船舶艘次" :number="tableData.yearVoyages"></Card>
<Card title="本港船舶艘次" :number="tableData.totalPortVoyages"></Card>
<Card title="本港年度艘次" :number="tableData.yearPortVoyages"></Card>
<Card title="累计货物数量" :number="tableData.totalCargos"></Card>
<Card title="年度货物数量" :number="tableData.yearCargos"></Card>
<Card title="本港货物累计" :number="tableData.totalPortCargos"></Card>
<Card title="本港年度货物" :number="tableData.yearPortCargos"></Card>
</div>
<div class="home-content">
<el-row :gutter="32">
@ -169,8 +149,9 @@ const outImportVoyages = ref({
},
},
legend: {
bottom: '2%',
left: 'center',
orient: 'vertical',
left: 'left',
top: 'middle',
},
series: [
{
@ -208,8 +189,9 @@ const outExportVoyages = ref({
},
},
legend: {
bottom: '2%',
left: 'center',
orient: 'vertical',
left: 'left',
top: 'middle',
},
series: [
{
@ -247,8 +229,9 @@ const inTotalVoyages = ref({
},
},
legend: {
bottom: '2%',
left: 'center',
orient: 'vertical',
left: 'left',
top: 'middle',
},
series: [
{
@ -286,8 +269,9 @@ const inYearVoyages = ref({
},
},
legend: {
bottom: '2%',
left: 'center',
orient: 'vertical',
left: 'left',
top: 'middle',
},
series: [
{
@ -325,8 +309,9 @@ const outImportCargos = ref({
},
},
legend: {
bottom: '2%',
left: 'center',
orient: 'vertical',
left: 'left',
top: 'middle',
},
series: [
{
@ -364,8 +349,9 @@ const outExportCargos = ref({
},
},
legend: {
bottom: '2%',
left: 'center',
orient: 'vertical',
left: 'left',
top: 'middle',
},
series: [
{
@ -403,8 +389,9 @@ const inTotalCargos = ref({
},
},
legend: {
bottom: '2%',
left: 'center',
orient: 'vertical',
left: 'left',
top: 'middle',
},
series: [
{
@ -442,8 +429,9 @@ const inYearCargos = ref({
},
},
legend: {
bottom: '2%',
left: 'center',
orient: 'vertical',
left: 'left',
top: 'middle',
},
series: [
{
@ -506,6 +494,9 @@ onMounted(async () => {
<style lang="scss" scoped>
.home {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
.home-search {
@ -514,16 +505,52 @@ onMounted(async () => {
justify-content: center;
padding: 16px 16px 0;
margin-bottom: 16px;
border-radius: 4px;
box-shadow: 0 0 12px rgb(0 0 0 / 5%);
.search-label {
font-size: 24px;
font-style: normal;
font-weight: 700;
line-height: 40px;
color: #f2f2f2;
}
input {
width: 245px;
height: 30px;
padding: 3px 2px;
font-family: 'Arial Negreta', 'Arial Normal', Arial;
font-size: 18px;
font-style: normal;
font-weight: 700;
color: #000;
text-transform: none;
letter-spacing: normal;
vertical-align: none;
background-color: #fff;
border-color: transparent;
border-radius: 21px;
}
.search-btn {
display: flex;
align-items: center;
justify-content: center;
width: 96px;
height: 40px;
font-size: 15px;
color: #fff;
background: inherit;
background-color: rgb(2 125 180 / 100%);
border: none;
border-width: 0;
border-radius: 5px;
box-shadow: none;
}
}
.home-header {
display: flex;
justify-content: space-between;
width: 100%;
}
.home-content {
flex: 1;
width: 100%;
.charts {
width: 100%;
@ -539,7 +566,7 @@ onMounted(async () => {
display: flex;
align-items: center;
justify-content: center;
width: 60%;
width: 900px;
height: 40px;
overflow: hidden;
font-size: 16px;

View File

@ -26,166 +26,177 @@
<div class="form-title-right" @click="onClickChangePage(1)"></div>
</div>
<el-form-item prop="username">
<el-input
placeholder="请输入登录账号(手机账号)"
autocomplete="on"
style="position: relative"
v-model="loginForm.username"
<input
type="text"
>
<template #prefix>
<svg-icon icon="user" />
</template>
</el-input>
placeholder="请填写登录账号(手机账号)"
v-model="loginForm.username"
/>
</el-form-item>
<el-form-item prop="password">
<el-input
placeholder="请输入密码"
autocomplete="on"
v-model="loginForm.password"
show-password
>
<template #prefix>
<svg-icon icon="password" />
</template>
</el-input>
<input type="password" placeholder="请填写密码" v-model="loginForm.password" />
</el-form-item>
<div class="login-btn">
<el-button
type="success"
style="width: 100%; height: 100%"
:loading="loading"
@click="onClickSubmit(loginFormRef)"
>
登录
</el-button>
</div>
<el-form-item prop="code">
<input
type="code"
placeholder="请填写验证码"
v-model="loginForm.code"
class="code-input"
/>
<div class="code-btn">发送短信</div>
</el-form-item>
<div class="login-btn" @click="onClickSubmit(loginFormRef)"></div>
</el-form>
</div>
</div>
<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 class="register-title">
<svg-icon icon="return" className="side-icon" @click="onClickChangePage(0)"></svg-icon>
<div class="text">入驻企业登记信息</div>
</div>
<div class="register-content">
<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>
<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
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="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="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 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="licensePhoto">
<el-input v-model="ruleForm.licensePhoto" disabled placeholder="请上传营业执照">
<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.licensePhoto" :file-no="ruleForm.code" />
<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>
<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>
</el-form>
</div>
</div>
</div>
</div>
<div class="login-text" v-if="currentPage === 0">
武汉理工大学 & 上海瑞通智慧科技有限公司 提供技术支持
</div>
</div>
</template>
@ -223,6 +234,7 @@ const loginRules = reactive<FormRules>({
const loginForm = reactive({
username: '', //
password: '', //
code: '',
});
//
@ -366,6 +378,7 @@ const onClickSubmitRegister = (formEl: FormInstance | undefined) => {
<style lang="scss" scoped>
.login {
position: relative;
width: 100%;
height: 100%;
background: linear-gradient(180deg, rgb(51 51 51 / 100%) 0%, rgb(242 242 242 / 100%) 100%);
@ -474,26 +487,84 @@ const onClickSubmitRegister = (formEl: FormInstance | undefined) => {
color: rgb(217 0 27);
}
}
:deep(.el-form-item) {
color: #454545;
background: rgb(0 0 0 / 10%);
border: 1px solid rgb(255 255 255 / 10%);
border-radius: 5px;
}
:deep(input) {
height: 47px;
padding: 12px 5px 12px 15px;
border: 0;
border-radius: 0;
width: 300px;
height: 60px;
padding: 3px 2px 3px 10px;
font-size: 18px;
font-style: normal;
font-weight: 400;
color: #aaa;
text-align: left;
text-decoration: none;
text-transform: none;
letter-spacing: normal;
vertical-align: none;
background-color: transparent;
border-color: transparent;
border-bottom: 1px solid rgb(121 121 121 / 100%);
}
:deep(.el-form-item__content) {
display: flex;
align-items: center;
justify-content: space-between;
width: 310px;
}
.code-input {
width: 135px;
height: 60px;
padding: 3px 2px 3px 10px;
font-size: 18px;
font-style: normal;
font-weight: 400;
color: #aaa;
text-align: left;
text-decoration: none;
text-transform: none;
letter-spacing: normal;
vertical-align: none;
background-color: transparent;
border-color: transparent;
border-bottom: 1px solid rgb(121 121 121 / 100%);
}
.code-btn {
display: flex;
align-items: center;
justify-content: center;
width: 130px;
height: 50px;
color: #fff;
background: inherit;
background-color: rgb(22 155 213 / 100%);
border: none;
border-width: 0;
border-radius: 5px;
box-shadow: none;
}
.login-btn {
display: flex;
align-items: center;
justify-content: space-between;
justify-content: center;
width: 100%;
height: 47px;
margin: 20px 0;
height: 50px;
margin: 40px 0;
font-size: 21px;
font-style: normal;
font-weight: 700;
color: #fff;
background: linear-gradient(
180deg,
rgb(202 249 130 / 100%) 0%,
rgb(112 182 3 / 100%) 54%,
rgb(75 121 2 / 100%) 100%
);
border: none;
border-radius: 5px;
box-shadow: 0 3px 5px rgb(0 0 0 / 19.2%);
}
.login-btn:hover {
background: rgb(0 191 191 / 100%);
box-shadow: 0 3px 5px rgb(0 0 0 / 19.2%);
}
}
}
@ -501,70 +572,119 @@ const onClickSubmitRegister = (formEl: FormInstance | undefined) => {
box-sizing: border-box;
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 {
.register-title {
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;
height: 100px;
padding: 0 0 20px;
.text {
display: flex;
flex: 1;
align-items: flex-end;
justify-content: center;
font-size: 39px;
font-style: normal;
font-weight: 700;
color: #fff;
}
.side-icon {
width: 36px;
height: 32px;
font-weight: 400;
line-height: normal;
color: #b4b4b4;
}
}
.register-content {
box-sizing: border-box;
width: 100%;
height: calc(100% - 120px);
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;
padding: 40px;
.form-left {
width: 49%;
.form-wrap {
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: 100%;
width: 49%;
padding: 20px 30px;
border: 1px dashed #ddd;
border-radius: 8px;
@ -578,30 +698,21 @@ const onClickSubmitRegister = (formEl: FormInstance | undefined) => {
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; /* 设置背景覆盖边框 */
}
}
}
}
}
}
.login-text {
position: absolute;
bottom: 40px;
left: 50%;
width: 387px;
height: 16px;
font-size: 15px;
color: #aaa;
border-width: 0;
transform: translateX(-50%);
}
}
</style>

View File

@ -1,6 +1,9 @@
<template>
<div class="notify">
<div class="title">平台公告</div>
<div class="title">
<svg-icon icon="return" className="side-icon" @click="onClickReturn"></svg-icon>
<div class="text">平台公告</div>
</div>
<div class="list">
<ul
class="list-wrap"
@ -34,9 +37,17 @@
<script lang="ts" setup>
import { computed, ref } from 'vue';
import { useRouter } from 'vue-router';
import { noticeGetAPI, noticePageAPI } from '@/api/Notice';
import { NoticeType } from '@/types/notice';
const router = useRouter();
//
const onClickReturn = () => {
router.back();
};
const noticeList = ref<NoticeType[]>([]);
const noticeViewData = ref<NoticeType>();
@ -86,12 +97,25 @@ const onClickOpenDialog = async (row: NoticeType) => {
color: #fff;
.title {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
margin-bottom: 15px;
margin-bottom: 30px;
font-size: 30px;
font-weight: 700;
.text {
display: flex;
flex: 1;
align-items: flex-end;
justify-content: center;
font-size: 30px;
font-weight: 700;
color: #fff;
}
.side-icon {
width: 36px;
height: 32px;
font-weight: 400;
line-height: normal;
color: #b4b4b4;
}
}
.list {
box-sizing: border-box;
@ -101,7 +125,7 @@ const onClickOpenDialog = async (row: NoticeType) => {
height: calc(100% - 100px);
.list-wrap {
box-sizing: border-box;
width: 30%;
width: 320px;
height: 500px;
overflow: auto;
.list-item {
@ -136,7 +160,7 @@ const onClickOpenDialog = async (row: NoticeType) => {
box-sizing: border-box;
flex: 1;
height: 100%;
margin-left: 20px;
margin-left: 100px;
font-size: 21px;
font-style: normal;
font-weight: 700;

View File

@ -151,7 +151,7 @@ const employeeListLoad = async () => {
height: 100%;
.list-left {
box-sizing: border-box;
width: 30%;
width: 266px;
.left-title {
font-size: 20px;
font-weight: 700;
@ -193,9 +193,9 @@ const employeeListLoad = async () => {
}
.list-right {
box-sizing: border-box;
flex: 1;
width: 800px;
height: 100%;
margin-left: 20px;
margin-left: 40px;
.right-title {
font-size: 20px;
font-weight: 700;
@ -206,7 +206,7 @@ const employeeListLoad = async () => {
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%;
width: 800px;
height: 400px;
padding: 40px;
color: #333;

View File

@ -1,30 +1,9 @@
<template>
<div class="table">
<div class="header">
<el-form :inline="true" :model="searchTableForm" ref="tableFormRef">
<el-form-item prop="name">
<el-input v-model="searchTableForm.name" 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>
<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
style="width: 100%; height: 100%"
>
<el-table v-loading="tableLoading" :data="tableState.tableData" border max-height="460">
<el-table-column prop="name" label="姓名" align="center" width="180" />
<el-table-column prop="dept" label="部门" align="center" width="180" />
<el-table-column prop="job" label="职位" align="center" width="180" />
@ -76,11 +55,8 @@
</div>
<!-- 分页 -->
<div class="footer-pagination">
<Pagination
:pageAble="tableState.pageAble"
:handle-size-change="handleSizeChange"
:handle-current-change="handleCurrentChange"
/>
<el-button type="primary" icon="Plus" @click="onClickOpenDialog('新增')"> </el-button>
<div class="tips">操作提示单击用户记录打开编辑窗口可修改发编辑用户信息</div>
</div>
</div>
<EmployeeDialog ref="employeeDialogRef" />
@ -88,60 +64,30 @@
</template>
<script lang="ts" setup>
import { ElMessage, ElMessageBox, FormInstance } from 'element-plus';
import { onMounted, reactive, ref } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { onMounted, ref } from 'vue';
import {
postEmployeeAddAPI,
postEmployeeDeleteAPI,
postEmployeePageAPI,
postEmployeeSaveAPI,
} from '@/api/Enterprise/employee';
import Pagination from '@/components/Pagination/Pagination.vue';
import { useTable } from '@/hooks/useTable';
import { EmployeeType } from '@/types/Enterprise';
import EmployeeDialog from './EmployeeDialog.vue';
//
const { getTableList, tableState, searchTable, resetTable, tableChangeCurrent, tableChangeSize } =
useTable({
api: postEmployeePageAPI,
});
const { getTableList, tableState } = useTable({
api: postEmployeePageAPI,
});
onMounted(async () => {
await getTableList();
});
//
const searchTableForm = reactive({
name: '',
});
//
const tableLoading = ref(false);
//
const tableFormRef = ref<FormInstance>();
//
const onClickSearch = async () => {
tableLoading.value = true;
console.log(searchTableForm);
//
tableState.value.searchParam = searchTableForm;
//
await searchTable();
tableLoading.value = false;
};
//
const onClickResetForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await resetTable();
formEl.resetFields();
};
// /
const employeeDialogRef = ref<InstanceType<typeof EmployeeDialog> | null>(null);
const onClickOpenDialog = (title: string, row: Partial<EmployeeType> = {}) => {
@ -176,16 +122,6 @@ const onClickDel = (row: EmployeeType) => {
console.log('用户点击了取消');
});
};
//
const handleSizeChange = async (val: number) => {
await tableChangeSize(val);
};
//
const handleCurrentChange = async (val: number) => {
await tableChangeCurrent(val);
};
</script>
<style lang="scss" scoped>
@ -208,17 +144,23 @@ const handleCurrentChange = async (val: number) => {
flex-direction: column;
padding: 16px;
overflow: hidden;
.footer-table {
position: relative;
flex: 1;
}
.footer-pagination {
box-sizing: border-box;
display: flex;
flex-shrink: 0;
justify-content: flex-end;
align-items: center;
width: 100%;
padding-top: 20px;
.el-button {
width: 140px;
height: 50px;
}
.tips {
margin-left: 20px;
font-family: 'Arial Normal', Arial;
font-size: 15px;
font-style: normal;
font-weight: 400;
color: #aaa;
}
}
}
}

View File

@ -66,7 +66,7 @@ onMounted(async () => {
width: 100%;
height: 100%;
.list-wrap {
width: 50%;
width: 30%;
height: 100%;
.title {
font-size: 26px;

View File

@ -1,6 +1,7 @@
<template>
<div class="table">
<div class="header">
<svg-icon icon="return" className="side-icon" @click="onClickReturn"></svg-icon>
<div class="title">用户设置</div>
<div class="api-btn">
<div
@ -25,10 +26,18 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import employeeRole from './components/EmployeeRole.vue';
import EmployeeTable from './components/EmployeeTable.vue';
import Wharf from './components/Wharf.vue';
const router = useRouter();
//
const onClickReturn = () => {
router.back();
};
//
const helpDocsList = ref(['码头信息', '用户管理', '权限管理']);
const currentNav = ref('码头信息');
@ -55,13 +64,19 @@ const onClickChangeNav = (item: string) => {
padding: 16px 16px 0;
margin-bottom: 15px;
color: #fff;
.side-icon {
width: 36px;
height: 32px;
font-weight: 400;
line-height: normal;
color: #b4b4b4;
}
.title {
font-size: 28px;
font-weight: 700;
}
.api-btn {
display: flex;
flex: 1;
align-items: center;
justify-content: flex-end;
.btn {

View File

@ -1,51 +1,12 @@
<template>
<div class="table">
<!-- <div class="header">
<el-form :inline="true" :model="searchTableForm" ref="tableFormRef">
<el-form-item>
<RemoteSelect
v-model:value="searchTableForm.enterpriseId"
placeholder="请选择订阅企业"
style="width: 150px"
:api="postEnterpriseListAPI"
/>
</el-form-item>
<el-form-item>
<RemoteSelect
v-model:value="searchTableForm.portId"
placeholder="请选择订阅港口"
style="width: 150px"
:api="postPortListAPI"
/>
</el-form-item>
<el-form-item>
<RemoteSelect
v-model:value="searchTableForm.wharfId"
placeholder="请选择订阅码头"
style="width: 150px"
:api="postWharfListAPI"
/>
</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="header">
<div class="title">我的订阅清单</div>
</div>
<div class="footer">
<div class="footer-util">
<el-button type="primary" icon="Plus" @click="onClickOpenDialog('新增')">
新增订阅
</el-button>
</div>
<!-- 表格 -->
<div class="footer-table">
<el-table
v-loading="tableLoading"
:data="tableState.tableData"
border
style="width: 100%; height: 100%"
>
<el-table v-loading="tableLoading" :data="tableState.tableData" border max-height="100%">
<el-table-column prop="enterprise.name" label="订阅企业" align="center" width="150" />
<el-table-column prop="port.name" label="订阅港口" align="center" width="150" />
<el-table-column prop="wharf.name" label="订阅码头" align="center" width="150" />
@ -107,11 +68,10 @@
</div>
<!-- 分页 -->
<div class="footer-pagination">
<Pagination
:pageAble="tableState.pageAble"
:handle-size-change="handleSizeChange"
:handle-current-change="handleCurrentChange"
/>
<div class="btn-add" @click="onClickOpenDialog('新增')">
<svg-icon icon="Add" className="icon"></svg-icon>
新增订阅
</div>
</div>
</div>
<PublishDialog ref="publishDialogRef" />
@ -153,7 +113,6 @@ import {
subscriptionDeleteAPI,
subscriptionSaveAPI,
} from '@/api/Subscription';
import Pagination from '@/components/Pagination/Pagination.vue';
import { useTable } from '@/hooks/useTable';
import { PageRowsResult } from '@/types';
import { SubscriptionType } from '@/types/subscription';
@ -170,7 +129,7 @@ const handleTableData = (data: PageRowsResult<SubscriptionType>) => {
};
//
const { getTableList, tableState, tableChangeCurrent, tableChangeSize } = useTable({
const { getTableList, tableState } = useTable({
api: publishPageAPI,
dataCallBack: handleTableData,
});
@ -251,16 +210,6 @@ const onClickDel = (row: SubscriptionType) => {
console.log('用户点击了取消');
});
};
//
const handleSizeChange = async (val: number) => {
await tableChangeSize(val);
};
//
const handleCurrentChange = async (val: number) => {
await tableChangeCurrent(val);
};
</script>
<style lang="scss" scoped>
@ -271,10 +220,15 @@ const handleCurrentChange = async (val: number) => {
flex-direction: column;
width: 100%;
.header {
display: flex;
padding: 16px 16px 0;
margin-bottom: 16px;
border-radius: 4px;
.title {
font-family: 'Arial Normal', Arial;
font-size: 27px;
font-style: normal;
font-weight: 400;
color: #80ffff;
}
}
.footer {
position: relative;
@ -298,10 +252,27 @@ const handleCurrentChange = async (val: number) => {
.footer-pagination {
box-sizing: border-box;
display: flex;
flex-shrink: 0;
justify-content: flex-end;
justify-content: center;
width: 100%;
padding-top: 20px;
margin-top: 40px;
.btn-add {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
height: 60px;
font-size: 21px;
color: #fff;
background-color: rgb(163 0 20 / 100%);
border-radius: 5px;
box-shadow: 5px 5px 5px rgb(0 0 0 / 85.1%);
.icon {
width: 32px;
height: 32px;
margin-right: 10px;
color: #80fffe;
}
}
}
}
}

View File

@ -1,37 +1,8 @@
<template>
<div class="table">
<!-- <div class="header">
<el-form :inline="true" :model="searchTableForm" ref="tableFormRef">
<el-form-item>
<RemoteSelect
v-model:value="searchTableForm.enterpriseId"
placeholder="请选择订阅企业"
style="width: 150px"
:api="postEnterpriseListAPI"
/>
</el-form-item>
<el-form-item>
<RemoteSelect
v-model:value="searchTableForm.portId"
placeholder="请选择订阅港口"
style="width: 150px"
:api="postPortListAPI"
/>
</el-form-item>
<el-form-item>
<RemoteSelect
v-model:value="searchTableForm.wharfId"
placeholder="请选择订阅码头"
style="width: 150px"
:api="postWharfListAPI"
/>
</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="header">
<div class="title">我收到的订阅清单</div>
</div>
<div class="footer">
<!-- 表格 -->
<div class="footer-table">
@ -40,7 +11,7 @@
:data="tableState.tableData"
border
stripe
style="width: 100%; height: 100%"
max-height="100%"
>
<el-table-column prop="enterprise.name" label="订阅企业" align="center" width="150" />
<el-table-column prop="port.name" label="订阅港口" align="center" width="150" />
@ -62,13 +33,6 @@
</el-table>
</div>
<!-- 分页 -->
<div class="footer-pagination">
<Pagination
:pageAble="tableState.pageAble"
:handle-size-change="handleSizeChange"
:handle-current-change="handleCurrentChange"
/>
</div>
</div>
</div>
</template>
@ -77,7 +41,6 @@
import dayjs from 'dayjs';
import { onMounted, ref } from 'vue';
import { receivePageAPI } from '@/api/Subscription';
import Pagination from '@/components/Pagination/Pagination.vue';
import { useTable } from '@/hooks/useTable';
import { PageRowsResult } from '@/types';
import { SubscriptionType } from '@/types/subscription';
@ -93,7 +56,7 @@ const handleTableData = (data: PageRowsResult<SubscriptionType>) => {
};
//
const { getTableList, tableState, tableChangeCurrent, tableChangeSize } = useTable({
const { getTableList, tableState } = useTable({
api: receivePageAPI,
dataCallBack: handleTableData,
});
@ -106,16 +69,6 @@ onMounted(async () => {
//
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>
@ -126,10 +79,15 @@ const handleCurrentChange = async (val: number) => {
flex-direction: column;
width: 100%;
.header {
display: flex;
padding: 16px 16px 0;
margin-bottom: 16px;
border-radius: 4px;
.title {
font-family: 'Arial Normal', Arial;
font-size: 27px;
font-style: normal;
font-weight: 400;
color: #80ffff;
}
}
.footer {
position: relative;

View File

@ -1,7 +1,8 @@
<template>
<div class="table">
<div class="header">
<div class="title">{{ currentSubscribeNav }}清单</div>
<svg-icon icon="return" className="side-icon" @click="onClickReturn"></svg-icon>
<div class="title">船货信息订阅</div>
<div class="api-btn">
<div
class="btn"
@ -24,9 +25,17 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import PublishTable from './components/PublishTable.vue';
import ReceiveTable from './components/ReceiveTable.vue';
const router = useRouter();
//
const onClickReturn = () => {
router.back();
};
//
const subscribeNavList = ref(['我的订阅', '收到订阅']);
const currentSubscribeNav = ref('我的订阅');
@ -53,13 +62,19 @@ const onClickChangeSubscribeType = async (item: string) => {
padding: 16px 16px 0;
margin-bottom: 15px;
color: #fff;
.side-icon {
width: 36px;
height: 32px;
font-weight: 400;
line-height: normal;
color: #b4b4b4;
}
.title {
font-size: 28px;
font-weight: 700;
}
.api-btn {
display: flex;
flex: 1;
align-items: center;
justify-content: flex-end;
.btn {

View File

@ -0,0 +1,195 @@
<template>
<div class="user">
<div class="header">
<svg-icon icon="return" className="side-icon" @click="onClickReturn"></svg-icon>
</div>
<div class="content">
<div class="title">我的资料</div>
<div class="password" @click="dialogVisible = true">修改密码</div>
</div>
<div class="logout" @click="onClickLogout">退</div>
</div>
<el-dialog v-model="dialogVisible" title="修改密码" width="500px" draggable>
<el-form ref="ruleFormRef" :model="passwordForm" :rules="passwordFormRules" label-width="auto">
<el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="passwordForm.oldPassword" placeholder="请输入旧密码" show-password />
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="passwordForm.newPassword" placeholder="请输入新密码" show-password />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input
v-model="passwordForm.confirmPassword"
placeholder="请再次输入新密码"
show-password
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button 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 { useRouter } from 'vue-router';
import { postUserPasswordAPI } from '@/api/System/user';
import { useUserStore } from '@/store/modules/user';
const router = useRouter();
//
const onClickReturn = () => {
router.back();
};
//
const dialogVisible = ref(false);
//
const passwordForm = reactive({
oldPassword: '',
newPassword: '',
confirmPassword: '',
});
const ruleFormRef = ref<FormInstance>();
const validatePass = (_: any, value: any, callback: any) => {
if (value === '') {
callback(new Error('请输入新密码'));
} else {
if (passwordForm.oldPassword === passwordForm.newPassword) {
callback(new Error('新密码不能与旧密码相同'));
} else {
callback();
}
}
};
const validatePass2 = (_: any, value: any, callback: any) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== passwordForm.newPassword) {
callback(new Error('两次密码不一致!'));
} else {
callback();
}
};
const passwordFormRules = reactive<FormRules>({
oldPassword: [{ required: true, message: '请输入旧密码', trigger: 'blur' }],
newPassword: [{ required: true, validator: validatePass, trigger: 'blur' }],
confirmPassword: [{ required: true, validator: validatePass2, trigger: 'blur' }],
});
//
const onClickConfirm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
try {
await postUserPasswordAPI({
newPassword: passwordForm.newPassword,
oldPassword: passwordForm.oldPassword,
});
userStore.logout();
ElMessage({
message: `修改密码成功,请重新登录`,
type: 'success',
});
} finally {
ruleFormRef.value?.resetFields();
}
});
};
// store
const userStore = useUserStore();
const onClickLogout = async () => {
ElMessageBox.confirm('您是否确认退出登录?', '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
userStore.logout(true);
ElMessage({
type: 'success',
message: '退出登录成功!',
});
});
};
</script>
<style lang="scss" scoped>
.user {
position: relative;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
.header {
box-sizing: border-box;
padding: 16px 16px 0;
margin-bottom: 15px;
color: #fff;
.side-icon {
width: 36px;
height: 32px;
font-weight: 400;
line-height: normal;
color: #b4b4b4;
}
}
.content {
box-sizing: border-box;
width: 100%;
padding: 40px;
.title {
width: 128px;
height: 37px;
font-family: 'Arial Negreta', 'Arial Normal', Arial;
font-size: 32px;
font-style: normal;
font-weight: 700;
color: #fff;
}
.password {
width: 140px;
height: 53px;
margin-top: 20px;
font-size: 21px;
line-height: 53px;
color: #fff;
text-align: center;
background-color: rgb(1 84 120 / 100%);
border: none;
border-radius: 5px;
box-shadow: 5px 5px 5px rgb(0 0 0 / 85.1%);
}
}
.logout {
position: absolute;
right: 20px;
bottom: 20px;
width: 140px;
height: 53px;
font-size: 21px;
line-height: 53px;
color: #fff;
text-align: center;
background-color: rgb(163 0 20 / 100%);
border: none;
border-radius: 5px;
box-shadow: 5px 5px 5px rgb(0 0 0 / 85.1%);
}
}
</style>