修改 数据填报,打包报错修改,框架迁移遗留问题;修改401/404显示逻辑;去除页面中的moment改用dayjs;

This commit is contained in:
扈兆增 2026-06-26 18:00:09 +08:00
parent 1b4f036c6e
commit 925fbf0d04
60 changed files with 1269 additions and 2147 deletions

View File

@ -24,6 +24,7 @@ module.exports = {
}, },
plugins: ['vue', '@typescript-eslint'], plugins: ['vue', '@typescript-eslint'],
rules: { rules: {
"no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
'vue/multi-word-component-names': 'off', 'vue/multi-word-component-names': 'off',
'@typescript-eslint/no-empty-function': 'off', // 关闭空方法检查 '@typescript-eslint/no-empty-function': 'off', // 关闭空方法检查
'@typescript-eslint/no-explicit-any': 'off', // 关闭any类型的警告 '@typescript-eslint/no-explicit-any': 'off', // 关闭any类型的警告

View File

@ -0,0 +1,9 @@
import request from '@/utils/request';
//修改密码
export function updatePassword(params:any) {
return request({
url: '/user/updatePassword',
method: 'post',
data: params
});
}

View File

@ -1,62 +0,0 @@
import request from '@/utils/request';
/**
* Kendo
* @param params
* @param sortConfig
*/
export function getKendoList(params: any, sortConfig?: any[]) {
return request({
url: '/dec-lygk-base-server/base/vmsstbprpt/GetKendoList',
method: 'post',
data: {
filters: params,
sorts: sortConfig || []
}
});
}
/**
* Kendo
* @param params
* @param sortConfig
*/
export function getKendoListCust(params: any, sortConfig?: any[]) {
return request({
url: '/dec-lygk-base-server/base/vmsstbprpt/GetKendoListCust',
method: 'post',
data: {
filters: params,
sorts: sortConfig || []
}
});
}
/**
* other
* @param filters
* @param sorts
* @param needTotal
* @param fields
* @param defaultSort
*/
export function getIntroduce(
filters: any[],
sorts?: any[],
needTotal?: boolean,
fields?: string[],
defaultSort?: any
) {
return request({
url: '/dec-lygk-base-server/base/introduce/getIntroduce',
method: 'post',
data: {
logic: 'and',
filters: filters,
sorts: sorts || [],
needTotal: needTotal || false,
fields: fields || [],
defaultSort: defaultSort
}
});
}

View File

@ -1,26 +0,0 @@
import request from '@/utils/request';
// 获取所有沿程配置数据
export function getAllConfigTree(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/msalongb/GetKendoList',
method: 'post',
data: data
});
}
// 保存沿程配置
export function saveBaseWbsb(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/wbsb/addOrUpdate',
method: 'post',
data: data
});
}
// 删除沿程配置
export function deleteBaseWbsb(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/wbsb/delete',
method: 'get',
params: data
});
}

View File

@ -1,34 +0,0 @@
import request from '@/utils/request';
// 获取所有地图 图层树
export function getAllMapLayerTree(data: any) {
return request({
url: '/api/wmp-sys-server/mapLayer/getAllMapLayerTree',
method: 'post',
data: data
});
}
// 保存地图 图层
export function saveMapLayer(data: any) {
return request({
url: '/api/wmp-sys-server/mapLayer/save',
method: 'post',
data: data
});
}
// 删除地图 图层
export function deleteMapLayer(data: any) {
return request({
url: '/api/wmp-sys-server/mapLayer/delete',
method: 'post',
data: data
});
}
// 获取所有地图 图层树
export function getAllMapLayerParentIdTree(data: any) {
return request({
url: '/api/wmp-sys-server/mapLayer/getAllMapLayerTree',
method: 'post',
data: data
});
}

View File

@ -1,35 +0,0 @@
import request from '@/utils/request';
// 获取所有地图 图例树
export function getAllMapLegendTree(data: any) {
return request({
url: '/api/wmp-sys-server/mapLegend/GetKendoList',
method: 'post',
data: data
});
}
// 保存地图 图例
export function saveMapLegend(data: any) {
return request({
url: '/api/wmp-sys-server/mapLegend/save',
method: 'post',
data: data
});
}
// 删除地图 图例
export function deleteMapLegend(data: any) {
return request({
url: '/api/wmp-sys-server/mapLegend/delete',
method: 'post',
data: data
});
}
// 获取所有地图 图例树
export function getAllMapLegendParentIdTree(data: any) {
return request({
url: '/api/wmp-sys-server/mapLegend/getAllMapLegendTree',
method: 'get',
params: data
});
}

View File

