10 changed files with 1129 additions and 19 deletions
@ -0,0 +1,4 @@ |
|||
package com.zdxt.enforcementcode.controller.app; |
|||
|
|||
public class LoginController { |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
import { _get, _post, _form, _delete } from "../../http/index"; |
|||
|
|||
// region 监督端接口
|
|||
|
|||
let supervisionAppBaseUrl = "/app-sup"; |
|||
|
|||
// 监督端用户登录
|
|||
export const supervisionLogin = (params, success, error) => _post(supervisionAppBaseUrl + "/login/do", params, success, error); |
|||
|
|||
// endregion
|
|||
@ -0,0 +1,23 @@ |
|||
|
|||
const routes = [ |
|||
// 监督端登录
|
|||
{ |
|||
path: "/supervision/login", |
|||
name: "supervisionLogin", |
|||
component: () => import("@/views/supervision/login.vue"), |
|||
meta: { |
|||
isKeepAlive: false, |
|||
}, |
|||
}, |
|||
// 监督端首页
|
|||
{ |
|||
path: "/supervision/supervisionHome", |
|||
name: "supervisionHome", |
|||
component: () => import("@/views/supervision/supervisionHomeV2.vue"), |
|||
meta: { |
|||
isKeepAlive: false, |
|||
}, |
|||
}, |
|||
]; |
|||
|
|||
export {routes}; |
|||
@ -1,11 +1,134 @@ |
|||
<template> |
|||
<div class="login-page"> |
|||
<div class="login-content"> |
|||
<van-nav-bar> |
|||
<template #title> |
|||
<div class="title"> |
|||
监督端登录 |
|||
</div> |
|||
</template> |
|||
</van-nav-bar> |
|||
<van-form @submit="onSubmit"> |
|||
<van-field v-model="loginParam.secretName" name="secretName" label="用户名" placeholder="用户名" |
|||
:rules="[{ required: true, message: '请填写用户名' }]"/> |
|||
<van-field v-model="loginParam.secretKey" type="password" name="secretKey" label="密码" placeholder="密码" |
|||
:rules="[{ required: true, message: '请填写密码' }]"/> |
|||
<div style="margin: 0.42rem"> |
|||
<van-button block type="primary" native-type="submit">登录</van-button> |
|||
</div> |
|||
</van-form> |
|||
<div style="margin: 0.42rem 0.42rem 0; text-align: center;"> |
|||
<van-button plain type="default" size="small" @click="showTestPicker = true" style="background-color: darkred;color: white">选择测试用户</van-button> |
|||
</div> |
|||
<van-action-sheet v-model:show="showTestPicker" title="选择测试用户"> |
|||
<div class="test-enterprise-list"> |
|||
<van-cell |
|||
v-for="(item, index) in testUsers" |
|||
:key="index" |
|||
:title="item.name" |
|||
:label="'账号:' + item.account" |
|||
is-link |
|||
@click="selectTestUser(item)" |
|||
/> |
|||
</div> |
|||
</van-action-sheet> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
import {reactive, ref} from 'vue'; |
|||
import {supervisionLogin} from '../../api/supervision'; |
|||
import CryptoJS from "crypto-js"; |
|||
import {showFailToast} from 'vant'; |
|||
import 'vant/es/toast/style'; |
|||
|
|||
const {useCommon} = $globalStore; |
|||
const router = useRouter(); |
|||
const loginParam = reactive({ |
|||
secretName: "", |
|||
secretKey: "" |
|||
}) |
|||
|
|||
const showTestPicker = ref(false); |
|||
const testUsers = [ |
|||
{ account: 'admin', name: '管理员', password: '123456' }, |
|||
]; |
|||
|
|||
const selectTestUser = (item) => { |
|||
loginParam.secretName = item.account; |
|||
loginParam.secretKey = item.password; |
|||
showTestPicker.value = false; |
|||
// 直接触发登录 |
|||
doLogin(item.account, item.password); |
|||
} |
|||
|
|||
const doLogin = (secretName, secretKey) => { |
|||
const encryptedKey = Encrypt(secretKey); |
|||
supervisionLogin({"secretName": secretName, "secretKey": encryptedKey}, response => { |
|||
if (response.code === 200) { |
|||
// 监督端登录成功 → 赋值用户基本信息 |
|||
useCommon.SET_USER_PHONENUMBER(response.data.phonenumber.toString()); |
|||
useCommon.SET_USER_ID(response.data.userId); |
|||
useCommon.SET_TOKEN(response.data.token); |
|||
useCommon.SET_ORG_ID(response.data.deptId || ""); |
|||
console.log("supervision login success", useCommon.userId); |
|||
router.push({name: "supervisionHome"}); |
|||
} else { |
|||
showFailToast(response.msg || "登录失败"); |
|||
} |
|||
}, error => { |
|||
showFailToast(error?.msg || "登录失败,请检查网络"); |
|||
}) |
|||
}; |
|||
|
|||
const onSubmit = async () => { |
|||
doLogin(loginParam.secretName, loginParam.secretKey); |
|||
}; |
|||
|
|||
const Encrypt = (passWord) => { |
|||
var keyStr = '1234567898745621'; |
|||
var ivStr = keyStr; |
|||
var key = CryptoJS.enc.Utf8.parse(keyStr); |
|||
var iv = CryptoJS.enc.Utf8.parse(ivStr); |
|||
var srcs = CryptoJS.enc.Utf8.parse(passWord); |
|||
var encrypted = CryptoJS.AES.encrypt(srcs, key, { |
|||
iv: iv, |
|||
mode: CryptoJS.mode.CBC, |
|||
padding: CryptoJS.pad.ZeroPadding |
|||
}); |
|||
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext); |
|||
} |
|||
</script> |
|||
|
|||
<template> |
|||
<style lang="less" scoped> |
|||
.login-page { |
|||
width: 100%; |
|||
height: 100%; |
|||
display: flex; |
|||
overflow: hidden; |
|||
background-image: url("~@/assets/images/login.jpg"); |
|||
background-repeat: no-repeat; |
|||
background-size: cover; |
|||
opacity: 0.9; |
|||
|
|||
</template> |
|||
.login-content { |
|||
margin: auto; |
|||
padding: 0.27rem 0.27rem 0.52rem 0.27rem; |
|||
background-color: #fff; |
|||
border-radius: 0.27rem; |
|||
box-shadow: 0 0 0.27rem rgba(0, 0, 0, 0.2); |
|||
opacity: 0.9; |
|||
|
|||
<style scoped lang="less"> |
|||
.title { |
|||
font-size: 0.52rem; |
|||
font-weight: 600; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.test-enterprise-list { |
|||
max-height: 60vh; |
|||
overflow-y: auto; |
|||
padding: 0.2rem; |
|||
} |
|||
</style> |
|||
|
|||
@ -0,0 +1,822 @@ |
|||
<template> |
|||
<div class="home app_content"> |
|||
<!-- 顶部蓝色背景区域 --> |
|||
<div class="header-bg"> |
|||
<div class="orbit-line"></div> |
|||
<div class="orbit-line"></div> |
|||
<div class="cityscape"></div> |
|||
|
|||
<!-- 盾牌图标 --> |
|||
<div class="shield-wrapper"> |
|||
<div class="shield"> |
|||
<div class="shield-icon"> |
|||
<div class="shield-text">执法<br>监督</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 监督端标签 --> |
|||
<div class="supervision-tag">监督端</div> |
|||
|
|||
<!-- 标语 --> |
|||
<div class="slogan"> |
|||
<span class="white-text">执法受监督</span> |
|||
<span class="gold-text">入企须扫码</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 内容区域 --> |
|||
<div class="content-area"> |
|||
<!-- 通知栏 --> |
|||
<div class="notice-bar" v-if="noticeVisible"> |
|||
<div class="notice-icon-wrap"> |
|||
<svg class="notice-icon" viewBox="0 0 24 24" fill="currentColor"> |
|||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/> |
|||
</svg> |
|||
</div> |
|||
<span class="notice-text">深圳市司法局2026年第二季度行政执法监督计划</span> |
|||
<div class="notice-close" @click="noticeVisible = false"> |
|||
<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"> |
|||
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> |
|||
</svg> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 轮播图 --> |
|||
<div class="banner-card"> |
|||
<van-swipe :autoplay="3000" indicator-color="rgba(255,255,255,0.9)" :loop="true"> |
|||
<van-swipe-item v-for="(item, index) in bannerList" :key="index"> |
|||
<div class="banner-inner"> |
|||
<img v-if="item.image" :src="item.image" class="banner-img" alt="" /> |
|||
<div v-else class="banner-placeholder"> |
|||
<div class="banner-text-group"> |
|||
<span class="banner-year">{{ item.year }}</span> |
|||
<span class="banner-subtitle">{{ item.subtitle }}</span> |
|||
</div> |
|||
<div class="banner-main-title">{{ item.title }}</div> |
|||
<div class="banner-tag" v-if="item.tag">{{ item.tag }}</div> |
|||
</div> |
|||
</div> |
|||
</van-swipe-item> |
|||
</van-swipe> |
|||
</div> |
|||
|
|||
<!-- 执法监督 + 投诉举报 双卡片行 --> |
|||
<div class="card-row"> |
|||
<!-- 执法监督 --> |
|||
<div class="scan-card"> |
|||
<div class="scan-card-label">执法监督</div> |
|||
<div class="scan-card-body"> |
|||
<div class="scan-card-icon"> |
|||
<div class="scan-icon-main"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"> |
|||
<circle cx="11" cy="11" r="8"/> |
|||
<path d="m21 21-4.35-4.35"/> |
|||
<line x1="11" y1="8" x2="11" y2="14"/> |
|||
<line x1="8" y1="11" x2="14" y2="11"/> |
|||
</svg> |
|||
</div> |
|||
<div class="scan-icon-check"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"> |
|||
<polyline points="20 6 9 17 4 12"/> |
|||
</svg> |
|||
</div> |
|||
</div> |
|||
<div class="scan-card-text">监督检查</div> |
|||
</div> |
|||
<!-- 背景装饰 --> |
|||
<div class="scan-card-bg-decor"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"> |
|||
<circle cx="11" cy="11" r="8"/> |
|||
<path d="m21 21-4.35-4.35"/> |
|||
</svg> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 投诉举报 --> |
|||
<div class="scan-card scan-card--orange"> |
|||
<div class="scan-card-label scan-card-label--orange">投诉举报</div> |
|||
<div class="scan-card-body"> |
|||
<div class="scan-card-icon"> |
|||
<div class="scan-icon-main scan-icon-main--orange"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"> |
|||
<path d="M4 4h16v12H5.17L4 17.17V4z" /> |
|||
<line x1="8" y1="9" x2="16" y2="9"/> |
|||
<line x1="8" y1="12" x2="13" y2="12"/> |
|||
</svg> |
|||
</div> |
|||
<div class="scan-icon-check scan-icon-check--orange"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"> |
|||
<polyline points="20 6 9 17 4 12"/> |
|||
</svg> |
|||
</div> |
|||
</div> |
|||
<div class="scan-card-text">投诉举报</div> |
|||
</div> |
|||
<!-- 背景装饰 --> |
|||
<div class="scan-card-bg-decor scan-card-bg-decor--orange"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"> |
|||
<path d="M4 4h16v12H5.17L4 17.17V4z" /> |
|||
<line x1="8" y1="9" x2="16" y2="9"/> |
|||
</svg> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 监督记录 + 统计分析 双卡片行 --> |
|||
<div class="card-row"> |
|||
<!-- 监督记录 --> |
|||
<div class="info-card info-card--teal"> |
|||
<div class="info-card-icon"> |
|||
<div class="info-icon-main info-icon-main--teal"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"> |
|||
<rect x="3" y="3" width="18" height="18" rx="2"/> |
|||
<line x1="7" y1="8" x2="17" y2="8"/> |
|||
<line x1="7" y1="12" x2="14" y2="12"/> |
|||
<line x1="7" y1="16" x2="11" y2="16"/> |
|||
</svg> |
|||
</div> |
|||
<div class="info-icon-check info-icon-check--teal"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"> |
|||
<polyline points="20 6 9 17 4 12"/> |
|||
</svg> |
|||
</div> |
|||
</div> |
|||
<div class="info-card-text">监督记录</div> |
|||
<!-- 背景装饰 --> |
|||
<div class="info-card-bg-decor"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"> |
|||
<rect x="3" y="3" width="18" height="18" rx="2"/> |
|||
<line x1="7" y1="8" x2="17" y2="8"/> |
|||
<line x1="7" y1="12" x2="14" y2="12"/> |
|||
</svg> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 统计分析 --> |
|||
<div class="info-card info-card--green"> |
|||
<div class="info-card-icon"> |
|||
<div class="info-icon-main info-icon-main--green"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"> |
|||
<rect x="3" y="4" width="18" height="16" rx="2"/> |
|||
<line x1="7" y1="16" x2="7" y2="10"/> |
|||
<line x1="11" y1="16" x2="11" y2="8"/> |
|||
<line x1="15" y1="16" x2="15" y2="12"/> |
|||
<path d="M6 11 Q9 7 12 9 Q15 11 18 7"/> |
|||
</svg> |
|||
</div> |
|||
<div class="info-icon-check info-icon-check--green"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"> |
|||
<polyline points="20 6 9 17 4 12"/> |
|||
</svg> |
|||
</div> |
|||
</div> |
|||
<div class="info-card-text">统计分析</div> |
|||
<!-- 背景装饰 --> |
|||
<div class="info-card-bg-decor info-card-bg-decor--green"> |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"> |
|||
<rect x="3" y="4" width="18" height="16" rx="2"/> |
|||
<line x1="7" y1="16" x2="7" y2="10"/> |
|||
<line x1="11" y1="16" x2="11" y2="8"/> |
|||
<line x1="15" y1="16" x2="15" y2="12"/> |
|||
</svg> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 底部导航栏 --> |
|||
<div class="footer-bar"> |
|||
<div class="footer-item footer-item--active"> |
|||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg> |
|||
<span>首页</span> |
|||
</div> |
|||
<div class="footer-item"> |
|||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg> |
|||
<span>查询</span> |
|||
</div> |
|||
<div class="footer-item"> |
|||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"/></svg> |
|||
<span>消息</span> |
|||
</div> |
|||
<div class="footer-item"> |
|||
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg> |
|||
<span>我的</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup name="supervisionHome"> |
|||
|
|||
const noticeVisible = ref(true); |
|||
|
|||
// ========== 轮播图数据 ========== |
|||
const bannerList = ref([ |
|||
{ year: '2026', subtitle: '法治课堂', title: '潮起深圳 领航出海', tag: '4月活动预告', image: '', link: '' }, |
|||
{ year: '2026', subtitle: '执法监督', title: '阳光执法 规范行为', tag: '', image: '', link: '' }, |
|||
{ year: '2026', subtitle: '营商环境', title: '优化服务 提质增效', tag: '', image: '', link: '' }, |
|||
]); |
|||
|
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
.home { |
|||
display: flex; |
|||
flex-direction: column; |
|||
height: 100%; |
|||
overflow: hidden; |
|||
background: #f0f6ff; |
|||
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif; |
|||
} |
|||
|
|||
/* ===== 顶部蓝色背景区域 ===== */ |
|||
.header-bg { |
|||
background: linear-gradient(180deg, #2b7de9 0%, #5ba3f5 40%, #a0cdf8 70%, #dceefb 90%, #eef5ff 100%); |
|||
padding: 20px 20px 20px; |
|||
text-align: center; |
|||
position: relative; |
|||
overflow: hidden; |
|||
flex-shrink: 0; |
|||
|
|||
&::after { |
|||
content: ''; |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
height: 80px; |
|||
background: linear-gradient(180deg, transparent, rgba(255,255,255,0.3)); |
|||
} |
|||
} |
|||
|
|||
/* 城市天际线装饰 */ |
|||
.cityscape { |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
height: 120px; |
|||
opacity: 0.15; |
|||
background: linear-gradient(0deg, rgba(255,255,255,0.5) 0%, transparent 100%); |
|||
|
|||
&::before { |
|||
content: ''; |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 5%; |
|||
width: 8%; |
|||
height: 60px; |
|||
background: rgba(255,255,255,0.4); |
|||
border-radius: 2px 2px 0 0; |
|||
} |
|||
|
|||
&::after { |
|||
content: ''; |
|||
position: absolute; |
|||
bottom: 0; |
|||
right: 15%; |
|||
width: 6%; |
|||
height: 100px; |
|||
background: rgba(255,255,255,0.3); |
|||
border-radius: 2px 2px 0 0; |
|||
box-shadow: |
|||
-30px 20px 0 rgba(255,255,255,0.25), |
|||
-55px 35px 0 rgba(255,255,255,0.2), |
|||
30px 40px 0 rgba(255,255,255,0.2), |
|||
60px 15px 0 rgba(255,255,255,0.15); |
|||
} |
|||
} |
|||
|
|||
/* 轨道线装饰 */ |
|||
.orbit-line { |
|||
position: absolute; |
|||
top: 50%; |
|||
left: 50%; |
|||
transform: translate(-50%, -50%); |
|||
width: 200px; |
|||
height: 120px; |
|||
border: 1.5px solid rgba(255,255,255,0.2); |
|||
border-radius: 50%; |
|||
z-index: 0; |
|||
|
|||
&:nth-child(2) { |
|||
width: 260px; |
|||
height: 155px; |
|||
border-color: rgba(255,255,255,0.12); |
|||
} |
|||
} |
|||
|
|||
/* 盾牌图标 */ |
|||
.shield-wrapper { |
|||
position: relative; |
|||
z-index: 1; |
|||
margin-bottom: 8px; |
|||
} |
|||
|
|||
.shield { |
|||
display: inline-block; |
|||
width: 90px; |
|||
height: 100px; |
|||
position: relative; |
|||
} |
|||
|
|||
.shield-icon { |
|||
width: 90px; |
|||
height: 100px; |
|||
background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); |
|||
clip-path: polygon(50% 0%, 100% 20%, 100% 65%, 50% 100%, 0% 65%, 0% 20%); |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
flex-direction: column; |
|||
color: white; |
|||
font-size: 18px; |
|||
font-weight: bold; |
|||
letter-spacing: 4px; |
|||
text-shadow: 0 1px 3px rgba(0,0,0,0.2); |
|||
|
|||
&::before { |
|||
content: ''; |
|||
position: absolute; |
|||
inset: 3px; |
|||
background: linear-gradient(135deg, #60a5fa 0%, #2563eb 100%); |
|||
clip-path: polygon(50% 2%, 98% 21%, 98% 64%, 50% 98%, 2% 64%, 2% 21%); |
|||
z-index: -1; |
|||
} |
|||
} |
|||
|
|||
.shield-text { |
|||
line-height: 1.3; |
|||
margin-top: 12px; |
|||
} |
|||
|
|||
/* 监督端标签 */ |
|||
.supervision-tag { |
|||
display: inline-block; |
|||
background: linear-gradient(135deg, #2563eb, #1d4ed8); |
|||
color: white; |
|||
padding: 5px 22px; |
|||
border-radius: 4px; |
|||
font-size: 15px; |
|||
font-weight: 500; |
|||
letter-spacing: 2px; |
|||
margin: 6px 0 12px; |
|||
position: relative; |
|||
z-index: 1; |
|||
} |
|||
|
|||
/* 标语 */ |
|||
.slogan { |
|||
position: relative; |
|||
z-index: 1; |
|||
font-size: 22px; |
|||
font-weight: bold; |
|||
letter-spacing: 3px; |
|||
|
|||
.white-text { |
|||
color: #ffffff; |
|||
text-shadow: 0 1px 4px rgba(0,0,0,0.15); |
|||
} |
|||
|
|||
.gold-text { |
|||
color: #fbbf24; |
|||
text-shadow: 0 1px 4px rgba(0,0,0,0.15); |
|||
} |
|||
} |
|||
|
|||
/* ===== 内容区域 ===== */ |
|||
.content-area { |
|||
padding: 0 16px; |
|||
margin-top: -10px; |
|||
position: relative; |
|||
z-index: 2; |
|||
flex: 1; |
|||
overflow-y: auto; |
|||
padding-bottom: 16px; |
|||
} |
|||
|
|||
/* 通知栏 */ |
|||
.notice-bar { |
|||
background: #ffffff; |
|||
border-radius: 12px; |
|||
padding: 14px 16px; |
|||
margin-bottom: 14px; |
|||
display: flex; |
|||
align-items: center; |
|||
box-shadow: 0 2px 12px rgba(0,0,0,0.06); |
|||
|
|||
.notice-icon-wrap { |
|||
width: 40px; |
|||
height: 40px; |
|||
min-width: 40px; |
|||
background: linear-gradient(135deg, #e0edff, #c8ddf8); |
|||
border-radius: 10px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin-right: 12px; |
|||
} |
|||
|
|||
.notice-icon { |
|||
width: 22px; |
|||
height: 22px; |
|||
color: #3b82f6; |
|||
} |
|||
|
|||
.notice-text { |
|||
flex: 1; |
|||
font-size: 14px; |
|||
color: #333; |
|||
line-height: 1.4; |
|||
} |
|||
|
|||
.notice-close { |
|||
width: 24px; |
|||
height: 24px; |
|||
min-width: 24px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
color: #c0c0c0; |
|||
margin-left: 8px; |
|||
cursor: pointer; |
|||
|
|||
svg { |
|||
width: 16px; |
|||
height: 16px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* 轮播图 */ |
|||
.banner-card { |
|||
border-radius: 16px; |
|||
overflow: hidden; |
|||
margin-bottom: 14px; |
|||
position: relative; |
|||
box-shadow: 0 2px 12px rgba(0,0,0,0.06); |
|||
} |
|||
|
|||
.banner-inner { |
|||
width: 100%; |
|||
height: 180px; |
|||
background: linear-gradient(135deg, #c8e2f8 0%, #a0c8f0 30%, #7bb3e8 60%, #5a9de0 100%); |
|||
position: relative; |
|||
overflow: hidden; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.banner-img { |
|||
width: 100%; |
|||
height: 100%; |
|||
object-fit: cover; |
|||
} |
|||
|
|||
.banner-placeholder { |
|||
width: 100%; |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
padding: 24px; |
|||
|
|||
.banner-text-group { |
|||
display: flex; |
|||
align-items: baseline; |
|||
gap: 8px; |
|||
margin-bottom: 6px; |
|||
} |
|||
|
|||
.banner-year { |
|||
font-size: 28px; |
|||
font-weight: 900; |
|||
color: #d97706; |
|||
letter-spacing: 1px; |
|||
} |
|||
|
|||
.banner-subtitle { |
|||
font-size: 18px; |
|||
font-weight: 600; |
|||
color: #d97706; |
|||
letter-spacing: 2px; |
|||
} |
|||
|
|||
.banner-main-title { |
|||
font-size: 24px; |
|||
color: #1a1a2e; |
|||
font-weight: 800; |
|||
letter-spacing: 4px; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.banner-tag { |
|||
display: inline-block; |
|||
background: linear-gradient(135deg, #f59e0b, #d97706); |
|||
color: #fff; |
|||
padding: 4px 16px; |
|||
border-radius: 20px; |
|||
font-size: 13px; |
|||
font-weight: 500; |
|||
align-self: center; |
|||
} |
|||
} |
|||
|
|||
:deep(.van-swipe__indicator) { |
|||
width: 8px; |
|||
height: 8px; |
|||
border-radius: 4px; |
|||
background: rgba(255, 255, 255, 0.5); |
|||
transition: all 0.3s; |
|||
} |
|||
|
|||
:deep(.van-swipe__indicator--active) { |
|||
width: 20px; |
|||
background: rgba(255, 255, 255, 0.9); |
|||
} |
|||
|
|||
/* ===== 卡片行 ===== */ |
|||
.card-row { |
|||
display: flex; |
|||
gap: 12px; |
|||
margin-bottom: 14px; |
|||
} |
|||
|
|||
/* 功能卡片(蓝色默认) */ |
|||
.scan-card { |
|||
flex: 1; |
|||
background: linear-gradient(135deg, #eaf3ff 0%, #d6eaff 60%, #c8e0f8 100%); |
|||
border-radius: 16px; |
|||
padding: 0 16px 18px; |
|||
position: relative; |
|||
overflow: hidden; |
|||
min-height: 150px; |
|||
box-shadow: 0 2px 12px rgba(0,0,0,0.05); |
|||
|
|||
.scan-card-label { |
|||
display: inline-block; |
|||
background: linear-gradient(135deg, #3b82f6, #2563eb); |
|||
color: #fff; |
|||
font-size: 12px; |
|||
font-weight: 500; |
|||
padding: 4px 12px; |
|||
border-radius: 0 0 8px 8px; |
|||
margin-bottom: 12px; |
|||
letter-spacing: 1px; |
|||
} |
|||
|
|||
.scan-card-body { |
|||
position: relative; |
|||
z-index: 1; |
|||
} |
|||
|
|||
.scan-card-icon { |
|||
width: 60px; |
|||
height: 60px; |
|||
position: relative; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.scan-icon-main { |
|||
width: 60px; |
|||
height: 60px; |
|||
background: linear-gradient(135deg, #3b82f6, #2563eb); |
|||
border-radius: 16px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
box-shadow: 0 4px 12px rgba(37,99,235,0.3); |
|||
|
|||
svg { |
|||
width: 32px; |
|||
height: 32px; |
|||
color: white; |
|||
} |
|||
} |
|||
|
|||
.scan-icon-check { |
|||
position: absolute; |
|||
bottom: -4px; |
|||
right: -4px; |
|||
width: 24px; |
|||
height: 24px; |
|||
background: linear-gradient(135deg, #60a5fa, #3b82f6); |
|||
border-radius: 50%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
border: 2px solid #eaf3ff; |
|||
|
|||
svg { |
|||
width: 12px; |
|||
height: 12px; |
|||
color: white; |
|||
} |
|||
} |
|||
|
|||
.scan-card-text { |
|||
font-size: 15px; |
|||
color: #1a1a2e; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.scan-card-bg-decor { |
|||
position: absolute; |
|||
bottom: 8px; |
|||
right: 0; |
|||
width: 80px; |
|||
height: 80px; |
|||
opacity: 0.1; |
|||
color: #3b82f6; |
|||
|
|||
svg { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* 橙色卡片变体(投诉举报) */ |
|||
.scan-card--orange { |
|||
background: linear-gradient(135deg, #fff7ed 0%, #ffedd5 60%, #fed7aa 100%); |
|||
|
|||
.scan-card-label--orange { |
|||
background: linear-gradient(135deg, #f59e0b, #d97706); |
|||
} |
|||
|
|||
.scan-icon-main--orange { |
|||
background: linear-gradient(135deg, #f59e0b, #d97706); |
|||
box-shadow: 0 4px 12px rgba(217,119,6,0.3); |
|||
} |
|||
|
|||
.scan-icon-check--orange { |
|||
background: linear-gradient(135deg, #fbbf24, #f59e0b); |
|||
border-color: #fff7ed; |
|||
} |
|||
|
|||
.scan-card-bg-decor--orange { |
|||
color: #d97706; |
|||
} |
|||
} |
|||
|
|||
/* 信息卡片(监督记录 / 统计分析) */ |
|||
.info-card { |
|||
flex: 1; |
|||
border-radius: 16px; |
|||
padding: 18px 16px; |
|||
position: relative; |
|||
overflow: hidden; |
|||
min-height: 130px; |
|||
box-shadow: 0 2px 12px rgba(0,0,0,0.05); |
|||
|
|||
.info-card-icon { |
|||
position: relative; |
|||
width: 60px; |
|||
height: 60px; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.info-card-text { |
|||
font-size: 15px; |
|||
color: #1a1a2e; |
|||
font-weight: 600; |
|||
position: relative; |
|||
z-index: 1; |
|||
} |
|||
|
|||
.info-card-bg-decor { |
|||
position: absolute; |
|||
bottom: 8px; |
|||
right: 0; |
|||
width: 80px; |
|||
height: 80px; |
|||
opacity: 0.1; |
|||
color: #0d9488; |
|||
|
|||
svg { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* 青色(监督记录) */ |
|||
.info-card--teal { |
|||
background: linear-gradient(135deg, #e8faf7 0%, #ccf0ea 60%, #b2e6de 100%); |
|||
} |
|||
|
|||
.info-icon-main--teal { |
|||
width: 60px; |
|||
height: 60px; |
|||
background: linear-gradient(135deg, #14b8a6, #0d9488); |
|||
border-radius: 16px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
box-shadow: 0 4px 12px rgba(13,148,136,0.3); |
|||
|
|||
svg { |
|||
width: 32px; |
|||
height: 32px; |
|||
color: white; |
|||
} |
|||
} |
|||
|
|||
.info-icon-check--teal { |
|||
position: absolute; |
|||
bottom: -4px; |
|||
right: -4px; |
|||
width: 24px; |
|||
height: 24px; |
|||
background: linear-gradient(135deg, #2dd4bf, #14b8a6); |
|||
border-radius: 50%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
border: 2px solid #e8faf7; |
|||
|
|||
svg { |
|||
width: 12px; |
|||
height: 12px; |
|||
color: white; |
|||
} |
|||
} |
|||
|
|||
/* 绿色(统计分析) */ |
|||
.info-card--green { |
|||
background: linear-gradient(135deg, #e8faf0 0%, #c6f0da 60%, #a8e6c8 100%); |
|||
} |
|||
|
|||
.info-icon-main--green { |
|||
width: 60px; |
|||
height: 60px; |
|||
background: linear-gradient(135deg, #10b981, #059669); |
|||
border-radius: 16px; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
box-shadow: 0 4px 12px rgba(5,150,105,0.3); |
|||
|
|||
svg { |
|||
width: 32px; |
|||
height: 32px; |
|||
color: white; |
|||
} |
|||
} |
|||
|
|||
.info-icon-check--green { |
|||
position: absolute; |
|||
bottom: -4px; |
|||
right: -4px; |
|||
width: 24px; |
|||
height: 24px; |
|||
background: linear-gradient(135deg, #34d399, #10b981); |
|||
border-radius: 50%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
border: 2px solid #e8faf0; |
|||
|
|||
svg { |
|||
width: 12px; |
|||
height: 12px; |
|||
color: white; |
|||
} |
|||
} |
|||
|
|||
.info-card-bg-decor--green { |
|||
color: #059669; |
|||
} |
|||
|
|||
/* ===== 底部导航栏 ===== */ |
|||
.footer-bar { |
|||
flex-shrink: 0; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-around; |
|||
background: #fff; |
|||
padding: 8px 0; |
|||
padding-bottom: calc(8px + env(safe-area-inset-bottom)); |
|||
box-shadow: 0 -2px 12px rgba(0,0,0,0.06); |
|||
|
|||
.footer-item { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
gap: 3px; |
|||
color: #999; |
|||
font-size: 11px; |
|||
|
|||
svg { |
|||
width: 24px; |
|||
height: 24px; |
|||
} |
|||
|
|||
&--active { |
|||
color: #3b82f6; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,4 +1,4 @@ |
|||
# 监督端开发环境 |
|||
VITE_PORT = 12003 |
|||
VITE_BASE_URL = 'http://localhost:17000/sup-ep' |
|||
VITE_DEFAULT_LOGIN = '/enforce/login' |
|||
VITE_DEFAULT_LOGIN = '/supervision/login' |
|||
|
|||
Loading…
Reference in new issue