@ -1,26 +0,0 @@
import request from '@/utils/request';
// 获取所有倾斜摄影
export function getAllTiltPhotoTree(data: any) {
return request({
url: '/api/wmp-sys-server/sys/oblique/GetKendoListCust',
method: 'post',
data: data
});
}
// 保存倾斜摄影
export function saveTiltPhoto(data: any) {
return request({
url: '/api/wmp-sys-server/sys/oblique/addOrUpdate',
method: 'post',
data: data
});
}
// 删除倾斜摄影
export function deleteTiltPhoto(data: any) {
return request({
url: '/api/wmp-sys-server/sys/oblique/delete',
method: 'get',
params: data
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

View File

@ -1,18 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onBeforeUnmount } from "vue"; import { ref } from 'vue';
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from 'vue-router';
import { Modal } from "ant-design-vue"; import { Modal } from 'ant-design-vue';
import { UserOutlined, LogoutOutlined } from "@ant-design/icons-vue"; import { UserOutlined, LogoutOutlined } from '@ant-design/icons-vue';
// //
import { useI18n } from "vue-i18n"; import { useI18n } from 'vue-i18n';
const { t } = useI18n(); const { t } = useI18n();
// import LangSelect from '@/components/LangSelect/index.vue'; // import LangSelect from '@/components/LangSelect/index.vue';
import Sidebar from "./Sidebar/index.vue"; import Sidebar from './Sidebar/index.vue';
import ChangePassword from './changePassword.vue';
import { useTagsViewStore } from "@/store/modules/tagsView"; import { useTagsViewStore } from '@/store/modules/tagsView';
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from '@/store/modules/user';
// const url = import.meta.env.VITE_APP_BASE_API;
const tagsViewStore = useTagsViewStore(); const tagsViewStore = useTagsViewStore();
const userStore = useUserStore(); const userStore = useUserStore();
@ -21,10 +20,10 @@ const route = useRoute();
const router = useRouter(); const router = useRouter();
function logout() { function logout() {
Modal.confirm({ Modal.confirm({
title: "提示?", title: '提示?',
content: "确定注销并退出系统吗?", content: '确定注销并退出系统吗?',
okText: "确定", okText: '确定',
type: "warning", type: 'warning',
onOk: async () => { onOk: async () => {
userStore userStore
.logout() .logout()
@ -34,14 +33,13 @@ function logout() {
.then(() => { .then(() => {
router.push(`/login`); router.push(`/login`);
}); });
}, }
}); });
} }
const changePasswordVisible = ref(false);
function changePassword() { function changePassword() {
router.push("/changePassword"); changePasswordVisible.value = true;
} }
onMounted(() => {});
onBeforeUnmount(() => {});
</script> </script>
<template> <template>
@ -52,8 +50,9 @@ onBeforeUnmount(() => {});
href="/" href="/"
class="h-[50px] min-w-[350px] flex items-center justify-center text-white" class="h-[50px] min-w-[350px] flex items-center justify-center text-white"
> >
<!-- <h1 class="text-blank font-bold text-[16px]">{{ t("login.title") }}</h1> --> <h1 class="text-blank font-bold text-[16px]">
<h1 class="text-blank font-bold text-[16px]">{{ t("login.titleSjtb") }}</h1> {{ t('login.titleSjtb') }}
</h1>
</a> </a>
</transition> </transition>
<Sidebar /> <Sidebar />
@ -82,11 +81,12 @@ onBeforeUnmount(() => {});
</template> </template>
</a-dropdown> </a-dropdown>
</a-layout-header> </a-layout-header>
<ChangePassword v-model:open="changePasswordVisible" />
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
@use "@/styles/variables.module.scss" as *; @use '@/styles/variables.module.scss' as *;
.navbar { .navbar {
width: 100%; width: 100%;
position: relative; position: relative;

View File

@ -0,0 +1,394 @@
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { useRouter } from 'vue-router';
import { message } from 'ant-design-vue';
import type { FormInstance } from 'ant-design-vue';
import { useUserStore } from '@/store/modules/user';
import { encrypt } from '@/utils/rsaEncrypt';
import { updatePassword } from '@/api/changePassWord';
const router = useRouter();
const userStore = useUserStore();
const props = defineProps<{ open: boolean }>();
const emit = defineEmits<{ 'update:open': [value: boolean] }>();
const closeModal = () => emit('update:open', false);
//
const formRef = ref<FormInstance>();
//
const submitting = ref(false);
//
interface ChangePasswordForm {
oldPassword: string;
newPassword: string;
confirmPassword: string;
}
const formState = reactive<ChangePasswordForm>({
oldPassword: '',
newPassword: '',
confirmPassword: ''
});
// ==================== ====================
/**
* 校验密码复杂度至少包含四类字符中的三类
*/
const checkComplexity = (
password: string
): { valid: boolean; message: string } => {
let count = 0;
const hasUpper = /[A-Z]/.test(password);
const hasLower = /[a-z]/.test(password);
const hasNumber = /[0-9]/.test(password);
const hasSpecial = /[^A-Za-z0-9]/.test(password);
if (hasUpper) count++;
if (hasLower) count++;
if (hasNumber) count++;
if (hasSpecial) count++;
if (count >= 3) {
return { valid: true, message: '' };
}
return {
valid: false,
message: '密码必须包含大写字母、小写字母、数字、特殊字符中的至少三类'
};
};
/**
* 校验连续重复字符
*/
const checkConsecutiveRepeat = (
password: string
): { valid: boolean; message: string } => {
for (let i = 0; i < password.length - 1; i++) {
if (password[i] === password[i + 1]) {
return {
valid: false,
message: '密码不能包含2位及以上相同字符的连续重复如11、aa'
};
}
}
return { valid: true, message: '' };
};
/**
* 校验连续递增/递减数字
*/
const checkConsecutiveNumbers = (
password: string
): { valid: boolean; message: string } => {
for (let i = 0; i < password.length - 1; i++) {
const curr = password.charCodeAt(i);
const next = password.charCodeAt(i + 1);
//
if (curr >= 48 && curr <= 57 && next >= 48 && next <= 57) {
if (Math.abs(next - curr) === 1) {
return {
valid: false,
message: '密码不能包含2位及以上连续递增或递减的数字如12、21'
};
}
}
}
return { valid: true, message: '' };
};
/**
* 校验连续递增/递减字母
*/
const checkConsecutiveLetters = (
password: string
): { valid: boolean; message: string } => {
for (let i = 0; i < password.length - 1; i++) {
const curr = password.charCodeAt(i);
const next = password.charCodeAt(i + 1);
//
const isCurrLetter =
(curr >= 65 && curr <= 90) || (curr >= 97 && curr <= 122);
const isNextLetter =
(next >= 65 && next <= 90) || (next >= 97 && next <= 122);
if (isCurrLetter && isNextLetter) {
if (Math.abs(next - curr) === 1) {
return {
valid: false,
message: '密码不能包含2位及以上连续递增或递减的字母如ab、ba'
};
}
}
}
return { valid: true, message: '' };
};
/**
* 校验用户名关联
*/
const checkUsernameRelation = (
password: string,
username: string
): { valid: boolean; message: string } => {
if (!username) {
return { valid: true, message: '' };
}
const lowerPassword = password.toLowerCase();
const lowerUsername = username.toLowerCase();
if (lowerPassword.includes(lowerUsername)) {
return {
valid: false,
message: '密码不能包含用户名或其核心部分'
};
}
return { valid: true, message: '' };
};
// ==================== ====================
const rules = {
oldPassword: [{ required: true, message: '请输入旧密码', trigger: 'blur' }],
newPassword: [
{ required: true, message: '请输入新密码', trigger: 'blur' },
{ min: 10, message: '密码长度不能少于10位', trigger: 'blur' },
{
validator: async (_rule: any, value: string) => {
if (!value) {
return Promise.resolve();
}
//
const complexity = checkComplexity(value);
if (!complexity.valid) {
return Promise.reject(new Error(complexity.message));
}
//
const repeat = checkConsecutiveRepeat(value);
if (!repeat.valid) {
return Promise.reject(new Error(repeat.message));
}
//
const numbers = checkConsecutiveNumbers(value);
if (!numbers.valid) {
return Promise.reject(new Error(numbers.message));
}
//
const letters = checkConsecutiveLetters(value);
if (!letters.valid) {
return Promise.reject(new Error(letters.message));
}
//
const username = userStore.username || '';
const usernameCheck = checkUsernameRelation(value, username);
if (!usernameCheck.valid) {
return Promise.reject(new Error(usernameCheck.message));
}
return Promise.resolve();
},
trigger: 'blur'
}
],
confirmPassword: [
{ required: true, message: '请再次输入新密码', trigger: 'blur' },
{
validator: async (_rule: any, value: string) => {
if (!value) {
return Promise.resolve();
}
if (value !== formState.newPassword) {
return Promise.reject(new Error('两次输入的密码不一致'));
}
return Promise.resolve();
},
trigger: 'blur'
}
]
};
/**
* 提交表单
*/
const handleSubmit = async () => {
try {
//
await formRef.value?.validate();
submitting.value = true;
// RSA
const encryptedOldPassword = encrypt(formState.oldPassword);
const encryptedNewPassword = encrypt(formState.newPassword);
if (!encryptedOldPassword || !encryptedNewPassword) {
message.error('密码加密失败');
return;
}
//
const res: any = await updatePassword({
id: userStore.userid,
password: encryptedNewPassword,
oldPassword: encryptedOldPassword
});
//
if (res.code === 0 || res.code === '0') {
message.success('密码修改成功,请重新登录');
// token
userStore.resetToken();
closeModal();
//
setTimeout(() => {
router.push('/login');
}, 1500);
} else {
message.error(res.msg || '密码修改失败');
}
} catch (error: any) {
if (error.errorFields) {
//
message.error('请检查表单填写是否正确');
} else {
//
message.error(error.message || '密码修改失败,请稍后重试');
}
} finally {
submitting.value = false;
}
};
/**
* 重置表单
*/
const handleReset = () => {
formRef.value?.resetFields();
formState.oldPassword = '';
formState.newPassword = '';
formState.confirmPassword = '';
};
/**
* 关闭弹窗并重置表单
*/
const handleCancel = () => {
formRef.value?.resetFields();
formState.oldPassword = '';
formState.newPassword = '';
formState.confirmPassword = '';
closeModal();
};
</script>
<template>
<a-modal
:open="props.open"
title="修改密码"
:footer="null"
:mask-closable="false"
width="480px"
@cancel="handleCancel"
>
<a-form
ref="formRef"
:model="formState"
:rules="rules"
layout="vertical"
class="password-form"
>
<a-form-item label="旧密码" name="oldPassword">
<a-input-password
v-model:value="formState.oldPassword"
placeholder="请输入旧密码"
allow-clear
/>
</a-form-item>
<a-form-item label="新密码" name="newPassword">
<a-input-password
v-model:value="formState.newPassword"
placeholder="请输入新密码"
allow-clear
/>
</a-form-item>
<a-form-item label="确认新密码" name="confirmPassword">
<a-input-password
v-model:value="formState.confirmPassword"
placeholder="请再次输入新密码"
allow-clear
/>
</a-form-item>
<a-form-item class="button-group">
<a-space>
<a-button
type="primary"
@click="handleSubmit"
:loading="submitting"
class="submit-btn"
>
提交
</a-button>
<a-button @click="handleReset">重置</a-button>
</a-space>
</a-form-item>
</a-form>
</a-modal>
</template>
<style scoped lang="scss">
.password-form {
:deep(.ant-form-item-label) {
label {
font-weight: 500;
color: #333;
}
}
:deep(.ant-input-password) {
border-radius: 4px;
&:hover {
border-color: #005293;
}
&:focus {
border-color: #005293;
box-shadow: 0 0 0 2px rgba(0, 82, 147, 0.2);
}
}
}
.button-group {
margin-top: 16px;
margin-bottom: 0;
.submit-btn {
width: 100px;
background-color: #005293;
border-color: #005293;
&:hover {
background-color: #003d6e;
border-color: #003d6e;
}
}
}
</style>

View File

@ -14,17 +14,11 @@ import dayjs from 'dayjs'; // ant 中文语言
import 'dayjs/locale/zh-cn'; import 'dayjs/locale/zh-cn';
// @ts-ignore // @ts-ignore
import 'virtual:svg-icons-register'; import 'virtual:svg-icons-register';
// 3d地图
import * as Cesium from 'cesium';
import 'cesium/Build/Cesium/Widgets/widgets.css';
// 国际化 // 国际化
import i18n from '@/lang/index'; import i18n from '@/lang/index';
import '@/styles/index.scss'; import '@/styles/index.scss';
import 'element-plus/theme-chalk/index.css'; import 'element-plus/theme-chalk/index.css';
//import 'element-plus/theme-chalk/dark/css-vars.css';
import WujieVue from 'wujie-vue3';
const app = createApp(App); const app = createApp(App);
// 自定义指令 // 自定义指令
@ -48,7 +42,5 @@ app
.use(router) .use(router)
.use(ElementPlus) .use(ElementPlus)
.use(Antd) .use(Antd)
.use(Antd)
.use(WujieVue)
.use(i18n) .use(i18n)
.mount('#app'); .mount('#app');

View File

@ -52,7 +52,6 @@ function findFirstAvailableRoute(routes: any[]): string | undefined {
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
NProgress.start(); NProgress.start();
const userStore = useUserStoreHook(); const userStore = useUserStoreHook();
if (userStore.Token) { if (userStore.Token) {
// 登录成功,跳转到首页 // 登录成功,跳转到首页
if (to.path === '/login') { if (to.path === '/login') {
@ -60,6 +59,15 @@ router.beforeEach(async (to, from, next) => {
next({ path: '/' }); next({ path: '/' });
NProgress.done(); NProgress.done();
return; return;
} else if (
(to.path === '/401' || to.path === '/404') &&
from.matched.length === 0 &&
!from.name
) {
// 拦截直接 URL 访问错误页面,仅允许内部重定向触发
next({ path: '/' });
NProgress.done();
return;
} else { } else {
const hasGetUserInfo = userStore.roles.length > 0; const hasGetUserInfo = userStore.roles.length > 0;
if (hasGetUserInfo) { if (hasGetUserInfo) {

View File

@ -35,12 +35,7 @@ export const constantRoutes: RouteRecordRaw[] = [
path: '/401', path: '/401',
component: () => import('@/views/error-page/401.vue'), component: () => import('@/views/error-page/401.vue'),
meta: { hidden: true } meta: { hidden: true }
}, }
{
path: '/changePassword',
component: () => import('@/views/changePassword/index.vue'),
meta: { hidden: true }
},
]; ];
// 创建路由 // 创建路由

View File

@ -20,27 +20,10 @@ service.interceptors.request.use(
); );
} }
config.headers.tenant_id = '4'; config.headers.tenant_id = '4';
if (
config.url.includes('/dec-lygk-base-server') ||
config.url.includes('/wmp-env-server') ||
config.url.includes('/wmp-sys-server') ||
config.url.includes('/wmp-eng-server') ||
config.url.includes('/dec-modules-usm-springcloud-starter') ||
config.url.includes('/wmp-swqx-server')
) {
config.headers._appid = '974975A6-47FD-4C04-9ACD-68938D2992BD';
config.headers._isolateid = '5b34aecb-adfb-4dfc-ad95-21505a9eb388';
config.headers._platformid = '31e6d13f-c359-4a19-8e67-b6f868f2401b';
config.headers._sysid = '10EC2E0B-AEA9-4757-83A2-201BA1BC54E9';
config.headers.authorization =
'bearer aa5be16b-d1a3-4b93-9886-b2490025c7d6';
config.baseURL = '/';
} else {
const user = useUserStoreHook(); const user = useUserStoreHook();
if (user.Token) { if (user.Token) {
config.headers.token = getToken(); config.headers.token = getToken();
} }
}
return config; return config;
}, },
(error: any) => { (error: any) => {

View File

@ -1,114 +1,48 @@
<!-- setup 无法设置组件名称组件名称keepAlive必须 -->
<script lang="ts">
export default {
name: 'Page401'
};
</script>
<script setup lang="ts">
import { reactive, toRefs } from 'vue';
import { useRouter } from 'vue-router';
const state = reactive({
errGif: new URL(`../../assets/401_images/401.gif`, import.meta.url).href,
ewizardClap:
'https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646',
dialogVisible: false
});
const { errGif, ewizardClap, dialogVisible } = toRefs(state);
const router = useRouter();
function back() {
router.back();
}
</script>
<template> <template>
<div class="errPage-container"> <div class="error-page-container">
<el-button icon="el-icon-arrow-left" class="pan-back-btn" @click="back"> <a-result
返回 status="403"
</el-button> title="401"
<el-row> sub-title="抱歉,您没有权限访问该页面,请尝试重新登录或联系管理员"
<el-col :span="12"> >
<h1 class="text-jumbo text-ginormous">Oops!</h1> <template #extra>
gif来源<a href="https://zh.airbnb.com/" target="_blank">airbnb</a> 页面 <a-space>
<h2>你没有权限去该页面</h2> <a-button type="primary" @click="goHome">
<h6>如有不满请联系你领导</h6> <template #icon><home-outlined /></template>
<ul class="list-unstyled"> 回首页
<li>或者你可以去:</li> </a-button>
<li class="link-type"> </a-space>
<router-link to="/"> 回首页 </router-link> </template>
</li> </a-result>
<li class="link-type">
<a href="https://www.taobao.com/">随便看看</a>
</li>
<li>
<a href="#" @click.prevent="dialogVisible = true">点我看图</a>
</li>
</ul>
</el-col>
<el-col :span="12">
<img
:src="errGif"
width="313"
height="428"
alt="Girl has dropped her ice cream."
/>
</el-col>
</el-row>
<el-dialog v-model="dialogVisible" title="随便看">
<img :src="ewizardClap" class="pan-img" />
</el-dialog>
</div> </div>
</template> </template>
<style lang="scss" scoped> <script setup lang="ts">
.errPage-container { import { useRouter } from 'vue-router';
width: 800px; import { HomeOutlined, ReloadOutlined } from '@ant-design/icons-vue';
max-width: 100%;
margin: 100px auto;
.pan-back-btn { const router = useRouter();
background: #008489;
color: #fff;
border: none !important;
}
.pan-gif { // permission
margin: 0 auto; const goHome = () => {
display: block; router.push('/');
} };
</script>
.pan-img { <style scoped>
display: block; .error-page-container {
margin: 0 auto; height: 100vh;
width: 100%; display: flex;
} justify-content: center;
align-items: center;
background: #f0f2f5;
}
.text-jumbo { /* 调整 Result 组件样式,使其更美观 */
font-size: 60px; .error-page-container :deep(.ant-result) {
font-weight: 700; padding: 48px 32px;
color: #484848; background: #fff;
} border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
.list-unstyled {
font-size: 14px;
li {
padding-bottom: 5px;
}
a {
color: #008489;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
} }
</style> </style>

View File

@ -1,280 +1,47 @@
<!-- setup 无法设置组件名称组件名称keepAlive必须 -->
<script lang="ts">
export default {
name: 'Page404'
};
</script>
<script setup lang="ts">
function message() {
return 'The webmaster said that you can not enter this page...';
}
</script>
<template> <template>
<div class="wscn-http404-container"> <div class="error-page-container">
<div class="wscn-http404"> <a-result
<div class="pic-404"> status="404"
<img title="404"
class="pic-404__parent" sub-title="抱歉,您访问的页面不存在,请检查网址或返回首页"
src="@/assets/404_images/404.png"
alt="404"
/>
<img
class="pic-404__child left"
src="@/assets/404_images/404_cloud.png"
alt="404"
/>
<img
class="pic-404__child mid"
src="@/assets/404_images/404_cloud.png"
alt="404"
/>
<img
class="pic-404__child right"
src="@/assets/404_images/404_cloud.png"
alt="404"
/>
</div>
<div class="bullshit">
<div class="bullshit__oops">OOPS!</div>
<div class="bullshit__info">
All rights reserved
<a
style="color: #20a0ff"
href="https://wallstreetcn.com"
target="_blank"
>wallstreetcn</a
> >
</div> <template #extra>
<div class="bullshit__headline">{{ message }}</div> <a-space>
<div class="bullshit__info"> <a-button type="primary" @click="goHome">
Please check that the URL you entered is correct, or click the button <template #icon><home-outlined /></template>
below to return to the homepage. 回首页
</div> </a-button>
<a href="" class="bullshit__return-home">Back to home</a> </a-space>
</div> </template>
</div> </a-result>
</div> </div>
</template> </template>
<style lang="scss" scoped> <script setup lang="ts">
.wscn-http404-container { import { useRouter } from 'vue-router';
transform: translate(-50%, -50%); import { HomeOutlined, ReloadOutlined } from '@ant-design/icons-vue';
position: absolute;
top: 40%; const router = useRouter();
left: 50%;
// permission
const goHome = () => {
router.push('/');
};
</script>
<style scoped>
.error-page-container {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: #f0f2f5;
} }
.wscn-http404 { .error-page-container :deep(.ant-result) {
position: relative; padding: 48px 32px;
width: 1200px; background: #fff;
padding: 0 50px; border-radius: 8px;
overflow: hidden; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
.pic-404 {
position: relative;
float: left;
width: 600px;
overflow: hidden;
&__parent {
width: 100%;
}
&__child {
position: absolute;
&.left {
width: 80px;
top: 17px;
left: 220px;
opacity: 0;
animation-name: cloudLeft;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
&.mid {
width: 46px;
top: 10px;
left: 420px;
opacity: 0;
animation-name: cloudMid;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1.2s;
}
&.right {
width: 62px;
top: 100px;
left: 500px;
opacity: 0;
animation-name: cloudRight;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
@keyframes cloudLeft {
0% {
top: 17px;
left: 220px;
opacity: 0;
}
20% {
top: 33px;
left: 188px;
opacity: 1;
}
80% {
top: 81px;
left: 92px;
opacity: 1;
}
100% {
top: 97px;
left: 60px;
opacity: 0;
}
}
@keyframes cloudMid {
0% {
top: 10px;
left: 420px;
opacity: 0;
}
20% {
top: 40px;
left: 360px;
opacity: 1;
}
70% {
top: 130px;
left: 180px;
opacity: 1;
}
100% {
top: 160px;
left: 120px;
opacity: 0;
}
}
@keyframes cloudRight {
0% {
top: 100px;
left: 500px;
opacity: 0;
}
20% {
top: 120px;
left: 460px;
opacity: 1;
}
80% {
top: 180px;
left: 340px;
opacity: 1;
}
100% {
top: 200px;
left: 300px;
opacity: 0;
}
}
}
}
.bullshit {
position: relative;
float: left;
width: 300px;
padding: 30px 0;
overflow: hidden;
&__oops {
font-size: 32px;
font-weight: bold;
line-height: 40px;
color: #1482f0;
opacity: 0;
margin-bottom: 20px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
&__headline {
font-size: 20px;
line-height: 24px;
color: #222;
font-weight: bold;
opacity: 0;
margin-bottom: 10px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.1s;
animation-fill-mode: forwards;
}
&__info {
font-size: 13px;
line-height: 21px;
color: grey;
opacity: 0;
margin-bottom: 30px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.2s;
animation-fill-mode: forwards;
}
&__return-home {
display: block;
float: left;
width: 110px;
height: 36px;
background: #1482f0;
border-radius: 100px;
text-align: center;
color: #ffffff;
opacity: 0;
font-size: 14px;
line-height: 36px;
cursor: pointer;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.3s;
animation-fill-mode: forwards;
}
@keyframes slideUp {
0% {
transform: translateY(60px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
}
} }
</style> </style>

View File

@ -0,0 +1,15 @@
<template>
<div />
</template>
<script setup lang="ts">
import { useRoute, useRouter } from 'vue-router';
const route = useRoute();
const router = useRouter();
const { params, query } = route;
const { path } = params;
router.replace({ path: '/' + path, query });
</script>

View File

@ -25,8 +25,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import moment from 'moment'; import dayjs from 'dayjs';
import { ref, computed, onMounted, watch } from 'vue'; import { ref, computed, onMounted, watch } from 'vue';
import BasicSearch from '@/components/BasicSearch/index.vue'; import BasicSearch from '@/components/BasicSearch/index.vue';
import { useShuJuTianBaoStore } from '@/store/modules/shuJuTianBao'; import { useShuJuTianBaoStore } from '@/store/modules/shuJuTianBao';
@ -50,7 +49,7 @@ const btnLoading = ref<boolean>(false);
const initSearchData = { const initSearchData = {
rvcd: 'all', rvcd: 'all',
stcd: null, stcd: null,
reportMonth: moment().subtract(1, 'month').format('YYYY-MM') reportMonth: dayjs().subtract(1, 'month').format('YYYY-MM')
}; };
const searchData = ref<any>({ ...initSearchData }); const searchData = ref<any>({ ...initSearchData });

View File

@ -338,7 +338,6 @@ const videoFileList = ref<any[]>([]);
// //
const disabledDate = (current: any) => { const disabledDate = (current: any) => {
// current moment/dayjs
// true // true
return current && current > dayjs().endOf('day'); return current && current > dayjs().endOf('day');
}; };
@ -370,7 +369,7 @@ const getHbrvcdDropdownSelect = async () => {
const res = await getSelectForDropdown({}); const res = await getSelectForDropdown({});
let list = res.data || []; let list = res.data || [];
if (list && list.length > 0) { if (list && list.length > 0) {
list = list.filter((item: any) => item.rvcd !== "all"); list = list.filter((item: any) => item.rvcd !== 'all');
} }
hbrvcdOption.value = list; hbrvcdOption.value = list;
} catch (error) { } catch (error) {
@ -469,13 +468,13 @@ const filterOption = (inputValue: string, option: any) => {
}; };
// //
const rules: Record<string, Rule[]> = { const rules: Record<string, Rule[]> = {
rvcd: [{ required: true, message: "请选择流域", trigger: "change" }], rvcd: [{ required: true, message: '请选择流域', trigger: 'change' }],
rstcd: [{ required: true, message: "请选择电站", trigger: "change" }], rstcd: [{ required: true, message: '请选择电站', trigger: 'change' }],
stcd: [{ required: true, message: "请选择过鱼设施", trigger: "change" }], stcd: [{ required: true, message: '请选择过鱼设施', trigger: 'change' }],
strdt: [{ required: true, message: "请选择过鱼时间", trigger: "change" }], strdt: [{ required: true, message: '请选择过鱼时间', trigger: 'change' }],
ftp: [{ required: true, message: "请选择鱼种类", trigger: "change" }], ftp: [{ required: true, message: '请选择鱼种类', trigger: 'change' }],
direction: [{ required: true, message: "请选择游向", trigger: "change" }], direction: [{ required: true, message: '请选择游向', trigger: 'change' }],
fcnt: [{ required: true, message: "请输入过鱼数量", trigger: "change" }], fcnt: [{ required: true, message: '请输入过鱼数量', trigger: 'change' }]
}; };
// //

View File

@ -103,11 +103,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, onMounted, watch } from 'vue'; import { ref, computed, onMounted, watch } from 'vue';
import {
SaveOutlined,
CheckSquareOutlined,
QuestionOutlined
} from '@ant-design/icons-vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import BasicSearch from '@/components/BasicSearch/index.vue'; // import BasicSearch from '@/components/BasicSearch/index.vue'; //
import { DateSetting } from '@/utils/enumeration'; import { DateSetting } from '@/utils/enumeration';

View File

@ -14,7 +14,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, onMounted, watch } from "vue"; import { ref, computed, onMounted } from "vue";
import dayjs from "dayjs"; import dayjs from "dayjs";
import BasicSearch from "@/components/BasicSearch/index.vue"; import BasicSearch from "@/components/BasicSearch/index.vue";
import { DateSetting } from "@/utils/enumeration"; import { DateSetting } from "@/utils/enumeration";

View File

@ -38,7 +38,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, onMounted } from "vue"; import { ref, computed, onMounted, watch } from "vue";
import BasicSearch from "@/components/BasicSearch/index.vue"; // import BasicSearch from "@/components/BasicSearch/index.vue"; //
import { getDictItemsByCode } from "@/api/dict"; import { getDictItemsByCode } from "@/api/dict";
import { CheckSquareOutlined, CloseCircleOutlined } from "@ant-design/icons-vue"; import { CheckSquareOutlined, CloseCircleOutlined } from "@ant-design/icons-vue";

View File

@ -33,79 +33,7 @@ export default ({ mode }: ConfigEnv): UserConfig => {
changeOrigin: true, changeOrigin: true,
rewrite: path => rewrite: path =>
path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '') path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
},
'/process': {
target: 'http://localhost:5174',
changeOrigin: true
},
'/api/dec-lygk-base-server': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,
secure: false,
rewrite: path =>
path.replace(
new RegExp('^/api/dec-lygk-base-server'),
'/api/dec-lygk-base-server'
)
},
'/wmp-env-server': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,
secure: false,
rewrite: path =>
path.replace(new RegExp('^/wmp-env-server'), '/api/wmp-env-server')
},
'/api/wmp-env-server': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,
secure: false,
rewrite: path =>
path.replace(
new RegExp('^/api/wmp-env-server'),
'/api/wmp-env-server'
)
},
'/api/wmp-eng-server': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,
secure: false,
rewrite: path =>
path.replace(
new RegExp('^/api/wmp-eng-server'),
'/api/wmp-eng-server'
)
},
'/api/wmp-sys-server': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,
secure: false,
rewrite: path =>
path.replace(
new RegExp('^/api/wmp-sys-server'),
'/api/wmp-sys-server'
)
},
'/api/dec-modules-usm-springcloud-starter': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,
secure: false,
rewrite: path =>
path.replace(
new RegExp('^/api/dec-modules-usm-springcloud-starter'),
'/api/dec-modules-usm-springcloud-starter'
)
},
'/api/wmp-swqx-server/': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,
secure: false,
rewrite: path =>
path.replace(
new RegExp('^/api/dec-modules-usm-springcloud-starter'),
'/api/dec-modules-usm-springcloud-starter'
)
} }
// /
} }
}, },
build: { build: {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

View File

@ -99,7 +99,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch } from 'vue'; import { ref, computed, watch } from 'vue';
import moment from 'moment'; import dayjs from 'dayjs';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useMapOrchestrator } from '@/modules/map/application/map-orchestrator'; import { useMapOrchestrator } from '@/modules/map/application/map-orchestrator';
import { useMapDataStore } from '@/modules/map/stores/map-data.store'; import { useMapDataStore } from '@/modules/map/stores/map-data.store';
@ -122,7 +122,7 @@ const formModel = ref({
anchorPointSelect: null, anchorPointSelect: null,
fishSurveyZhuanZhi: false fishSurveyZhuanZhi: false
}); });
const currentDate = moment(); const currentDate = dayjs();
const defaultYear = const defaultYear =
currentDate.month() < 6 ? currentDate.year() - 1 : currentDate.year(); currentDate.month() < 6 ? currentDate.year() - 1 : currentDate.year();
@ -132,8 +132,8 @@ const fishSurveyZhuanZhiParams = ref({
}); });
const searchTimeRange = ref([ const searchTimeRange = ref([
moment(mapViewStore.searchTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'), dayjs(mapViewStore.searchTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'),
moment(mapViewStore.searchTimeRange[1]).format('YYYY-MM-DD HH:mm:ss') dayjs(mapViewStore.searchTimeRange[1]).format('YYYY-MM-DD HH:mm:ss')
]); ]);
// //
@ -148,8 +148,8 @@ watch(
() => { () => {
mapOrchestrator.resetFilterState(); mapOrchestrator.resetFilterState();
searchTimeRange.value = [ searchTimeRange.value = [
moment(mapViewStore.searchTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'), dayjs(mapViewStore.searchTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'),
moment(mapViewStore.searchTimeRange[1]).format('YYYY-MM-DD HH:mm:ss') dayjs(mapViewStore.searchTimeRange[1]).format('YYYY-MM-DD HH:mm:ss')
]; ];
formModel.value = { formModel.value = {
siteRangePicker: null, siteRangePicker: null,

View File

@ -1,18 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, onBeforeUnmount } from "vue"; import { ref } from 'vue';
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from 'vue-router';
import { Modal } from "ant-design-vue"; import { Modal } from 'ant-design-vue';
import { UserOutlined, LogoutOutlined } from "@ant-design/icons-vue"; import { UserOutlined, LogoutOutlined } from '@ant-design/icons-vue';
// //
import { useI18n } from "vue-i18n"; import { useI18n } from 'vue-i18n';
const { t } = useI18n(); const { t } = useI18n();
// import LangSelect from '@/components/LangSelect/index.vue'; // import LangSelect from '@/components/LangSelect/index.vue';
import Sidebar from "./Sidebar/index.vue"; import Sidebar from './Sidebar/index.vue';
import ChangePassword from './changePassword.vue';
import { useTagsViewStore } from "@/store/modules/tagsView"; import { useTagsViewStore } from '@/store/modules/tagsView';
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from '@/store/modules/user';
// const url = import.meta.env.VITE_APP_BASE_API;
const tagsViewStore = useTagsViewStore(); const tagsViewStore = useTagsViewStore();
const userStore = useUserStore(); const userStore = useUserStore();
@ -21,10 +20,10 @@ const route = useRoute();
const router = useRouter(); const router = useRouter();
function logout() { function logout() {
Modal.confirm({ Modal.confirm({
title: "提示?", title: '提示?',
content: "确定注销并退出系统吗?", content: '确定注销并退出系统吗?',
okText: "确定", okText: '确定',
type: "warning", type: 'warning',
onOk: async () => { onOk: async () => {
userStore userStore
.logout() .logout()
@ -34,14 +33,13 @@ function logout() {
.then(() => { .then(() => {
router.push(`/login`); router.push(`/login`);
}); });
}, }
}); });
} }
const changePasswordVisible = ref(false);
function changePassword() { function changePassword() {
router.push("/changePassword"); changePasswordVisible.value = true;
} }
onMounted(() => {});
onBeforeUnmount(() => {});
</script> </script>
<template> <template>
@ -52,8 +50,9 @@ onBeforeUnmount(() => {});
href="/" href="/"
class="h-[50px] min-w-[350px] flex items-center justify-center text-white" class="h-[50px] min-w-[350px] flex items-center justify-center text-white"
> >
<!-- <h1 class="text-blank font-bold text-[16px]">{{ t("login.title") }}</h1> --> <h1 class="text-blank font-bold text-[16px]">
<h1 class="text-blank font-bold text-[16px]">{{ t("login.title") }}</h1> {{ t('login.title') }}
</h1>
</a> </a>
</transition> </transition>
<Sidebar /> <Sidebar />
@ -82,11 +81,12 @@ onBeforeUnmount(() => {});
</template> </template>
</a-dropdown> </a-dropdown>
</a-layout-header> </a-layout-header>
<ChangePassword v-model:open="changePasswordVisible" />
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
@use "@/styles/variables.module.scss" as *; @use '@/styles/variables.module.scss' as *;
.navbar { .navbar {
width: 100%; width: 100%;
position: relative; position: relative;

View File

@ -0,0 +1,394 @@
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { useRouter } from 'vue-router';
import { message } from 'ant-design-vue';
import type { FormInstance } from 'ant-design-vue';
import { useUserStore } from '@/store/modules/user';
import { encrypt } from '@/utils/rsaEncrypt';
import { updatePassword } from '@/api/changePassWord';
const router = useRouter();
const userStore = useUserStore();
const props = defineProps<{ open: boolean }>();
const emit = defineEmits<{ 'update:open': [value: boolean] }>();
const closeModal = () => emit('update:open', false);
//
const formRef = ref<FormInstance>();
//
const submitting = ref(false);
//
interface ChangePasswordForm {
oldPassword: string;
newPassword: string;
confirmPassword: string;
}
const formState = reactive<ChangePasswordForm>({
oldPassword: '',
newPassword: '',
confirmPassword: ''
});
// ==================== ====================
/**
* 校验密码复杂度至少包含四类字符中的三类
*/
const checkComplexity = (
password: string
): { valid: boolean; message: string } => {
let count = 0;
const hasUpper = /[A-Z]/.test(password);
const hasLower = /[a-z]/.test(password);
const hasNumber = /[0-9]/.test(password);
const hasSpecial = /[^A-Za-z0-9]/.test(password);
if (hasUpper) count++;
if (hasLower) count++;
if (hasNumber) count++;
if (hasSpecial) count++;
if (count >= 3) {
return { valid: true, message: '' };
}
return {
valid: false,
message: '密码必须包含大写字母、小写字母、数字、特殊字符中的至少三类'
};
};
/**
* 校验连续重复字符
*/
const checkConsecutiveRepeat = (
password: string
): { valid: boolean; message: string } => {
for (let i = 0; i < password.length - 1; i++) {
if (password[i] === password[i + 1]) {
return {
valid: false,
message: '密码不能包含2位及以上相同字符的连续重复如11、aa'
};
}
}
return { valid: true, message: '' };
};
/**
* 校验连续递增/递减数字
*/
const checkConsecutiveNumbers = (
password: string
): { valid: boolean; message: string } => {
for (let i = 0; i < password.length - 1; i++) {
const curr = password.charCodeAt(i);
const next = password.charCodeAt(i + 1);
//
if (curr >= 48 && curr <= 57 && next >= 48 && next <= 57) {
if (Math.abs(next - curr) === 1) {
return {
valid: false,
message: '密码不能包含2位及以上连续递增或递减的数字如12、21'
};
}
}
}
return { valid: true, message: '' };
};
/**
* 校验连续递增/递减字母
*/
const checkConsecutiveLetters = (
password: string
): { valid: boolean; message: string } => {
for (let i = 0; i < password.length - 1; i++) {
const curr = password.charCodeAt(i);
const next = password.charCodeAt(i + 1);
//
const isCurrLetter =
(curr >= 65 && curr <= 90) || (curr >= 97 && curr <= 122);
const isNextLetter =
(next >= 65 && next <= 90) || (next >= 97 && next <= 122);
if (isCurrLetter && isNextLetter) {
if (Math.abs(next - curr) === 1) {
return {
valid: false,
message: '密码不能包含2位及以上连续递增或递减的字母如ab、ba'
};
}
}
}
return { valid: true, message: '' };
};
/**
* 校验用户名关联
*/
const checkUsernameRelation = (
password: string,
username: string
): { valid: boolean; message: string } => {
if (!username) {
return { valid: true, message: '' };
}
const lowerPassword = password.toLowerCase();
const lowerUsername = username.toLowerCase();
if (lowerPassword.includes(lowerUsername)) {
return {
valid: false,
message: '密码不能包含用户名或其核心部分'
};
}
return { valid: true, message: '' };
};
// ==================== ====================
const rules = {
oldPassword: [{ required: true, message: '请输入旧密码', trigger: 'blur' }],
newPassword: [
{ required: true, message: '请输入新密码', trigger: 'blur' },
{ min: 10, message: '密码长度不能少于10位', trigger: 'blur' },
{
validator: async (_rule: any, value: string) => {
if (!value) {
return Promise.resolve();
}
//
const complexity = checkComplexity(value);
if (!complexity.valid) {
return Promise.reject(new Error(complexity.message));
}
//
const repeat = checkConsecutiveRepeat(value);
if (!repeat.valid) {
return Promise.reject(new Error(repeat.message));
}
//
const numbers = checkConsecutiveNumbers(value);
if (!numbers.valid) {
return Promise.reject(new Error(numbers.message));
}
//
const letters = checkConsecutiveLetters(value);
if (!letters.valid) {
return Promise.reject(new Error(letters.message));
}
//
const username = userStore.username || '';
const usernameCheck = checkUsernameRelation(value, username);
if (!usernameCheck.valid) {
return Promise.reject(new Error(usernameCheck.message));
}
return Promise.resolve();
},
trigger: 'blur'
}
],
confirmPassword: [
{ required: true, message: '请再次输入新密码', trigger: 'blur' },
{
validator: async (_rule: any, value: string) => {
if (!value) {
return Promise.resolve();
}
if (value !== formState.newPassword) {
return Promise.reject(new Error('两次输入的密码不一致'));
}
return Promise.resolve();
},
trigger: 'blur'
}
]
};
/**
* 提交表单
*/
const handleSubmit = async () => {
try {
//
await formRef.value?.validate();
submitting.value = true;
// RSA
const encryptedOldPassword = encrypt(formState.oldPassword);
const encryptedNewPassword = encrypt(formState.newPassword);
if (!encryptedOldPassword || !encryptedNewPassword) {
message.error('密码加密失败');
return;
}
//
const res: any = await updatePassword({
id: userStore.userid,
password: encryptedNewPassword,
oldPassword: encryptedOldPassword
});
//
if (res.code === 0 || res.code === '0') {
message.success('密码修改成功,请重新登录');
// token
userStore.resetToken();
closeModal();
//
setTimeout(() => {
router.push('/login');
}, 1500);
} else {
message.error(res.msg || '密码修改失败');
}
} catch (error: any) {
if (error.errorFields) {
//
message.error('请检查表单填写是否正确');
} else {
//
message.error(error.message || '密码修改失败,请稍后重试');
}
} finally {
submitting.value = false;
}
};
/**
* 重置表单
*/
const handleReset = () => {
formRef.value?.resetFields();
formState.oldPassword = '';
formState.newPassword = '';
formState.confirmPassword = '';
};
/**
* 关闭弹窗并重置表单
*/
const handleCancel = () => {
formRef.value?.resetFields();
formState.oldPassword = '';
formState.newPassword = '';
formState.confirmPassword = '';
closeModal();
};
</script>
<template>
<a-modal
:open="props.open"
title="修改密码"
:footer="null"
:mask-closable="false"
width="480px"
@cancel="handleCancel"
>
<a-form
ref="formRef"
:model="formState"
:rules="rules"
layout="vertical"
class="password-form"
>
<a-form-item label="旧密码" name="oldPassword">
<a-input-password
v-model:value="formState.oldPassword"
placeholder="请输入旧密码"
allow-clear
/>
</a-form-item>
<a-form-item label="新密码" name="newPassword">
<a-input-password
v-model:value="formState.newPassword"
placeholder="请输入新密码"
allow-clear
/>
</a-form-item>
<a-form-item label="确认新密码" name="confirmPassword">
<a-input-password
v-model:value="formState.confirmPassword"
placeholder="请再次输入新密码"
allow-clear
/>
</a-form-item>
<a-form-item class="button-group">
<a-space>
<a-button
type="primary"
@click="handleSubmit"
:loading="submitting"
class="submit-btn"
>
提交
</a-button>
<a-button @click="handleReset">重置</a-button>
</a-space>
</a-form-item>
</a-form>
</a-modal>
</template>
<style scoped lang="scss">
.password-form {
:deep(.ant-form-item-label) {
label {
font-weight: 500;
color: #333;
}
}
:deep(.ant-input-password) {
border-radius: 4px;
&:hover {
border-color: #005293;
}
&:focus {
border-color: #005293;
box-shadow: 0 0 0 2px rgba(0, 82, 147, 0.2);
}
}
}
.button-group {
margin-top: 16px;
margin-bottom: 0;
.submit-btn {
width: 100px;
background-color: #005293;
border-color: #005293;
&:hover {
background-color: #003d6e;
border-color: #003d6e;
}
}
}
</style>

View File

@ -23,8 +23,6 @@ import i18n from '@/lang/index';
import '@/styles/index.scss'; import '@/styles/index.scss';
import 'element-plus/theme-chalk/index.css'; import 'element-plus/theme-chalk/index.css';
//import 'element-plus/theme-chalk/dark/css-vars.css';
import WujieVue from 'wujie-vue3';
const app = createApp(App); const app = createApp(App);
// 自定义指令 // 自定义指令
@ -49,6 +47,5 @@ app
.use(ElementPlus) .use(ElementPlus)
.use(Antd) .use(Antd)
.use(Antd) .use(Antd)
.use(WujieVue)
.use(i18n) .use(i18n)
.mount('#app'); .mount('#app');

View File

@ -1,6 +1,6 @@
import { watch, type WatchStopHandle } from 'vue'; import { watch, type WatchStopHandle } from 'vue';
import { unByKey } from 'ol/Observable'; import { unByKey } from 'ol/Observable';
import moment from 'moment'; import dayjs from 'dayjs';
import { MapClass } from '@/components/gis/map.class'; import { MapClass } from '@/components/gis/map.class';
import { getMapConfig, layerConfig2Flat } from '@/components/gis/gisUtils'; import { getMapConfig, layerConfig2Flat } from '@/components/gis/gisUtils';
import { useMapConfigStore } from '@/modules/map/stores/map-config.store'; import { useMapConfigStore } from '@/modules/map/stores/map-config.store';
@ -393,7 +393,7 @@ export const useMapOrchestrator = () => {
// 备注:统一重置地图筛选表单依赖的时间范围,供筛选组件在切页时复位默认输入。 // 备注:统一重置地图筛选表单依赖的时间范围,供筛选组件在切页时复位默认输入。
const resetFilterState = () => { const resetFilterState = () => {
mapViewStore.setSearchTimeRange([moment().subtract(1, 'M'), moment()]); mapViewStore.setSearchTimeRange([dayjs().subtract(1, 'M'), dayjs()]);
}; };
// 备注:统一处理搜索定位,按点位编码从缓存数据中查找并飞行到目标位置。 // 备注:统一处理搜索定位,按点位编码从缓存数据中查找并飞行到目标位置。

View File

@ -1,11 +1,11 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { ref } from 'vue'; import { ref } from 'vue';
import moment from 'moment'; import dayjs from 'dayjs';
export const useMapViewStore = defineStore('map-view', () => { export const useMapViewStore = defineStore('map-view', () => {
const checkedLayerKeys = ref<string[]>([]); const checkedLayerKeys = ref<string[]>([]);
const legendCheckedState = ref<Record<string, number>>({}); const legendCheckedState = ref<Record<string, number>>({});
const searchTimeRange = ref<[any, any]>([moment().subtract(1, 'M'), moment()]); const searchTimeRange = ref<[any, any]>([dayjs().subtract(1, 'M'), dayjs()]);
const selectedBaseId = ref(''); const selectedBaseId = ref('');
const currentZoomLevel = ref(4.5); const currentZoomLevel = ref(4.5);
@ -67,7 +67,7 @@ export const useMapViewStore = defineStore('map-view', () => {
const resetViewState = () => { const resetViewState = () => {
checkedLayerKeys.value = []; checkedLayerKeys.value = [];
legendCheckedState.value = {}; legendCheckedState.value = {};
searchTimeRange.value = [moment().subtract(1, 'M'), moment()]; searchTimeRange.value = [dayjs().subtract(1, 'M'), dayjs()];
selectedBaseId.value = ''; selectedBaseId.value = '';
currentZoomLevel.value = 4.5; currentZoomLevel.value = 4.5;
}; };

View File

@ -18,7 +18,7 @@
<div v-if="modalData" class="modal-content"> <div v-if="modalData" class="modal-content">
<MonthlyAverage <MonthlyAverage
:tm="modalData.date ? moment(modalData.date).format('YYYY-MM') + '-01 00:00:00' : moment().format('YYYY-MM') + '-01 23:59:59'" :tm="modalData.date ? dayjs(modalData.date).format('YYYY-MM') + '-01 00:00:00' : dayjs().format('YYYY-MM') + '-01 23:59:59'"
:dataDimensionVal="modalData.baseid" :rvcd='modalData.rvcd' :stcd="modalData.stcd" :jdList="JidiSelectEventStore.jidiData" /> :dataDimensionVal="modalData.baseid" :rvcd='modalData.rvcd' :stcd="modalData.stcd" :jdList="JidiSelectEventStore.jidiData" />
</div> </div>
</a-modal> </a-modal>
@ -37,7 +37,7 @@ import { wbsbGetKendoList, avgMonGetKendoListCust } from "@/api/sw";
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent"; import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import MonthlyAverage from './monthlyAverage.vue' import MonthlyAverage from './monthlyAverage.vue'
import MonthlyAverageMaxModal from './TwoLayers/monthlyAverageMaxModal.vue' import MonthlyAverageMaxModal from './TwoLayers/monthlyAverageMaxModal.vue'
import moment from 'moment' import dayjs from 'dayjs'
import { import {
ZoomInOutlined ZoomInOutlined
} from '@ant-design/icons-vue'; } from '@ant-design/icons-vue';

View File

@ -104,7 +104,7 @@ import { message } from 'ant-design-vue';
import dayjs, { Dayjs } from 'dayjs'; import dayjs, { Dayjs } from 'dayjs';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts'; import type { EChartsOption } from 'echarts';
import moment from 'moment'; import dayjs from 'dayjs';
import { omit } from 'lodash'; import { omit } from 'lodash';
import { wbsbGetKendoList, getVmsstbprpt, DetGetKendoListCust } from '@/api/sw'; import { wbsbGetKendoList, getVmsstbprpt, DetGetKendoListCust } from '@/api/sw';
import BasicTable from '@/components/BasicTable/index.vue'; import BasicTable from '@/components/BasicTable/index.vue';
@ -220,7 +220,7 @@ const getColorByCodeAndType = (code: string[], typeKey: string[]): string[] => {
/** /**
* 日期格式化 * 日期格式化
*/ */
const tmFmt = (d: string) => moment(d).format('YYYY-MM-DD'); const tmFmt = (d: string) => dayjs(d).format('YYYY-MM-DD');
/** /**
* 格式化数值保留一位小数四舍五入空值显示 - * 格式化数值保留一位小数四舍五入空值显示 -
@ -675,7 +675,7 @@ const handleSearch = async () => {
const tmValue = dayjs.isDayjs(formValue.tm) const tmValue = dayjs.isDayjs(formValue.tm)
? formValue.tm.format('YYYY-MM-DD 00:00:00') ? formValue.tm.format('YYYY-MM-DD 00:00:00')
: moment(formValue.tm).format('YYYY-MM-DD 00:00:00'); : dayjs(formValue.tm).format('YYYY-MM-DD 00:00:00');
const values = { const values = {
...formValue, ...formValue,
@ -694,12 +694,12 @@ const handleExport = async () => {
try { try {
const tmValue = dayjs.isDayjs(formValue.tm) const tmValue = dayjs.isDayjs(formValue.tm)
? formValue.tm.format('YYYY-MM-DD 00:00:00') ? formValue.tm.format('YYYY-MM-DD 00:00:00')
: moment(formValue.tm).format('YYYY-MM-DD 00:00:00'); : dayjs(formValue.tm).format('YYYY-MM-DD 00:00:00');
const params = { const params = {
...buildFilterParams({ ...formValue, tm: tmValue }), ...buildFilterParams({ ...formValue, tm: tmValue }),
exportType: 'excel', exportType: 'excel',
exportFileName: `月平均水温历史对比 ${moment().format( exportFileName: `月平均水温历史对比 ${dayjs().format(
'YYYY-MM-DD HH-mm-ss' 'YYYY-MM-DD HH-mm-ss'
)}` )}`
}; };

View File

@ -60,6 +60,15 @@ router.beforeEach(async (to, from, next) => {
next({ path: '/' }); next({ path: '/' });
NProgress.done(); NProgress.done();
return; return;
} else if (
(to.path === '/401' || to.path === '/404') &&
from.matched.length === 0 &&
!from.name
) {
// 拦截直接 URL 访问错误页面,仅允许内部重定向触发
next({ path: '/' });
NProgress.done();
return;
} else { } else {
const hasGetUserInfo = userStore.roles.length > 0; const hasGetUserInfo = userStore.roles.length > 0;
if (hasGetUserInfo) { if (hasGetUserInfo) {

View File

@ -35,12 +35,7 @@ export const constantRoutes: RouteRecordRaw[] = [
path: '/401', path: '/401',
component: () => import('@/views/error-page/401.vue'), component: () => import('@/views/error-page/401.vue'),
meta: { hidden: true } meta: { hidden: true }
}, }
{
path: '/changePassword',
component: () => import('@/views/changePassword/index.vue'),
meta: { hidden: true }
},
]; ];
// 创建路由 // 创建路由

View File

@ -0,0 +1,136 @@
import { ref, computed } from 'vue';
import dayjs, { Dayjs } from 'dayjs';
export interface UseTimeScaleOptions {
defaultTimeScale?: string;
onSearchFinish?: (values: any) => void;
onReset?: (values: any) => void;
}
export function useTimeScale(options: UseTimeScaleOptions = {}) {
const defaultTimeScale = options.defaultTimeScale || 'tm';
const currentTimeScale = ref(defaultTimeScale);
const jcdt = ref({
min: null as string | null,
max: null as string | null
});
// 根据时间尺度动态切换 picker 类型
const timePicker = computed(() => {
if (currentTimeScale.value === 'tm') return 'date';
if (currentTimeScale.value === 'dt') return 'date';
return 'month';
});
// 根据时间尺度动态切换 format
const timeFormat = computed(() => {
if (currentTimeScale.value === 'tm') return 'YYYY-MM-DD HH:mm';
if (currentTimeScale.value === 'dt') return 'YYYY-MM-DD';
return 'YYYY-MM';
});
// 小时模式需要 showTime 配置
const timeShowTime = computed(() => {
if (currentTimeScale.value === 'tm') return { format: 'HH:mm' };
return undefined;
});
// 设置默认时间范围
const setDefaultTimeRange = (timeScale: string) => {
const now = dayjs();
const today = now.format('YYYY-MM-DD');
if (timeScale === 'tm') {
// 小时:默认前七天,使用当前时分秒
jcdt.value = {
min: `${dayjs().subtract(6, 'day').format('YYYY-MM-DD')} ${now.format(
'HH:mm:ss'
)}`,
max: `${today} ${now.format('HH:mm:ss')}`
};
} else if (timeScale === 'dt') {
// 日:默认前一个月
jcdt.value = {
min: `${dayjs().subtract(1, 'month').format('YYYY-MM-DD')} 00:00:00`,
max: `${today} 23:59:59`
};
} else {
// 月默认前4个月
jcdt.value = {
min: `${dayjs().subtract(4, 'month').format('YYYY-MM')}-01 00:00:00`,
max: `${today} 23:59:59`
};
}
};
const handleRangeClick = (value: any) => {
jcdt.value = {
min: dayjs(value.value[0]).format('YYYY-MM-DD HH:mm:ss'),
max: dayjs(value.value[1]).format('YYYY-MM-DD HH:mm:ss')
};
};
// 禁用起始时间之前的日期
const disabledEndDate = (current: Dayjs) => {
if (!jcdt.value.min) return false;
return current && current < dayjs(jcdt.value.min).endOf('day');
};
// 处理搜索完成
const handleSearchFinish = (values: any) => {
values.jcdt = {
min: values.jcdt?.min || jcdt.value.min,
max: values.jcdt?.max || jcdt.value.max
};
if (jcdt.value.min) values.jcdt.min = dayjs(jcdt.value.min);
if (jcdt.value.max) values.jcdt.max = dayjs(jcdt.value.max);
// 强制使用当前 timeScale不被传入值覆盖
values.timeScale = currentTimeScale.value;
options.onSearchFinish?.(values);
};
// 处理值变化
const handleValuesChange = (changedValues: any, allValues: any) => {
if (
changedValues.timeScale &&
changedValues.timeScale !== currentTimeScale.value
) {
currentTimeScale.value = changedValues.timeScale;
setDefaultTimeRange(changedValues.timeScale);
}
};
// 处理重置
const handleReset = () => {
jcdt.value = {
min: null,
max: null
};
currentTimeScale.value = defaultTimeScale;
setDefaultTimeRange(defaultTimeScale);
options.onReset?.({
timeScale: defaultTimeScale
});
};
// 初始化
const init = () => {
setDefaultTimeRange(defaultTimeScale);
};
return {
jcdt,
currentTimeScale,
timePicker,
timeFormat,
timeShowTime,
handleRangeClick,
disabledEndDate,
handleSearchFinish,
handleValuesChange,
handleReset,
init,
setDefaultTimeRange
};
}

View File

@ -1,449 +0,0 @@
import moment from 'moment';
export const urlList = [
{
url: '/wmp-eng-server/eng/point/GetKendoListCust',
title: '常规水电',
params: {
anchoPointState: [{ field: 'anchoPointState', operator: 'isnotnull' }]
},
orders:
'{"baseId":"asc","rvcdStepSort":"asc","siteStepSort":"asc","ennm":"asc"}'
},
{
url: '/wmp-env-server/sw/getFacilityPointList/GetKendoListCust',
title: '低温水减缓设施',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-eng-server/eng/eq/interval/GetKendoListCust',
title: '生态流量达标率',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] },
orders:
'{"baseId":"asc","rvcdStepSort":"asc","siteStepSort":"asc","ennm":"asc"}'
},
{
url: '/wmp-env-server/env/wq/anchorPoint/reach/GetKendoListCust',
title: '实际水质',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/wq/anchorPoint/reach/GetKendoListCust',
title: '目标水质',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '自建站',
params: {
dtinType: [{ field: 'dtinType', operator: 'eq', value: '0' }],
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
},
orders: '{"siteStepSort":"asc"}'
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '国家站',
params: {
dtinType: [{ field: 'dtinType', operator: 'eq', value: '1' }],
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '人工站',
params: {
dtinType: [{ field: 'dtinType', operator: 'eq', value: '2' }],
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '栖息地水质站',
params: {
fhstcd: [{ field: 'fhstcd', operator: 'isnotnull' }],
fhFlag: [{ field: 'fhFlag', operator: 'eq', value: '1' }],
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fp/point/qgc/GetKendoListCust',
title: '过鱼设施',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-eng-server/eng/eq/eqds/GetKendoListCust',
title: '生态流量泄放设施',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/fb/point/GetKendoListCust',
title: '鱼类增殖站',
params: {
sttp: [{ field: 'sttp', operator: 'eq', value: 'FB' }],
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fhvap/GetKendoListCust',
title: '珍稀植物园',
params: { sttpCode: 'VP', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fhvap/GetKendoListCust',
title: '动物救助站',
params: { sttpCode: 'VA', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/fb/point/GetKendoListCust',
title: '人工产卵场',
params: { sttp: 'SG', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/sw/getEngTempPointList/GetKendoListCust',
title: '水温监测断面',
keyType: 'wt_point',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/sw/getEngTempPointList/GetKendoListCust',
title: '自建水温站',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }], flag: '0' }
},
{
url: '/wmp-env-server/sw/getEngTempPointList/GetKendoListCust',
title: '人工水温站',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }], flag: '2' }
},
{
url: '/wmp-env-server/sw/getEngTempPointList/GetKendoListCust',
title: '栖息地水温站',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
fhstcd: [{ field: 'fhstcd', operator: 'isnotnull' }],
fhFlag: '1'
}
},
{
url: '/wmp-env-server/env/fhvap/GetKendoListCust',
title: '栖息地',
params: { sttpCode: 'FH', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fhvap/fhPoint/GetKendoListCust',
title: '水质监测站',
params: { sttpCode: 'WQ', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fhvap/fhPoint/GetKendoListCust',
title: '水温监测站',
params: {
sttpCode: 'WTRV',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fhvap/fhPoint/GetKendoListCust',
title: '流量监测站',
params: { sttpCode: 'ZQ', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fhvap/fhPoint/GetKendoListCust',
title: '视频监控',
params: { sttpCode: 'VD', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/vd/aiPoint/GetKendoListCust',
title: 'AI视频监控站',
params: { sttpCode: 'AIVD' }
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '水电站监控视频',
keyType: 'video_fbfm_point',
params: {
sttp: 'VD_FBFM',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '生态流量监测断面视频',
keyType: 'video_eqs_point',
params: {
sttp: 'VD_EQS',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '水质站运行视频',
keyType: 'video_wq_point',
params: {
sttp: 'VD_WQ',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '过鱼设施视频',
keyType: 'video_fp_point',
params: {
sttp: 'VD_FP',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '鱼类增殖站视频',
keyType: 'video_fb_point',
params: {
sttp: 'VD_FB',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '栖息地视频',
keyType: 'video_fh_point',
params: {
sttp: 'VD_FH',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '低温水减缓设施视频',
keyType: 'video_dw_point',
params: {
sttp: 'VD_DW',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '动物救助站视频',
keyType: 'video_va_point',
params: {
sttp: 'VD_VA',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '珍稀植物园视频',
keyType: 'video_vp_point',
params: {
sttp: 'VD_VP',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/we/point/qgc/GetKendoListCust',
title: '水生生态调查断面',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] },
orders: '{"siteStepSort":"asc"}'
},
{
url: '/wmp-env-server/env/we/fishPoint/qgc/GetKendoListCust',
title: '鱼类分布',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-eng-server/eng/alarmPoint/GetKendoListCust',
title: '水电站告警情况',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/fb/point/discharge/GetKendoListCust',
title: '水电站',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fh/zqpoint/GetKendoListCust',
title: '国家水文站',
params: { dtinType: 1, lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fh/zqpoint/GetKendoListCust',
title: '自建水文站',
params: { dtinType: 0, lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '增殖站水质站',
params: {
dtinType: 0,
sttpCode: 'WQFB',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '视频监控站',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/wb/point/GetKendoListCust',
title: '气象站',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/sw/getEngTempPointList/getLastData',
title: '水温站点',
params: {
logic: 'and',
filters: []
}
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '水质站点',
params: {
logic: 'and',
filters: [
{
field: 'lgtd',
operator: 'isnotnull',
dataType: 'string'
},
{
field: 'orderIndex',
operator: 'isnotnull',
dataType: 'string'
}
]
},
orders: '{"orderIndex":"asc"}'
},
{
url: '/wmp-env-server/env/warn/stcd/point/GetKendoListCust',
title: '水质告警',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'WQ' }]
}
},
{
url: '/wmp-env-server/env/warn/stcd/point/GetKendoListCust',
title: '水温告警',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'WTRV' }]
}
},
{
url: '/wmp-env-server/env/warn/stcd/point/GetKendoListCust',
title: '水位告警',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'ENG' }]
}
},
{
url: '/wmp-env-server/env/warn/stcd/operatePoint/GetKendoListCust',
title: '环保设施告警',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
yr: moment().format('YYYY')
}
},
{
url: '/wmp-env-server/env/fp/point/built/GetKendoListCust',
title: '在建过鱼设施-地图锚点',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
bldsttCcode: [{ field: 'bldsttCcode', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/env/fb/point/built/GetKendoListCust',
title: '在建鱼类增殖站',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'FB' }],
bldsttCcode: [{ field: 'bldsttCcode', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/env/fb/point/built/GetKendoListCust',
title: '在建人工产卵场',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'SG' }],
bldsttCcode: [{ field: 'bldsttCcode', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/env/fhvap/built/GetKendoListCust',
title: '珍稀植物园-在建',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'VP' }],
bldsttCcode: [{ field: 'bldsttCcode', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/env/fhvap/built/GetKendoListCust',
title: '动物救助站-在建',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'VA' }],
bldsttCcode: [{ field: 'bldsttCcode', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/eng/eq/eqds/built/GetKendoListCust',
title: '在建生态流量泄放设施',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
BLDSTT_CCODE: [{ field: 'BLDSTT_CCODE', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/env/we/fishList/point/GetKendoList',
title: '鱼类沿程',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/wva/point/GetKendoListCust',
title: '野生动物监测',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'WVA' }]
}
},
{
url: '/wmp-env-server/env/we/fishList/point/GetNativeRareFish',
title: '土著珍稀鱼类',
params: {
rare: '1',
specOrigin: '1',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/te/tet/point/GetTerrestrialAnimal',
title: '陆生动物分布',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/sdFprdR/point/getFprdPointList',
title: '鱼类调查装置',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
}
];

View File

@ -1,7 +1,6 @@
import { defineStore, storeToRefs } from 'pinia'; import { defineStore, storeToRefs } from 'pinia';
import { ref } from 'vue'; import { ref } from 'vue';
import { omit } from 'lodash'; import dayjs from 'dayjs';
import moment from 'moment';
import { MapClass } from '@/components/gis/map.class'; import { MapClass } from '@/components/gis/map.class';
import { applyLayerMutualExclusionRules } from '@/modules/map/domain/map-layer-rules'; import { applyLayerMutualExclusionRules } from '@/modules/map/domain/map-layer-rules';
import { import {
@ -13,7 +12,7 @@ import { useMapConfigStore } from '@/modules/map/stores/map-config.store';
import { useMapDataStore } from '@/modules/map/stores/map-data.store'; import { useMapDataStore } from '@/modules/map/stores/map-data.store';
import { useMapViewStore } from '@/modules/map/stores/map-view.store'; import { useMapViewStore } from '@/modules/map/stores/map-view.store';
import request from '@/utils/request'; import request from '@/utils/request';
import { urlList } from './GisUrlList'; import { urlList } from '@/utils/GisUrlList';
const mapClass = MapClass.getInstance(); const mapClass = MapClass.getInstance();
const DEFAULT_LAYER_REQUEST_CONCURRENCY = 4; const DEFAULT_LAYER_REQUEST_CONCURRENCY = 4;
@ -707,19 +706,19 @@ export const useMapStore = defineStore('map', () => {
'wq_rive_gradient_line' 'wq_rive_gradient_line'
]; // 需要时间搜索的图层key ]; // 需要时间搜索的图层key
let yearTime = moment().subtract(1, 'years'); // 鱼类分布年份 let yearTime = dayjs().subtract(1, 'years'); // 鱼类分布年份
if (timeRangeLayerKeys.includes(layerKey)) { if (timeRangeLayerKeys.includes(layerKey)) {
requestParams.filters.push({ requestParams.filters.push({
field: 'tm', field: 'tm',
operator: 'gte', operator: 'gte',
dataType: 'date', dataType: 'date',
value: moment(searchTimeRange.value[0]).format('YYYY-MM-DD HH:mm:ss') value: dayjs(searchTimeRange.value[0]).format('YYYY-MM-DD HH:mm:ss')
}); });
requestParams.filters.push({ requestParams.filters.push({
field: 'tm', field: 'tm',
operator: 'lte', operator: 'lte',
dataType: 'date', dataType: 'date',
value: moment(searchTimeRange.value[1]).format('YYYY-MM-DD 23:59:59') value: dayjs(searchTimeRange.value[1]).format('YYYY-MM-DD 23:59:59')
}); });
} }
if (spjkz.includes(layerKey)) { if (spjkz.includes(layerKey)) {
@ -737,7 +736,7 @@ export const useMapStore = defineStore('map', () => {
field: 'startTime', field: 'startTime',
operator: 'eq', operator: 'eq',
dataType: 'date', dataType: 'date',
value: moment(yearTime) value: dayjs(yearTime)
.startOf('year') .startOf('year')
.format('YYYY-MM-DD 00:00:00') .format('YYYY-MM-DD 00:00:00')
}); });
@ -745,7 +744,7 @@ export const useMapStore = defineStore('map', () => {
field: 'endTime', field: 'endTime',
operator: 'eq', operator: 'eq',
dataType: 'date', dataType: 'date',
value: moment(yearTime).endOf('year').format('YYYY-MM-DD 23:59:59') value: dayjs(yearTime).endOf('year').format('YYYY-MM-DD 23:59:59')
}); });
} }
} }

View File

@ -1,4 +1,4 @@
import moment from 'moment'; import dayjs from 'dayjs';
// const page =location.href.split('page='); // const page =location.href.split('page=');
// const zaiJianParams = page?.[1]==="zaiJianDianZhanHuanBaoGongZuo"?{bldsttCcode:1}:{} // const zaiJianParams = page?.[1]==="zaiJianDianZhanHuanBaoGongZuo"?{bldsttCcode:1}:{}
// const zaiJianParams2 = page?.[1]==="zaiJianDianZhanHuanBaoGongZuo"?{BLDSTT_CCODE:1}:{} // const zaiJianParams2 = page?.[1]==="zaiJianDianZhanHuanBaoGongZuo"?{BLDSTT_CCODE:1}:{}
@ -262,7 +262,7 @@ export const urlList = [
title: '环保设施告警', title: '环保设施告警',
params: { params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }], lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
yr: moment().format('YYYY') yr: dayjs().format('YYYY')
} }
}, },
{ {

View File

@ -17,8 +17,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import moment from 'moment';
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import BasicSearch from '@/components/BasicSearch/index.vue'; import BasicSearch from '@/components/BasicSearch/index.vue';

View File

@ -66,7 +66,7 @@ import { ref, computed, onMounted } from 'vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import BasicSearch from '@/components/BasicSearch/index.vue'; import BasicSearch from '@/components/BasicSearch/index.vue';
import { DateSetting } from '@/utils/enumeration'; import { DateSetting } from '@/utils/enumeration';
import { useTimeScale } from '@/composables/useTimeScale'; import { useTimeScale } from '@/store/composables/useTimeScale';
import { getFishReleaseMonitorSectionList } from '@/api/DataQueryMenuModule'; import { getFishReleaseMonitorSectionList } from '@/api/DataQueryMenuModule';
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -70,7 +70,7 @@ import { ref, computed, onMounted } from 'vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import BasicSearch from '@/components/BasicSearch/index.vue'; import BasicSearch from '@/components/BasicSearch/index.vue';
import { DateSetting } from '@/utils/enumeration'; import { DateSetting } from '@/utils/enumeration';
import { useTimeScale } from '@/composables/useTimeScale'; import { useTimeScale } from '@/store/composables/useTimeScale';
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'export-btn'): void; (e: 'export-btn'): void;

View File

@ -69,7 +69,7 @@
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import BasicSearch from '@/components/BasicSearch/index.vue'; import BasicSearch from '@/components/BasicSearch/index.vue';
import { DateSetting } from '@/utils/enumeration'; import { DateSetting } from '@/utils/enumeration';
import { useTimeScale } from '@/composables/useTimeScale'; import { useTimeScale } from '@/store/composables/useTimeScale';
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'export-btn'): void; (e: 'export-btn'): void;

View File

@ -69,7 +69,7 @@
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import BasicSearch from '@/components/BasicSearch/index.vue'; import BasicSearch from '@/components/BasicSearch/index.vue';
import { DateSetting } from '@/utils/enumeration'; import { DateSetting } from '@/utils/enumeration';
import { useTimeScale } from '@/composables/useTimeScale'; import { useTimeScale } from '@/store/composables/useTimeScale';
import { getFlowStationSectionList } from '@/api/DataQueryMenuModule'; import { getFlowStationSectionList } from '@/api/DataQueryMenuModule';
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -69,7 +69,7 @@
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import BasicSearch from '@/components/BasicSearch/index.vue'; import BasicSearch from '@/components/BasicSearch/index.vue';
import { DateSetting } from '@/utils/enumeration'; import { DateSetting } from '@/utils/enumeration';
import { useTimeScale } from '@/composables/useTimeScale'; import { useTimeScale } from '@/store/composables/useTimeScale';
import { getSurfaceTempSectionList } from '@/api/DataQueryMenuModule'; import { getSurfaceTempSectionList } from '@/api/DataQueryMenuModule';
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -69,7 +69,7 @@
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import BasicSearch from '@/components/BasicSearch/index.vue'; import BasicSearch from '@/components/BasicSearch/index.vue';
import { DateSetting } from '@/utils/enumeration'; import { DateSetting } from '@/utils/enumeration';
import { useTimeScale } from '@/composables/useTimeScale'; import { useTimeScale } from '@/store/composables/useTimeScale';
import { getSurfaceTempSectionList } from '@/api/DataQueryMenuModule'; import { getSurfaceTempSectionList } from '@/api/DataQueryMenuModule';
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -69,7 +69,7 @@
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import BasicSearch from '@/components/BasicSearch/index.vue'; import BasicSearch from '@/components/BasicSearch/index.vue';
import { DateSetting } from '@/utils/enumeration'; import { DateSetting } from '@/utils/enumeration';
import { useTimeScale } from '@/composables/useTimeScale'; import { useTimeScale } from '@/store/composables/useTimeScale';
import { getWaterDataSectionList } from '@/api/DataQueryMenuModule'; import { getWaterDataSectionList } from '@/api/DataQueryMenuModule';
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -1,491 +0,0 @@
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { useRouter } from 'vue-router';
import { message } from 'ant-design-vue';
import type { FormInstance } from 'ant-design-vue';
import { ArrowLeftOutlined } from '@ant-design/icons-vue';
import { useUserStore } from '@/store/modules/user';
import { encrypt } from '@/utils/rsaEncrypt';
import {
updatePassword,
} from "@/api/changePassWord";
const router = useRouter();
const userStore = useUserStore();
//
const formRef = ref<FormInstance>();
//
const submitting = ref(false);
//
interface ChangePasswordForm {
oldPassword: string;
newPassword: string;
confirmPassword: string;
}
const formState = reactive<ChangePasswordForm>({
oldPassword: '',
newPassword: '',
confirmPassword: ''
});
// ==================== ====================
/**
* 校验密码复杂度至少包含四类字符中的三类
*/
const checkComplexity = (password: string): { valid: boolean; message: string } => {
let count = 0;
const hasUpper = /[A-Z]/.test(password);
const hasLower = /[a-z]/.test(password);
const hasNumber = /[0-9]/.test(password);
const hasSpecial = /[^A-Za-z0-9]/.test(password);
if (hasUpper) count++;
if (hasLower) count++;
if (hasNumber) count++;
if (hasSpecial) count++;
if (count >= 3) {
return { valid: true, message: '' };
}
return {
valid: false,
message: '密码必须包含大写字母、小写字母、数字、特殊字符中的至少三类'
};
};
/**
* 校验连续重复字符
*/
const checkConsecutiveRepeat = (password: string): { valid: boolean; message: string } => {
for (let i = 0; i < password.length - 1; i++) {
if (password[i] === password[i + 1]) {
return {
valid: false,
message: '密码不能包含2位及以上相同字符的连续重复如11、aa'
};
}
}
return { valid: true, message: '' };
};
/**
* 校验连续递增/递减数字
*/
const checkConsecutiveNumbers = (password: string): { valid: boolean; message: string } => {
for (let i = 0; i < password.length - 1; i++) {
const curr = password.charCodeAt(i);
const next = password.charCodeAt(i + 1);
//
if (curr >= 48 && curr <= 57 && next >= 48 && next <= 57) {
if (Math.abs(next - curr) === 1) {
return {
valid: false,
message: '密码不能包含2位及以上连续递增或递减的数字如12、21'
};
}
}
}
return { valid: true, message: '' };
};
/**
* 校验连续递增/递减字母
*/
const checkConsecutiveLetters = (password: string): { valid: boolean; message: string } => {
for (let i = 0; i < password.length - 1; i++) {
const curr = password.charCodeAt(i);
const next = password.charCodeAt(i + 1);
//
const isCurrLetter = (curr >= 65 && curr <= 90) || (curr >= 97 && curr <= 122);
const isNextLetter = (next >= 65 && next <= 90) || (next >= 97 && next <= 122);
if (isCurrLetter && isNextLetter) {
if (Math.abs(next - curr) === 1) {
return {
valid: false,
message: '密码不能包含2位及以上连续递增或递减的字母如ab、ba'
};
}
}
}
return { valid: true, message: '' };
};
/**
* 校验用户名关联
*/
const checkUsernameRelation = (password: string, username: string): { valid: boolean; message: string } => {
if (!username) {
return { valid: true, message: '' };
}
const lowerPassword = password.toLowerCase();
const lowerUsername = username.toLowerCase();
if (lowerPassword.includes(lowerUsername)) {
return {
valid: false,
message: '密码不能包含用户名或其核心部分'
};
}
return { valid: true, message: '' };
};
// ==================== ====================
const rules = {
oldPassword: [
{ required: true, message: '请输入旧密码', trigger: 'blur' }
],
newPassword: [
{ required: true, message: '请输入新密码', trigger: 'blur' },
{ min: 10, message: '密码长度不能少于10位', trigger: 'blur' },
{
validator: async (_rule: any, value: string) => {
if (!value) {
return Promise.resolve();
}
//
const complexity = checkComplexity(value);
if (!complexity.valid) {
return Promise.reject(new Error(complexity.message));
}
//
const repeat = checkConsecutiveRepeat(value);
if (!repeat.valid) {
return Promise.reject(new Error(repeat.message));
}
//
const numbers = checkConsecutiveNumbers(value);
if (!numbers.valid) {
return Promise.reject(new Error(numbers.message));
}
//
const letters = checkConsecutiveLetters(value);
if (!letters.valid) {
return Promise.reject(new Error(letters.message));
}
//
const username = userStore.username || '';
const usernameCheck = checkUsernameRelation(value, username);
if (!usernameCheck.valid) {
return Promise.reject(new Error(usernameCheck.message));
}
return Promise.resolve();
},
trigger: 'blur'
}
],
confirmPassword: [
{ required: true, message: '请再次输入新密码', trigger: 'blur' },
{
validator: async (_rule: any, value: string) => {
if (!value) {
return Promise.resolve();
}
if (value !== formState.newPassword) {
return Promise.reject(new Error('两次输入的密码不一致'));
}
return Promise.resolve();
},
trigger: 'blur'
}
]
};
// ==================== ====================
/**
* 修改密码接口待补充实际后端接口
* @param oldPassword 旧密码已加密
* @param newPassword 新密码已加密
*/
// const changePasswordApi = async (oldPassword: string, newPassword: string) => {
// // TODO: API
// //
// // return request({
// // url: '/user/changePassword',
// // method: 'post',
// // data: { oldPassword, newPassword }
// // });
// //
// return new Promise((resolve) => {
// setTimeout(() => {
// resolve({ code: 0, msg: '' });
// }, 1000);
// });
// };
// ==================== ====================
/**
* 提交表单
*/
const handleSubmit = async () => {
try {
//
await formRef.value?.validate();
submitting.value = true;
// RSA
const encryptedOldPassword = encrypt(formState.oldPassword);
const encryptedNewPassword = encrypt(formState.newPassword);
if (!encryptedOldPassword || !encryptedNewPassword) {
message.error('密码加密失败');
return;
}
//
const res: any = await updatePassword({id:userStore.userid,password:encryptedNewPassword,oldPassword:encryptedOldPassword});
//
if (res.code === 0 || res.code === '0') {
message.success('密码修改成功,请重新登录');
// token
userStore.resetToken();
//
setTimeout(() => {
router.push('/login');
}, 1500);
} else {
message.error(res.msg || '密码修改失败');
}
} catch (error: any) {
if (error.errorFields) {
//
message.error('请检查表单填写是否正确');
} else {
//
message.error(error.message || '密码修改失败,请稍后重试');
}
} finally {
submitting.value = false;
}
};
/**
* 重置表单
*/
const handleReset = () => {
formRef.value?.resetFields();
formState.oldPassword = '';
formState.newPassword = '';
formState.confirmPassword = '';
};
/**
* 返回上一页
*/
const handleBack = () => {
router.back();
};
</script>
<template>
<div class="change-password-container">
<a-card :bordered="false" class="password-card">
<!-- 标题区域 -->
<div class="card-header">
<a-button type="text" @click="handleBack" class="back-btn">
<ArrowLeftOutlined />
</a-button>
<h2 class="card-title">修改密码</h2>
</div>
<a-form ref="formRef" :model="formState" :rules="rules" layout="vertical" class="password-form">
<!-- 旧密码 -->
<a-form-item label="旧密码" name="oldPassword">
<a-input-password v-model:value="formState.oldPassword" placeholder="请输入旧密码" size="large"
allow-clear />
</a-form-item>
<!-- 新密码 -->
<a-form-item label="新密码" name="newPassword" :dependencies="['username']">
<a-input-password v-model:value="formState.newPassword" placeholder="请输入新密码" size="large"
allow-clear />
</a-form-item>
<!-- 确认新密码 -->
<a-form-item label="确认新密码" name="confirmPassword">
<a-input-password v-model:value="formState.confirmPassword" placeholder="请再次输入新密码" size="large"
allow-clear />
</a-form-item>
<!-- 按钮区域 -->
<a-form-item class="button-group">
<a-button type="primary" size="large" @click="handleSubmit" :loading="submitting"
class="submit-btn">
提交
</a-button>
<a-button size="large" @click="handleReset" class="reset-btn">
重置
</a-button>
</a-form-item>
</a-form>
</a-card>
</div>
</template>
<style scoped lang="scss">
.change-password-container {
min-height: calc(100vh - 110px);
display: flex;
justify-content: center;
align-items: center;
padding: 40px 20px;
background-color: #fff;
}
.password-card {
width: 100%;
max-width: 500px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
border-radius: 8px;
.card-header {
display: flex;
align-items: center;
padding: 16px 0px;
border-bottom: 2px solid #005293;
.back-btn {
font-size: 18px;
color: #005293;
padding: 4px 8px;
margin-right: 12px;
&:hover {
color: #003d6e;
background-color: rgba(0, 82, 147, 0.1);
}
}
.card-title {
margin: 0;
font-size: 20px;
font-weight: 600;
color: #005293;
}
}
:deep(.ant-card-body) {
padding: 32px;
}
}
.password-form {
:deep(.ant-form-item-label) {
label {
font-weight: 500;
color: #333;
}
}
:deep(.ant-input-password) {
border-radius: 4px;
&:hover {
border-color: #005293;
}
&:focus {
border-color: #005293;
box-shadow: 0 0 0 2px rgba(0, 82, 147, 0.2);
}
}
}
.password-tips {
margin-top: 8px;
padding: 12px;
background-color: #f5f7fa;
border-left: 3px solid #005293;
border-radius: 4px;
font-size: 13px;
color: #666;
line-height: 1.8;
p {
margin: 0 0 8px 0;
font-weight: 500;
color: #333;
}
ul {
margin: 0;
padding-left: 0;
list-style: none;
li {
margin: 4px 0;
}
}
}
.button-group {
margin-top: 24px;
margin-bottom: 0;
.submit-btn {
width: 120px;
margin-right: 16px;
background-color: #005293;
border-color: #005293;
&:hover {
background-color: #003d6e;
border-color: #003d6e;
}
}
.reset-btn {
width: 120px;
}
}
//
@media (max-width: 768px) {
.change-password-container {
padding: 20px 10px;
}
.password-card {
:deep(.ant-card-body) {
padding: 24px 16px;
}
}
.button-group {
display: flex;
flex-direction: column;
gap: 12px;
.submit-btn,
.reset-btn {
width: 100%;
margin-right: 0;
}
}
}
</style>

View File

@ -1,114 +1,48 @@
<!-- setup 无法设置组件名称组件名称keepAlive必须 -->
<script lang="ts">
export default {
name: 'Page401'
};
</script>
<script setup lang="ts">
import { reactive, toRefs } from 'vue';
import { useRouter } from 'vue-router';
const state = reactive({
errGif: new URL(`../../assets/401_images/401.gif`, import.meta.url).href,
ewizardClap:
'https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646',
dialogVisible: false
});
const { errGif, ewizardClap, dialogVisible } = toRefs(state);
const router = useRouter();
function back() {
router.back();
}
</script>
<template> <template>
<div class="errPage-container"> <div class="error-page-container">
<el-button icon="el-icon-arrow-left" class="pan-back-btn" @click="back"> <a-result
返回 status="403"
</el-button> title="401"
<el-row> sub-title="抱歉,您没有权限访问该页面,请尝试重新登录或联系管理员"
<el-col :span="12"> >
<h1 class="text-jumbo text-ginormous">Oops!</h1> <template #extra>
gif来源<a href="https://zh.airbnb.com/" target="_blank">airbnb</a> 页面 <a-space>
<h2>你没有权限去该页面</h2> <a-button type="primary" @click="goHome">
<h6>如有不满请联系你领导</h6> <template #icon><home-outlined /></template>
<ul class="list-unstyled"> 回首页
<li>或者你可以去:</li> </a-button>
<li class="link-type"> </a-space>
<router-link to="/"> 回首页 </router-link> </template>
</li> </a-result>
<li class="link-type">
<a href="https://www.taobao.com/">随便看看</a>
</li>
<li>
<a href="#" @click.prevent="dialogVisible = true">点我看图</a>
</li>
</ul>
</el-col>
<el-col :span="12">
<img
:src="errGif"
width="313"
height="428"
alt="Girl has dropped her ice cream."
/>
</el-col>
</el-row>
<el-dialog v-model="dialogVisible" title="随便看">
<img :src="ewizardClap" class="pan-img" />
</el-dialog>
</div> </div>
</template> </template>
<style lang="scss" scoped> <script setup lang="ts">
.errPage-container { import { useRouter } from 'vue-router';
width: 800px; import { HomeOutlined, ReloadOutlined } from '@ant-design/icons-vue';
max-width: 100%;
margin: 100px auto;
.pan-back-btn { const router = useRouter();
background: #008489;
color: #fff;
border: none !important;
}
.pan-gif { // permission
margin: 0 auto; const goHome = () => {
display: block; router.push('/');
} };
</script>
.pan-img { <style scoped>
display: block; .error-page-container {
margin: 0 auto; height: 100vh;
width: 100%; display: flex;
} justify-content: center;
align-items: center;
background: #f0f2f5;
}
.text-jumbo { /* 调整 Result 组件样式,使其更美观 */
font-size: 60px; .error-page-container :deep(.ant-result) {
font-weight: 700; padding: 48px 32px;
color: #484848; background: #fff;
} border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
.list-unstyled {
font-size: 14px;
li {
padding-bottom: 5px;
}
a {
color: #008489;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
} }
</style> </style>

View File

@ -1,280 +1,47 @@
<!-- setup 无法设置组件名称组件名称keepAlive必须 -->
<script lang="ts">
export default {
name: 'Page404'
};
</script>
<script setup lang="ts">
function message() {
return 'The webmaster said that you can not enter this page...';
}
</script>
<template> <template>
<div class="wscn-http404-container"> <div class="error-page-container">
<div class="wscn-http404"> <a-result
<div class="pic-404"> status="404"
<img title="404"
class="pic-404__parent" sub-title="抱歉,您访问的页面不存在,请检查网址或返回首页"
src="@/assets/404_images/404.png"
alt="404"
/>
<img
class="pic-404__child left"
src="@/assets/404_images/404_cloud.png"
alt="404"
/>
<img
class="pic-404__child mid"
src="@/assets/404_images/404_cloud.png"
alt="404"
/>
<img
class="pic-404__child right"
src="@/assets/404_images/404_cloud.png"
alt="404"
/>
</div>
<div class="bullshit">
<div class="bullshit__oops">OOPS!</div>
<div class="bullshit__info">
All rights reserved
<a
style="color: #20a0ff"
href="https://wallstreetcn.com"
target="_blank"
>wallstreetcn</a
> >
</div> <template #extra>
<div class="bullshit__headline">{{ message }}</div> <a-space>
<div class="bullshit__info"> <a-button type="primary" @click="goHome">
Please check that the URL you entered is correct, or click the button <template #icon><home-outlined /></template>
below to return to the homepage. 回首页
</div> </a-button>
<a href="" class="bullshit__return-home">Back to home</a> </a-space>
</div> </template>
</div> </a-result>
</div> </div>
</template> </template>
<style lang="scss" scoped> <script setup lang="ts">
.wscn-http404-container { import { useRouter } from 'vue-router';
transform: translate(-50%, -50%); import { HomeOutlined, ReloadOutlined } from '@ant-design/icons-vue';
position: absolute;
top: 40%; const router = useRouter();
left: 50%;
// permission
const goHome = () => {
router.push('/');
};
</script>
<style scoped>
.error-page-container {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: #f0f2f5;
} }
.wscn-http404 { .error-page-container :deep(.ant-result) {
position: relative; padding: 48px 32px;
width: 1200px; background: #fff;
padding: 0 50px; border-radius: 8px;
overflow: hidden; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
.pic-404 {
position: relative;
float: left;
width: 600px;
overflow: hidden;
&__parent {
width: 100%;
}
&__child {
position: absolute;
&.left {
width: 80px;
top: 17px;
left: 220px;
opacity: 0;
animation-name: cloudLeft;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
&.mid {
width: 46px;
top: 10px;
left: 420px;
opacity: 0;
animation-name: cloudMid;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1.2s;
}
&.right {
width: 62px;
top: 100px;
left: 500px;
opacity: 0;
animation-name: cloudRight;
animation-duration: 2s;
animation-timing-function: linear;
animation-fill-mode: forwards;
animation-delay: 1s;
}
@keyframes cloudLeft {
0% {
top: 17px;
left: 220px;
opacity: 0;
}
20% {
top: 33px;
left: 188px;
opacity: 1;
}
80% {
top: 81px;
left: 92px;
opacity: 1;
}
100% {
top: 97px;
left: 60px;
opacity: 0;
}
}
@keyframes cloudMid {
0% {
top: 10px;
left: 420px;
opacity: 0;
}
20% {
top: 40px;
left: 360px;
opacity: 1;
}
70% {
top: 130px;
left: 180px;
opacity: 1;
}
100% {
top: 160px;
left: 120px;
opacity: 0;
}
}
@keyframes cloudRight {
0% {
top: 100px;
left: 500px;
opacity: 0;
}
20% {
top: 120px;
left: 460px;
opacity: 1;
}
80% {
top: 180px;
left: 340px;
opacity: 1;
}
100% {
top: 200px;
left: 300px;
opacity: 0;
}
}
}
}
.bullshit {
position: relative;
float: left;
width: 300px;
padding: 30px 0;
overflow: hidden;
&__oops {
font-size: 32px;
font-weight: bold;
line-height: 40px;
color: #1482f0;
opacity: 0;
margin-bottom: 20px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
&__headline {
font-size: 20px;
line-height: 24px;
color: #222;
font-weight: bold;
opacity: 0;
margin-bottom: 10px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.1s;
animation-fill-mode: forwards;
}
&__info {
font-size: 13px;
line-height: 21px;
color: grey;
opacity: 0;
margin-bottom: 30px;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.2s;
animation-fill-mode: forwards;
}
&__return-home {
display: block;
float: left;
width: 110px;
height: 36px;
background: #1482f0;
border-radius: 100px;
text-align: center;
color: #ffffff;
opacity: 0;
font-size: 14px;
line-height: 36px;
cursor: pointer;
animation-name: slideUp;
animation-duration: 0.5s;
animation-delay: 0.3s;
animation-fill-mode: forwards;
}
@keyframes slideUp {
0% {
transform: translateY(60px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
}
} }
</style> </style>

View File

@ -1,10 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from "vue"; import { onMounted, ref } from 'vue';
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue"; import JidiSelectorMod from '@/modules/jidiSelectorMod.vue';
import RightDrawer from "@/components/RightDrawer/index.vue"; import RightDrawer from '@/components/RightDrawer/index.vue';
import jidiInfoMod from "@/modules/jidiInfoMod/index.vue"; import jidiInfoMod from '@/modules/jidiInfoMod/index.vue';
import shuidianhuangjingjieruMod from "@/modules/shuidianhuangjingjieruMod/index.vue"; import shuidianhuangjingjieruMod from '@/modules/shuidianhuangjingjieruMod/index.vue';
import { useModelStore } from "@/store/modules/model"; import { useModelStore } from '@/store/modules/model';
const modelStore = useModelStore(); const modelStore = useModelStore();
// import { getQgcStaticData } from "@/api/ecoFlow"; // import { getQgcStaticData } from "@/api/ecoFlow";
@ -27,111 +27,111 @@ onMounted(() => {
const showMapModal = () => { const showMapModal = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "ENG"; modelStore.params.sttp = 'ENG';
modelStore.title = "三峡 "; modelStore.title = '三峡 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal1 = () => { const showMapModal1 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "WT"; modelStore.params.sttp = 'WT';
modelStore.title = "水温 "; modelStore.title = '水温 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal2 = () => { const showMapModal2 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "WQFB"; modelStore.params.sttp = 'WQFB';
modelStore.title = "水质 "; modelStore.title = '水质 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal3 = () => { const showMapModal3 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "FH"; modelStore.params.sttp = 'FH';
modelStore.title = "栖息地 "; modelStore.title = '栖息地 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
};// }; //
const showMapModal4 = () => { const showMapModal4 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "fh_zq_point"; modelStore.params.sttp = 'fh_zq_point';
modelStore.title = "栖息地流量 "; modelStore.title = '栖息地流量 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal5 = () => { const showMapModal5 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "fp_point"; modelStore.params.sttp = 'fp_point';
modelStore.title = "过鱼设施 "; modelStore.title = '过鱼设施 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal6 = () => { const showMapModal6 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "FB"; modelStore.params.sttp = 'FB';
modelStore.title = "鱼类增殖站 "; modelStore.title = '鱼类增殖站 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
// //
const showMapModal7 = () => { const showMapModal7 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "VA"; modelStore.params.sttp = 'VA';
modelStore.title = "动物救助站 "; modelStore.title = '动物救助站 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal8 = () => { const showMapModal8 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "VP"; modelStore.params.sttp = 'VP';
modelStore.title = "珍稀植物园 "; modelStore.title = '珍稀植物园 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal9 = () => { const showMapModal9 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "WE"; modelStore.params.sttp = 'WE';
modelStore.title = "水生生态调查断面 "; modelStore.title = '水生生态调查断面 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal10 = () => { const showMapModal10 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "WVA"; modelStore.params.sttp = 'WVA';
modelStore.title = "野生动物监测 "; modelStore.title = '野生动物监测 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal11 = () => { const showMapModal11 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "VD_FBFM"; modelStore.params.sttp = 'VD_FBFM';
modelStore.title = "AI视频监控站 "; modelStore.title = 'AI视频监控站 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal12 = () => { const showMapModal12 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "eng_alarm_point"; modelStore.params.sttp = 'eng_alarm_point';
modelStore.title = "水电站告警情况 "; modelStore.title = '水电站告警情况 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal13 = () => { const showMapModal13 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "FPRD"; modelStore.params.sttp = 'FPRD';
modelStore.title = "鱼类调查装置 "; modelStore.title = '鱼类调查装置 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal14 = () => { const showMapModal14 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "DW_2"; modelStore.params.sttp = 'DW_2';
modelStore.title = "低温水减缓设施-叠梁门 "; modelStore.title = '低温水减缓设施-叠梁门 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal15 = () => { const showMapModal15 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "DW_5"; modelStore.params.sttp = 'DW_5';
modelStore.title = "前置挡墙 "; modelStore.title = '前置挡墙 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal16 = () => { const showMapModal16 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "DW_6"; modelStore.params.sttp = 'DW_6';
modelStore.title = "隔水幕墙 "; modelStore.title = '隔水幕墙 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
const showMapModal17 = () => { const showMapModal17 = () => {
modelStore.modalVisible = true; modelStore.modalVisible = true;
modelStore.params.sttp = "DW_1"; modelStore.params.sttp = 'DW_1';
modelStore.title = "夹岩双层取水 "; modelStore.title = '夹岩双层取水 ';
modelStore.isBasicEdit = true; modelStore.isBasicEdit = true;
}; };
//DW_5 //DW_5

View File

@ -246,15 +246,13 @@ import { UserOutlined, LockOutlined, MobileOutlined } from "@ant-design/icons-vu
import { getCaptcha } from "@/api/auth"; import { getCaptcha } from "@/api/auth";
import { message } from "ant-design-vue"; import { message } from "ant-design-vue";
// //
import router from "@/router"; import router from "@/router";
import Cookies from "js-cookie";
// API // API
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { LoginData } from "@/api/auth/types"; import { LoginData } from "@/api/auth/types";
// //
import { encrypt, decrypt } from "@/utils/rsaEncrypt"; import { encrypt } from "@/utils/rsaEncrypt";
// //
import { useUserStore } from "@/store/modules/user"; import { useUserStore } from "@/store/modules/user";

View File

@ -25,7 +25,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import moment from 'moment'; import dayjs from 'dayjs';
import { ref, computed, onMounted, watch } from 'vue'; import { ref, computed, onMounted, watch } from 'vue';
import BasicSearch from '@/components/BasicSearch/index.vue'; import BasicSearch from '@/components/BasicSearch/index.vue';
@ -50,7 +50,7 @@ const btnLoading = ref<boolean>(false);
const initSearchData = { const initSearchData = {
rvcd: 'all', rvcd: 'all',
stcd: null, stcd: null,
reportMonth: moment().subtract(1, 'month').format('YYYY-MM') reportMonth: dayjs().subtract(1, 'month').format('YYYY-MM')
}; };
const searchData = ref<any>({ ...initSearchData }); const searchData = ref<any>({ ...initSearchData });

View File

@ -338,7 +338,6 @@ const videoFileList = ref<any[]>([]);
// //
const disabledDate = (current: any) => { const disabledDate = (current: any) => {
// current moment/dayjs
// true // true
return current && current > dayjs().endOf('day'); return current && current > dayjs().endOf('day');
}; };
@ -370,7 +369,7 @@ const getHbrvcdDropdownSelect = async () => {
const res = await getSelectForDropdown({}); const res = await getSelectForDropdown({});
let list = res.data || []; let list = res.data || [];
if (list && list.length > 0) { if (list && list.length > 0) {
list = list.filter((item: any) => item.rvcd !== "all"); list = list.filter((item: any) => item.rvcd !== 'all');
} }
hbrvcdOption.value = list; hbrvcdOption.value = list;
} catch (error) { } catch (error) {
@ -469,13 +468,13 @@ const filterOption = (inputValue: string, option: any) => {
}; };
// //
const rules: Record<string, Rule[]> = { const rules: Record<string, Rule[]> = {
rvcd: [{ required: true, message: "请选择流域", trigger: "change" }], rvcd: [{ required: true, message: '请选择流域', trigger: 'change' }],
rstcd: [{ required: true, message: "请选择电站", trigger: "change" }], rstcd: [{ required: true, message: '请选择电站', trigger: 'change' }],
stcd: [{ required: true, message: "请选择过鱼设施", trigger: "change" }], stcd: [{ required: true, message: '请选择过鱼设施', trigger: 'change' }],
strdt: [{ required: true, message: "请选择过鱼时间", trigger: "change" }], strdt: [{ required: true, message: '请选择过鱼时间', trigger: 'change' }],
ftp: [{ required: true, message: "请选择鱼种类", trigger: "change" }], ftp: [{ required: true, message: '请选择鱼种类', trigger: 'change' }],
direction: [{ required: true, message: "请选择游向", trigger: "change" }], direction: [{ required: true, message: '请选择游向', trigger: 'change' }],
fcnt: [{ required: true, message: "请输入过鱼数量", trigger: "change" }], fcnt: [{ required: true, message: '请输入过鱼数量', trigger: 'change' }]
}; };
// //