Merge branch 'main' of http://175.6.124.250:3100/luozhun/policeSecurity
|
@ -1,3 +1,10 @@
|
|||
# 配置文档参考 https://taro-docs.jd.com/docs/next/env-mode-config
|
||||
TARO_APP_ID="wx0acd1c4fcf94bdd3"
|
||||
# TARO_APP_BASE_API="http://172.10.10.93:8765"
|
||||
TARO_APP_BASE_API="http://172.10.10.93:8765"
|
||||
|
||||
|
||||
|
||||
# minio
|
||||
TARO_APP_MINIO_URL=http://118.253.177.137:9000
|
||||
TARO_APP_MINIO_BUCKET=police-security-dev
|
||||
|
|
|
@ -1 +1,6 @@
|
|||
# TARO_APP_ID="生产环境下的小程序appid"
|
||||
# TARO_APP_ID="wx0acd1c4fcf94bdd3"
|
||||
TARO_APP_BASE_API="https://www.hnjinglian.cn:5678"
|
||||
|
||||
# minio
|
||||
TARO_APP_MINIO_URL=https://www.hnjinglian.cn:9002
|
||||
TARO_APP_MINIO_BUCKET=police-security
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
# TARO_APP_ID="测试环境下的小程序appid"
|
|
@ -5,11 +5,14 @@
|
|||
"appid": "touristappid",
|
||||
"setting": {
|
||||
"urlCheck": false,
|
||||
"es6": false,
|
||||
"es6": true,
|
||||
"enhance": false,
|
||||
"minified": true,
|
||||
"minifyWXSS": true,
|
||||
"minifyWXML": true,
|
||||
"compileHotReLoad": false,
|
||||
"postcss": false,
|
||||
"minified": false
|
||||
"postcss": true,
|
||||
"minified": true
|
||||
},
|
||||
"compileType": "miniprogram"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {MINI_PROGRAM_USER_CONFIG} from "@/config";
|
||||
import { MINI_PROGRAM_USER_CONFIG } from "@/config";
|
||||
|
||||
|
||||
const tabBarItems = Object.values(MINI_PROGRAM_USER_CONFIG).map(item => item.tabBarList).flat()
|
||||
|
@ -17,14 +17,24 @@ export default defineAppConfig({
|
|||
'myProject/projectDetails/projectDetails',
|
||||
'securityUserForm/securityUserForm',
|
||||
]
|
||||
}, {
|
||||
},
|
||||
{
|
||||
root: "subPages/police",
|
||||
pages: [
|
||||
'dailyInspection/dailyInspection',
|
||||
'myEnterprisesUnit/myEnterprisesUnit',
|
||||
'myEnterprisesUnit/projectDetails/projectDetails'
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
root: "subPages/select",
|
||||
pages: [
|
||||
'dailyLife/dailyLife',
|
||||
'signature/signature'
|
||||
]
|
||||
},
|
||||
],
|
||||
|
||||
window: {
|
||||
backgroundTextStyle: 'light',
|
||||
navigationBarBackgroundColor: '#4e87ff',
|
||||
|
|
|
@ -24,6 +24,40 @@ const App = createApp({
|
|||
})
|
||||
}
|
||||
},
|
||||
onShow(){
|
||||
const updateManager = Taro.getUpdateManager()
|
||||
updateManager.onCheckForUpdate(function(res) {
|
||||
// 请求完新版本信息的回调
|
||||
if (res.hasUpdate) {
|
||||
// 新版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate()
|
||||
}
|
||||
})
|
||||
updateManager.onUpdateReady(function() {
|
||||
// 新版本已经准备好,可以提示用户更新
|
||||
Taro.showModal({
|
||||
title: '更新提示',
|
||||
content: '发现新版本,是否重启应用?',
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
// 新的版本已经准备好,调用 applyUpdate 应用新版本
|
||||
updateManager.applyUpdate()
|
||||
}
|
||||
}
|
||||
}).then(res=>{
|
||||
console.log(res)
|
||||
})
|
||||
})
|
||||
updateManager.onUpdateFailed(function() {
|
||||
// 新版本下载失败,可进行一些提示用户的操作
|
||||
Taro.showModal({
|
||||
title: '已有新版本',
|
||||
content: '请删除当前小程序,重新从搜索界面打开获取最新版本',
|
||||
}).then(res => {
|
||||
console.log(res)
|
||||
})
|
||||
})
|
||||
}
|
||||
// 入口组件不需要实现 render 方法,即使实现了也会被 taro 所覆盖
|
||||
})
|
||||
|
||||
|
|
Before Width: | Height: | Size: 500 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 1.2 KiB |
|
@ -20,7 +20,7 @@ export const MINI_PROGRAM_USER_CONFIG: Record<MiniProgramUserIdentity, UserConfi
|
|||
},
|
||||
{
|
||||
pagePath: 'pages/police/mine/index',
|
||||
text: '警察我的',
|
||||
text: '我的',
|
||||
iconPath: "assets/mine/my.png",
|
||||
selectedIconPath: "assets/mine/my-active.png"
|
||||
},
|
||||
|
@ -37,7 +37,7 @@ export const MINI_PROGRAM_USER_CONFIG: Record<MiniProgramUserIdentity, UserConfi
|
|||
},
|
||||
{
|
||||
pagePath: 'pages/projectManager/mine/index',
|
||||
text: '项目经理我的',
|
||||
text: '我的',
|
||||
iconPath: "assets/mine/my.png",
|
||||
selectedIconPath: "assets/mine/my-active.png"
|
||||
},
|
||||
|
|
|
@ -1,47 +1,76 @@
|
|||
.nameTitle {
|
||||
position: absolute;
|
||||
top: 19%;
|
||||
left: 55px;
|
||||
height: 125rpx;
|
||||
background-color: #fff;
|
||||
width: 650rpx;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0px 10px 10px -4px #e3e3e3;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.itemSchool {
|
||||
border-right: solid 1.5rpx #dadada;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 25%;
|
||||
font-size: 24px
|
||||
}
|
||||
|
||||
.itemSchool text:nth-child(1) {
|
||||
margin-bottom: 10rpx;
|
||||
color: #898a8a;
|
||||
margin-left: -8px;
|
||||
}
|
||||
}
|
||||
.nameTitle .itemSchool:nth-child(4) {
|
||||
border-right: none;
|
||||
}
|
||||
.swiperDemoItem {
|
||||
color: #3886d0;
|
||||
display: flex;
|
||||
padding: 20px 0 0 50px;
|
||||
overflow: hidden;
|
||||
height: 70rpx;
|
||||
margin-top: 70px;
|
||||
|
||||
.swiperDemoIndex {
|
||||
width: 15px;
|
||||
height: 45px;
|
||||
background-image: linear-gradient(to bottom, #5d9cf9, #317ad9);
|
||||
//background: rgb();
|
||||
border-radius: 20px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.subModule {
|
||||
.Module {
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
.subModule {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-right: -3px;
|
||||
margin-left: -1px;
|
||||
|
||||
.subModuleItem {
|
||||
width: 33%;
|
||||
height: 180rpx;
|
||||
width: 246rpx;
|
||||
height: 140rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 10rpx;
|
||||
border: 1px solid #ccc;
|
||||
border-left: 0;
|
||||
margin-top: -1px;
|
||||
|
||||
.subModuleIndex {
|
||||
width: 65rpx;
|
||||
height: 65rpx;
|
||||
|
||||
width: 45rpx;
|
||||
height: 45rpx;
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
.swiperDemoItem {
|
||||
color: #3886d0;
|
||||
display: flex;
|
||||
padding: 20px 0 0 50px;
|
||||
overflow: hidden;
|
||||
height: 70rpx;
|
||||
|
||||
.swiperDemoIndex {
|
||||
width: 15px;
|
||||
height: 45px;
|
||||
background-image: linear-gradient(to bottom, #5d9cf9, #317ad9);
|
||||
//background: rgb();
|
||||
border-radius: 20px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.subModule {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-right: -3px;
|
||||
margin-left: -1px;
|
||||
|
||||
.subModuleItem {
|
||||
width: 33%;
|
||||
height: 180rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 10rpx;
|
||||
border: 1px solid #ccc;
|
||||
border-left: 0;
|
||||
margin-top: -1px;
|
||||
|
||||
.subModuleIndex {
|
||||
width: 65rpx;
|
||||
height: 65rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,56 +3,114 @@
|
|||
<view class="swiperDemo">
|
||||
<nut-swiper ref="swiperRef" pagination-visible pagination-color="#e53e31" :auto-play="3000" :init-page="0">
|
||||
<nut-swiper-item v-for="(item, index) in list" :key="index" style="height: 180px">
|
||||
<image src="@/assets/images/01.png" alt="" style="height: 100%; width: 100%" draggable="false"/>
|
||||
<image :src="item" alt="" style="height: 100%; width: 100%" draggable="false" />
|
||||
</nut-swiper-item>
|
||||
</nut-swiper>
|
||||
</view>
|
||||
<view class="nameTitle">
|
||||
<view class="itemSchool">
|
||||
<text>单位数量</text>
|
||||
<text style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 80px; text-align: center">{{ numberStatistics.enterprisesUnitCount }}</text>
|
||||
</view>
|
||||
<view class="itemSchool">
|
||||
<text>服务项目</text>
|
||||
<text>
|
||||
{{ numberStatistics.serviceProjectCount }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="itemSchool">
|
||||
<text>有保安证人员</text>
|
||||
<text>{{ numberStatistics.securityUserCount }}</text>
|
||||
</view>
|
||||
<view class="itemSchool">
|
||||
<text>无保安证人员</text>
|
||||
<text>{{ numberStatistics.noCardSecurityUserCount }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="swiperDemoItem">
|
||||
<view class="swiperDemoIndex"></view>
|
||||
<view>请选择</view>
|
||||
</view>
|
||||
<!--九宫格-->
|
||||
<view>
|
||||
<view class="Module">
|
||||
<view class="subModule">
|
||||
<view class="subModuleItem" v-for="item in subModuleList" :key="item.id" @click="subNavigation(item.url)">
|
||||
<view class="subModuleIndex">
|
||||
<image :src="item.icon"></image>
|
||||
</view>
|
||||
<view style=" font-size: 12px;color: #414141;margin-top: 9px">{{ item.name }}</view>
|
||||
<view style="font-size: 12px; color: #414141; margin-top: 5px">{{ item.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view style="background-color: #e9eef4; height: 15rpx"></view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {ref} from 'vue'
|
||||
import Taro from "@tarojs/taro";
|
||||
import { onMounted, ref } from 'vue'
|
||||
import Taro from '@tarojs/taro'
|
||||
import icon from '@/assets/images/project.png'
|
||||
import icon01 from '@/assets/images/回单.jpg'
|
||||
import icon02 from '@/assets/images/工单.jpg'
|
||||
import icon03 from '@/assets/images/排名.jpg'
|
||||
import icon04 from '@/assets/images/法制宣传.jpg'
|
||||
import icon06 from '@/assets/images/警保风采.jpg'
|
||||
import './index.scss'
|
||||
|
||||
const list = ref(['https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',])
|
||||
import api from '@/request'
|
||||
import { DataStatisticsRes } from '@/types/pages/police'
|
||||
const list = ref([process.env.TARO_APP_MINIO_URL + '/police-security/2024/11/5/dunpai.jpg'])
|
||||
const swiperRef = ref() //轮播图
|
||||
const subModuleList = ref([
|
||||
{
|
||||
id: 0,
|
||||
icon: icon,
|
||||
name: '企事业单位',
|
||||
url: '/subPages/police/myEnterprisesUnit/myEnterprisesUnit'
|
||||
name: '项目管理',
|
||||
url: '/subPages/police/myEnterprisesUnit/myEnterprisesUnit',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
icon: icon,
|
||||
name: '警保风采',
|
||||
url: ''
|
||||
icon: icon02,
|
||||
name: '监督考核',
|
||||
url: '/subPages/police/dailyInspection/dailyInspection',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
icon: icon,
|
||||
name: '待定',
|
||||
url: ''
|
||||
}
|
||||
icon: icon03,
|
||||
name: '考核排名',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
icon: icon06,
|
||||
name: '警保风采',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
icon: icon04,
|
||||
name: '法制宣传',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
icon: icon01,
|
||||
name: '整改回单',
|
||||
url: '',
|
||||
},
|
||||
])
|
||||
|
||||
const subNavigation = async (url: string) => Taro.navigateTo({url})
|
||||
const numberStatistics = ref<DataStatisticsRes>({
|
||||
enterprisesUnitCount: 0,
|
||||
serviceProjectCount: 0,
|
||||
securityUserCount: 0,
|
||||
noCardSecurityUserCount: 0,
|
||||
})
|
||||
const dataStatistics = async () => {
|
||||
const resp = await api.get<DataStatisticsRes>('/policeIndex/dataStatistics')
|
||||
numberStatistics.value = resp.data as DataStatisticsRes
|
||||
}
|
||||
onMounted(async () => {
|
||||
await dataStatistics()
|
||||
})
|
||||
|
||||
const subNavigation = async (url: string) => Taro.navigateTo({ url })
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<view class="search" id="search">
|
||||
<nut-input v-model="valueInput" @input="searchInput" placeholder="请进行搜索"></nut-input>
|
||||
<view v-if="valueInput">
|
||||
<ul>
|
||||
<li v-for="item in searchResults" :key="item.id">{{item}}</li>
|
||||
</ul>
|
||||
</view>
|
||||
<view v-else >
|
||||
没有找到相关结果
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {onMounted, ref,} from "vue";
|
||||
const valueInput = ref('')
|
||||
const list = ref([])
|
||||
const dataList = ref([
|
||||
{
|
||||
id:0,
|
||||
value:'齐家园'
|
||||
},
|
||||
{
|
||||
id:1,
|
||||
value:'刘德华'
|
||||
},
|
||||
{
|
||||
id:2,
|
||||
value:'张学友'
|
||||
},{
|
||||
id:3,
|
||||
value:'黎明'
|
||||
},
|
||||
{
|
||||
id:4,
|
||||
value:'家具城'
|
||||
},
|
||||
{
|
||||
id:5,
|
||||
value:'左岸春天'
|
||||
},
|
||||
{
|
||||
id:6,
|
||||
value:'麦德龙商城'
|
||||
},
|
||||
{
|
||||
id:7,
|
||||
value:'世纪酒店'
|
||||
},
|
||||
{
|
||||
id:8,
|
||||
value:'四方小学'
|
||||
},
|
||||
{
|
||||
id:9,
|
||||
value:'海洋半岛'
|
||||
},
|
||||
{
|
||||
id:10,
|
||||
value:'育英小学'
|
||||
},
|
||||
{
|
||||
id:11,
|
||||
value:'明德小学'
|
||||
},{
|
||||
id:12,
|
||||
value:'希望小学',
|
||||
}
|
||||
])
|
||||
const searchResults = ref([])
|
||||
const searchInput = (e:any)=>{
|
||||
valueInput.value = e.target.value
|
||||
if (!valueInput.value) {
|
||||
searchResults.value = []
|
||||
return;
|
||||
}else{
|
||||
searchResults.value = list.value.filter(item =>
|
||||
item.toLowerCase().includes(valueInput.value.toLowerCase())
|
||||
);
|
||||
}
|
||||
}
|
||||
onMounted(()=>{
|
||||
dataList.value.map((item)=>{
|
||||
return list.value.push(item.value)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<style scoped lang="scss">
|
||||
.search{
|
||||
padding: 0 10px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #4e71f2;
|
||||
margin: 1px 5px;
|
||||
border-radius: 10px;
|
||||
width: 30%;
|
||||
.ceShi{
|
||||
height: 300px;
|
||||
background: #ccc;
|
||||
}
|
||||
}
|
||||
.nut-input{
|
||||
padding: 20rpx 20rpx;
|
||||
margin: 5px 0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,71 @@
|
|||
.public {
|
||||
height: 100vh;
|
||||
background-color: #fff;
|
||||
}
|
||||
.public-container {
|
||||
height: 320rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-image: url('../../../assets/images/banner.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: right;
|
||||
overflow: hidden;
|
||||
padding: 45rpx;
|
||||
box-sizing: border-box;
|
||||
.contacts {
|
||||
height: 75rpx;
|
||||
width: 75rpx;
|
||||
border-radius: 50%;
|
||||
border: solid 1px gray;
|
||||
.image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.tips-text {
|
||||
display: flex;
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
line-height: 50rpx;
|
||||
margin-left: 20rpx;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
}
|
||||
.exit {
|
||||
height: 100rpx;
|
||||
line-height: 40px;
|
||||
border-bottom: solid 0.5px #ebebf7;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: #7d7d7d;
|
||||
.exitItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 30rpx;
|
||||
}
|
||||
.exitItemIndex {
|
||||
height: 40rpx;
|
||||
width: 40rpx;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
line-height: 48rpx;
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.microscope {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
display: inline-block;
|
||||
border: solid 2px #ccc;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
border-bottom: white;
|
||||
border-left: white;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,80 @@
|
|||
<template>
|
||||
<view>
|
||||
警察我的
|
||||
<view class="public">
|
||||
<!-- 公安-->
|
||||
<view class="public-container" >
|
||||
<view class="contacts">
|
||||
<image src="@/assets/logo/avatar1.png" mode="scaleToFill" class="image" />
|
||||
</view>
|
||||
<view class="tips-text">
|
||||
<view style="font-size: 15px;">名字</view>
|
||||
<view style="font-size: 12px;">
|
||||
<text style="margin-right: 5px">部门 </text>
|
||||
<text>未选择单位</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 用户信息 -->
|
||||
<view class="userIndex">
|
||||
<view class="exit" v-for="item in datalist" :key="item.value" @click="addExit(item.value)">
|
||||
<view class="exitItem">
|
||||
<!-- <view class="exitItemIndex">-->
|
||||
<!-- <image :src="item.url" mode="scaleToFill" class="image" />-->
|
||||
<!-- </view>-->
|
||||
<text style="margin-left: 30rpx;font-size: 12px;">{{ item.name }}</text>
|
||||
</view>
|
||||
<view style="margin-right: 40rpx">
|
||||
<text class="microscope"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 退出弹框-->
|
||||
<nut-dialog
|
||||
content="是否退出登录?"
|
||||
v-model:visible="visible" @cancel="visible = false" @ok="onOk"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import './index.scss'
|
||||
import {ref} from "vue";
|
||||
import {useUserStore} from "@/store/userStore";
|
||||
import {useTabBarStore} from "@/store/tabBarStore"
|
||||
import Taro from "@tarojs/taro";
|
||||
|
||||
const {setSelected} = useTabBarStore()
|
||||
const {resetUserInfo} = useUserStore()
|
||||
const visible = ref<boolean>(false)
|
||||
const datalist = ref([
|
||||
{
|
||||
value: 0,
|
||||
name: '简介',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
name: '退出登录',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
name: '修改用户信息',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
name: '意见收集',
|
||||
},
|
||||
])
|
||||
const addExit = (index:number)=>{
|
||||
switch (index) {
|
||||
case 1:
|
||||
visible.value = true
|
||||
break;
|
||||
}
|
||||
}
|
||||
const onOk = ()=>{
|
||||
resetUserInfo()
|
||||
setSelected(0)
|
||||
Taro.navigateTo({
|
||||
url: "/pages/login/login",
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,48 +1,76 @@
|
|||
.nameTitle {
|
||||
position: absolute;
|
||||
top: 19%;
|
||||
left: 55px;
|
||||
height: 125rpx;
|
||||
background-color: #fff;
|
||||
width: 650rpx;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0px 10px 10px -4px #e3e3e3;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.itemSchool {
|
||||
border-right: solid 1.5rpx #dadada;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 25%;
|
||||
font-size: 24px
|
||||
}
|
||||
|
||||
.itemSchool text:nth-child(1) {
|
||||
margin-bottom: 10rpx;
|
||||
color: #898a8a;
|
||||
margin-left: -8px;
|
||||
}
|
||||
}
|
||||
.nameTitle .itemSchool:nth-child(4) {
|
||||
border-right: none;
|
||||
}
|
||||
.swiperDemoItem {
|
||||
color: #3886d0;
|
||||
display: flex;
|
||||
padding: 20px 0 0 50px;
|
||||
overflow: hidden;
|
||||
height: 70rpx;
|
||||
margin-top: 70px;
|
||||
|
||||
.swiperDemoIndex {
|
||||
width: 15px;
|
||||
height: 45px;
|
||||
background-image: linear-gradient(to bottom, #5d9cf9, #317ad9);
|
||||
//background: rgb();
|
||||
border-radius: 20px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.subModule {
|
||||
.Module {
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
.subModule {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin-right: -3px;
|
||||
margin-left: -1px;
|
||||
|
||||
.subModuleItem {
|
||||
width: 33%;
|
||||
height: 180rpx;
|
||||
width: 246rpx;
|
||||
height: 140rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 10rpx;
|
||||
border: 1px solid #ccc;
|
||||
border-left: 0;
|
||||
margin-top: -1px;
|
||||
|
||||
.subModuleIndex {
|
||||
width: 65rpx;
|
||||
height: 65rpx;
|
||||
|
||||
width: 45rpx;
|
||||
height: 45rpx;
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,56 +3,101 @@
|
|||
<view class="swiperDemo">
|
||||
<nut-swiper ref="swiperRef" pagination-visible pagination-color="#e53e31" :auto-play="3000" :init-page="0">
|
||||
<nut-swiper-item v-for="(item, index) in list" :key="index" style="height: 180px">
|
||||
<image src="@/assets/images/01.png" alt="" style="height: 100%; width: 100%" draggable="false"/>
|
||||
<image :src="item" alt="" style="height: 100%; width: 100%" draggable="false" />
|
||||
<view>1123</view>
|
||||
</nut-swiper-item>
|
||||
</nut-swiper>
|
||||
</view>
|
||||
<view class="nameTitle">
|
||||
<view class="itemSchool">
|
||||
<text>单位数量</text>
|
||||
<text style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 80px; text-align: center">51</text>
|
||||
</view>
|
||||
<view class="itemSchool">
|
||||
<text>服务项目</text>
|
||||
<text> 13123 </text>
|
||||
</view>
|
||||
<view class="itemSchool">
|
||||
<text>有保安证人员</text>
|
||||
<text> 1000</text>
|
||||
</view>
|
||||
<view class="itemSchool">
|
||||
<text>无保安证人员</text>
|
||||
<text> 140</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="swiperDemoItem">
|
||||
<view class="swiperDemoIndex"></view>
|
||||
<view>请选择</view>
|
||||
</view>
|
||||
<!--九宫格-->
|
||||
<view>
|
||||
<view class="Module">
|
||||
<view class="subModule">
|
||||
<view class="subModuleItem" v-for="item in subModuleList" :key="item.id" @click="subNavigation(item.url)">
|
||||
<view class="subModuleIndex">
|
||||
<image :src="item.icon"></image>
|
||||
</view>
|
||||
<view style=" font-size: 12px;color: #414141;margin-top: 9px">{{ item.name }}</view>
|
||||
<view style="font-size: 12px; color: #414141; margin-top: 5px">{{ item.name }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view style="background-color: #e9eef4; height: 15rpx"></view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {ref} from 'vue'
|
||||
import Taro from "@tarojs/taro";
|
||||
import { ref } from 'vue'
|
||||
import Taro from '@tarojs/taro'
|
||||
import icon from '@/assets/images/project.png'
|
||||
import icon01 from '@/assets/images/回单.jpg'
|
||||
import icon02 from '@/assets/images/工单.jpg'
|
||||
import icon03 from '@/assets/images/排名.jpg'
|
||||
import icon04 from '@/assets/images/法制宣传.jpg'
|
||||
import icon06 from '@/assets/images/警保风采.jpg'
|
||||
import './index.scss'
|
||||
|
||||
const list = ref(['https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',])
|
||||
const list = ref([process.env.TARO_APP_MINIO_URL + '/police-security/2024/11/5/dunpai.jpg'])
|
||||
const swiperRef = ref() //轮播图
|
||||
const subModuleList = ref([
|
||||
{
|
||||
id: 0,
|
||||
icon: icon,
|
||||
name: '我的项目',
|
||||
url: '/subPages/projectManager/myProject/myProject'
|
||||
name: '项目管理',
|
||||
url: '/subPages/projectManager/myProject/myProject',
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
icon: icon,
|
||||
name: '警保风采',
|
||||
url: ''
|
||||
icon: icon02,
|
||||
name: '整改工单',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
icon: icon,
|
||||
name: '待定',
|
||||
url: ''
|
||||
}
|
||||
icon: icon03,
|
||||
name: '考核排名',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
icon: icon06,
|
||||
name: '警保风采',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
icon: icon04,
|
||||
name: '法制宣传',
|
||||
url: '',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
icon: icon01,
|
||||
name: '整改回单',
|
||||
url: '',
|
||||
},
|
||||
])
|
||||
const subNavigation = async (url: string) => Taro.navigateTo({ url })
|
||||
|
||||
|
||||
const subNavigation = async (url: string) => Taro.navigateTo({url})
|
||||
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
.mine {
|
||||
height: 100vh;
|
||||
background-color: #fff;
|
||||
}
|
||||
.mine-container {
|
||||
height: 320rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-image: url('../../../assets/images/banner.png');
|
||||
background-repeat: no-repeat;
|
||||
background-position: right;
|
||||
overflow: hidden;
|
||||
padding: 45rpx;
|
||||
box-sizing: border-box;
|
||||
.contacts {
|
||||
height: 75rpx;
|
||||
width: 75rpx;
|
||||
border-radius: 50%;
|
||||
border: solid 1px gray;
|
||||
.image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.tips-text {
|
||||
display: flex;
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
line-height: 50rpx;
|
||||
margin-left: 20rpx;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
}
|
||||
.exit {
|
||||
height: 100rpx;
|
||||
line-height: 40px;
|
||||
border-bottom: solid 0.5px #ebebf7;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: #7d7d7d;
|
||||
.exitItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 30rpx;
|
||||
}
|
||||
.exitItemIndex {
|
||||
height: 40rpx;
|
||||
width: 40rpx;
|
||||
border-radius: 50%;
|
||||
display: block;
|
||||
line-height: 48rpx;
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.microscope {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
display: inline-block;
|
||||
border: solid 2px #ccc;
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
border-bottom: white;
|
||||
border-left: white;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,80 @@
|
|||
<template>
|
||||
<view>
|
||||
项目经理我的
|
||||
<view class="mine">
|
||||
<view class="mine-container" >
|
||||
<view class="contacts">
|
||||
<image src="@/assets/logo/avatar1.png" mode="scaleToFill" class="image" />
|
||||
</view>
|
||||
<view class="tips-text">
|
||||
<view style="font-size: 15px;">名字</view>
|
||||
<view style="font-size: 12px;">
|
||||
<text style="margin-right: 5px">保安部门 </text>
|
||||
<text>未选择单位</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 用户信息 -->
|
||||
<view class="userIndex">
|
||||
<view class="exit" v-for="item in datalist" :key="item.value" @click="addExit(item.value)">
|
||||
<view class="exitItem">
|
||||
<!-- <view class="exitItemIndex">-->
|
||||
<!-- <image :src="item.url" mode="scaleToFill" class="image" />-->
|
||||
<!-- </view>-->
|
||||
<text style="margin-left: 30rpx;font-size: 12px;">{{ item.name }}</text>
|
||||
</view>
|
||||
<view style="margin-right: 40rpx">
|
||||
<text class="microscope"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 退出弹框-->
|
||||
<nut-dialog
|
||||
content="是否退出登录?"
|
||||
v-model:visible="visible" @cancel="visible = false" @ok="onOk"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import './index.scss'
|
||||
import {ref} from "vue";
|
||||
import {useUserStore} from "@/store/userStore";
|
||||
import {useTabBarStore} from "@/store/tabBarStore"
|
||||
import Taro from "@tarojs/taro";
|
||||
|
||||
const {setSelected} = useTabBarStore()
|
||||
const {resetUserInfo} = useUserStore()
|
||||
const visible = ref<boolean>(false)
|
||||
const datalist = ref([
|
||||
{
|
||||
value: 0,
|
||||
name: '小程序简介',
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
name: '退出登录',
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
name: '修改用户信息',
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
name: '意见收集',
|
||||
},
|
||||
])
|
||||
|
||||
const addExit = (index:number)=>{
|
||||
switch (index) {
|
||||
case 1:
|
||||
visible.value = true
|
||||
break;
|
||||
}
|
||||
}
|
||||
const onOk = ()=>{
|
||||
resetUserInfo()
|
||||
setSelected(0)
|
||||
Taro.navigateTo({
|
||||
url: "/pages/login/login",
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -33,13 +33,7 @@
|
|||
</nut-radio>
|
||||
</nut-radio-group>
|
||||
</nut-form-item>
|
||||
<nut-form-item label="手机号:">
|
||||
<nut-input
|
||||
v-model="formData.telephone"
|
||||
placeholder="请输入手机号码"
|
||||
type="text"
|
||||
/>
|
||||
</nut-form-item>
|
||||
|
||||
<nut-form-item label="行政区划:" prop="name">
|
||||
<view @click="visible = true" style="color: #808080">
|
||||
{{ streetCommunitySmallCommunityLabel || "请选择行政区划" }}
|
||||
|
@ -55,8 +49,9 @@
|
|||
v-model:visible="visible"
|
||||
v-model="TreeValue"
|
||||
title="选择地址"
|
||||
:options="TreeData"
|
||||
@change="change"
|
||||
lazy
|
||||
:lazy-load="lazyLoad"
|
||||
text-key="label"
|
||||
></nut-cascader>
|
||||
<nut-popup v-model:visible="show" position="bottom">
|
||||
|
@ -95,18 +90,28 @@ const formData = ref<RegisterParams>({
|
|||
});
|
||||
const show = ref(false)
|
||||
const visible = ref(false)
|
||||
|
||||
const TreeValue = ref<Record<string, any>[]>([])
|
||||
const TreeData = ref(['']);
|
||||
// const TreeData = ref([]);
|
||||
|
||||
const streetCommunitySmallCommunityLabel = ref<string>("");
|
||||
const getAdministrativeDivisionTree = async () => {
|
||||
const resp = await api.get<TreeNodeVo<string>[]>('/common/administrativeDivisionTree')
|
||||
TreeData.value = resp.data as any
|
||||
console.log(resp.data)
|
||||
const getAdministrativeDivisionTree = async (value:string) => {
|
||||
const resp = await api.get<TreeNodeVo<string>[]>('/common/administrativeDivisionByParentCode',{parentCode:value})
|
||||
return resp.data as any
|
||||
}
|
||||
const change = (value: string, pathNodes: Record<string, any>[]) => {
|
||||
|
||||
|
||||
const change = async (value: string, pathNodes: Record<string, any>[]) => {
|
||||
streetCommunitySmallCommunityLabel.value = pathNodes.map((e) => e.text).join(",");
|
||||
TreeValue.value = value as any
|
||||
}
|
||||
const lazyLoad = async (node:any, resolve:any)=>{
|
||||
if (node.root) {
|
||||
await resolve(getAdministrativeDivisionTree ('0'))
|
||||
} else {
|
||||
await resolve(getAdministrativeDivisionTree (node.value))
|
||||
}
|
||||
}
|
||||
const columns = ref([])
|
||||
const unitsList = async () => {
|
||||
if (streetCommunitySmallCommunityLabel.value !== '') {
|
||||
|
@ -126,7 +131,7 @@ const unitsList = async () => {
|
|||
|
||||
|
||||
const selectedLabel = ref('')
|
||||
const confirm = ({selectedOptions, selectedValue}) => {
|
||||
const confirm = ({selectedOptions}) => {
|
||||
Object.keys(selectedOptions).forEach((e) => {
|
||||
selectedLabel.value = selectedOptions[e].label
|
||||
formData.value.unitId = selectedOptions[e].value
|
||||
|
@ -136,7 +141,7 @@ const confirm = ({selectedOptions, selectedValue}) => {
|
|||
}
|
||||
|
||||
// 身份
|
||||
watch(() => formData.value.identity, (value) => {
|
||||
watch(() => formData.value.identity, () => {
|
||||
formData.value.unitId = ''
|
||||
selectedLabel.value = ''
|
||||
})
|
||||
|
@ -155,7 +160,7 @@ const register = async () => {
|
|||
identity: formData.value.identity,
|
||||
unitId: formData.value.unitId
|
||||
}
|
||||
const resp = await api.post<string>('/miniProgramUser/register', miniProgramUserRegisterParams, {loading: true})
|
||||
const resp = await api.post<string>('/mp/user/register', miniProgramUserRegisterParams, {loading: true})
|
||||
Taro.showToast({
|
||||
title: "注册成功",
|
||||
icon: 'success',
|
||||
|
@ -165,7 +170,7 @@ const register = async () => {
|
|||
await Taro.setStorage({
|
||||
key: "token",
|
||||
data: resp.data,
|
||||
success(res) {
|
||||
success() {
|
||||
Taro.navigateTo({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
|
@ -209,10 +214,10 @@ const onChooseAvatar = (e) => {
|
|||
formData.value.avatar = avatarUrl
|
||||
}
|
||||
// 获取昵称
|
||||
const getNickname = (e) => {
|
||||
formData.value.name = e.detail.value
|
||||
console.log(formData.value.name)
|
||||
}
|
||||
// const getNickname = (e) => {
|
||||
// formData.value.name = e.detail.value
|
||||
// console.log(formData.value.name)
|
||||
// }
|
||||
|
||||
onMounted(async () => {
|
||||
await getAdministrativeDivisionTree()
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export default {
|
||||
"component": true
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
.uiwu-flex-align {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uiwu-flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.uiwu-flex-space {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.uiwu-picker-search {
|
||||
position: absolute;
|
||||
height: 1031rpx;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: url('../assets/images/popuptiobg.png') no-repeat 0 0 #fff;
|
||||
background-size: 100% auto;
|
||||
border-radius: 30rpx 30rpx 0 0;
|
||||
|
||||
&-btn {
|
||||
padding: 20rpx 30rpx 40rpx;
|
||||
|
||||
text {
|
||||
&:nth-child(1) {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
color: #00bbff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-input {
|
||||
box-sizing: border-box;
|
||||
height: 80rpx;
|
||||
background: rgba(#f3f6fd, 0.6);
|
||||
border-radius: 16rpx;
|
||||
margin: 0 30rpx;
|
||||
padding-left: 24rpx;
|
||||
padding-right: 10rpx;
|
||||
|
||||
input {
|
||||
font-size: 28rpx;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
width: 100%;
|
||||
height: calc(100% - 212rpx);
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.radio-group {
|
||||
padding: 0 50rpx 30rpx;
|
||||
|
||||
&-item {
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
radio {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.searchButton {
|
||||
height: 60rpx;
|
||||
width: 200rpx;
|
||||
border-radius: 10rpx;
|
||||
line-height: 60rpx;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
background-color: #00bbff;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<view>
|
||||
<view @tap.stop="open">11111</view>
|
||||
<nut-popup v-model:visible="show" position="bottom" round="true">
|
||||
<view style="height: 1031rpx">
|
||||
<view class="uiwu-picker-search">
|
||||
<view class="uiwu-picker-search-btn uiwu-flex uiwu-flex-space">
|
||||
<text @tap.stop="show = false">取消</text>
|
||||
<text @tap.stop="determine">确定</text>
|
||||
</view>
|
||||
<view class="uiwu-picker-search-input uiwu-flex uiwu-flex-align">
|
||||
<input v-model="inputText.value" type="text" :placeholder="placeholder" confirm-type="search" @confirm="confirm_" />
|
||||
<view @click.stop="confirm" class="searchButton">搜索</view>
|
||||
</view>
|
||||
<scroll-view class="scroll-view" scroll-y>
|
||||
<!-- <radio-group class="radio-group" @change="change">
|
||||
<view class="radio-group-item uiwu-flex uiwu-flex-space" v-for="(item, index) in listData.value" :key="index">
|
||||
<text>{{ item.bank_name }}</text>
|
||||
<radio :value="item.bank_name" color="#687CFF" />
|
||||
</view>
|
||||
</radio-group> -->
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</nut-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import './picker-search.scss'
|
||||
import { ref, expose } from 'vue'
|
||||
// import { searchBankName } from '@/api/app'
|
||||
|
||||
const props = defineProps({
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请输入银行名称',
|
||||
},
|
||||
})
|
||||
|
||||
// 定义响应式变量
|
||||
const show = ref(true)
|
||||
const listData = ref([])
|
||||
const currentBankName = ref('')
|
||||
const inputText = ref('')
|
||||
|
||||
// 搜索方法
|
||||
const confirm = () => {
|
||||
// searchBankName({ bank_name: inputText.value.trim() }).then((res) => {
|
||||
// console.log('searchBankName', res)
|
||||
// listData.value = res.data
|
||||
// })
|
||||
}
|
||||
|
||||
// 输入确认方法
|
||||
const confirm_ = ({ detail: { value } }) => {
|
||||
console.log('confirm', value)
|
||||
// searchBankName({ bank_name: value.trim() }).then((res) => {
|
||||
// console.log('searchBankName', res)
|
||||
// listData.value = res.data
|
||||
// })
|
||||
}
|
||||
|
||||
// 单选框切换方法
|
||||
const change = ({ detail: { value } }) => {
|
||||
console.log('change', value)
|
||||
currentBankName.value = value
|
||||
}
|
||||
|
||||
// 确定方法
|
||||
const determine = () => {
|
||||
if (currentBankName.value.trim() === '') {
|
||||
uni.showToast({
|
||||
title: '请选择银行',
|
||||
duration: 1500,
|
||||
icon: 'error',
|
||||
})
|
||||
return
|
||||
}
|
||||
// 触发父组件的事件,传递选择的银行名称
|
||||
emit('change', currentBankName.value.trim())
|
||||
show.value = false
|
||||
}
|
||||
|
||||
// 打开弹窗
|
||||
const open = () => {
|
||||
show.value = true
|
||||
}
|
||||
// expose({ open })
|
||||
</script>
|
|
@ -1,6 +1,6 @@
|
|||
import Taro from "@tarojs/taro";
|
||||
import {ApiOptions} from "@/types/request";
|
||||
import {useUserStore} from "@/store/userStore";
|
||||
import { ApiOptions } from "@/types/request";
|
||||
import { useUserStore } from "@/store/userStore";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -10,7 +10,7 @@ import {useUserStore} from "@/store/userStore";
|
|||
const requestInterceptor = (chain: Taro.Chain) => {
|
||||
const requestParams = chain.requestParams
|
||||
const tokenInfo = useUserStore().getTokenInfo()
|
||||
const {header} = requestParams;
|
||||
const { header } = requestParams;
|
||||
const customHeader: Record<string, any> = {}
|
||||
//添加token
|
||||
tokenInfo && (customHeader[tokenInfo.name] = tokenInfo.value);
|
||||
|
@ -35,6 +35,9 @@ class CustomRequest {
|
|||
Taro.showLoading({
|
||||
title: '请求中...',
|
||||
}).then()
|
||||
// Taro.showLoading({
|
||||
// title: '请求中...',
|
||||
// })
|
||||
}
|
||||
Taro.request<JsonResult<T>, object>({
|
||||
url: this.BASE_API + url,
|
||||
|
@ -77,7 +80,7 @@ class CustomRequest {
|
|||
})
|
||||
}
|
||||
|
||||
get<T>(url: string, params?: object, options: ApiOptions = {loading: false}): Promise<JsonResult<T>> {
|
||||
get<T>(url: string, params?: object, options: ApiOptions = { loading: false }): Promise<JsonResult<T>> {
|
||||
options.header = {
|
||||
...options.header,
|
||||
"content-type": 'application/x-www-form-urlencoded'
|
||||
|
@ -85,11 +88,11 @@ class CustomRequest {
|
|||
return this.request<T>(url, "GET", options, params)
|
||||
}
|
||||
|
||||
post<T>(url: string, params?: object, options: ApiOptions = {loading: false}): Promise<JsonResult<T>> {
|
||||
post<T>(url: string, params?: object, options: ApiOptions = { loading: false }): Promise<JsonResult<T>> {
|
||||
return this.request<T>(url, "POST", options, params)
|
||||
}
|
||||
|
||||
delete<T>(url: string, params?: object, options: ApiOptions = {loading: false}): Promise<JsonResult<T>> {
|
||||
delete<T>(url: string, params?: object, options: ApiOptions = { loading: false }): Promise<JsonResult<T>> {
|
||||
options.header = {
|
||||
...options.header,
|
||||
"content-type": 'application/x-www-form-urlencoded'
|
||||
|
@ -97,7 +100,7 @@ class CustomRequest {
|
|||
return this.request(url, "DELETE", options, params)
|
||||
}
|
||||
|
||||
put<T>(url: string, params?: object, options: ApiOptions = {loading: false}): Promise<JsonResult<T>> {
|
||||
put<T>(url: string, params?: object, options: ApiOptions = { loading: false }): Promise<JsonResult<T>> {
|
||||
return this.request(url, "PUT", options, params)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useDailyStore = defineStore('daily', {
|
||||
state: () => ({
|
||||
userdailyinspection: [],
|
||||
base64_1: '',
|
||||
base64_2: '',
|
||||
}),
|
||||
actions: {
|
||||
dailyinspectionList(data) {
|
||||
this.userdailyinspection = [...data]
|
||||
},
|
||||
change_base64_1(data) {
|
||||
this.base64_1 = data
|
||||
},
|
||||
change_base64_2(data) {
|
||||
this.base64_2 = data
|
||||
},
|
||||
clearSignData() {
|
||||
this.base64_1 = ''
|
||||
this.base64_2 = ''
|
||||
},
|
||||
|
||||
},
|
||||
getters: {
|
||||
getdailyinspection(state) {
|
||||
return state.userdailyinspection
|
||||
},
|
||||
get_base64_1(state) {
|
||||
return state.base64_1
|
||||
},
|
||||
get_base64_2(state) {
|
||||
return state.base64_2
|
||||
},
|
||||
|
||||
}
|
||||
})
|
|
@ -0,0 +1,149 @@
|
|||
page {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
|
||||
.picker {
|
||||
padding: 30rpx 30rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.exit {
|
||||
height: 100rpx;
|
||||
line-height: 40px;
|
||||
border-bottom: solid 0.5px #ebebf7;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.exitItem {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.iconoscope {
|
||||
z-index: 9999;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
display: inline-block;
|
||||
border: solid 2px #c2c2c2;
|
||||
margin-left: 10px;
|
||||
transform: rotate(45deg);
|
||||
border-bottom: white;
|
||||
border-left: white;
|
||||
}
|
||||
}
|
||||
|
||||
.sigh_btns {
|
||||
transform: rotate(-90deg);
|
||||
transform-origin: center
|
||||
}
|
||||
|
||||
.sigh_btns_noRotate {}
|
||||
|
||||
|
||||
|
||||
.input_width {
|
||||
width: 400rpx;
|
||||
height: 40rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.uiwu-flex-align {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uiwu-flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.uiwu-flex-space {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.uiwu-picker-search {
|
||||
position: absolute;
|
||||
height: 1031rpx;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: url('../../../assets/images/popuptiobg.png') no-repeat 0 0 #fff;
|
||||
background-size: 100% auto;
|
||||
border-radius: 30rpx 30rpx 0 0;
|
||||
|
||||
&-btn {
|
||||
padding: 20rpx 30rpx 40rpx;
|
||||
|
||||
text {
|
||||
&:nth-child(1) {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
color: rgb(73, 143, 242);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-input {
|
||||
box-sizing: border-box;
|
||||
height: 80rpx;
|
||||
background: rgba(#f3f6fd, 0.6);
|
||||
border-radius: 16rpx;
|
||||
margin: 0 30rpx;
|
||||
padding-left: 24rpx;
|
||||
padding-right: 10rpx;
|
||||
|
||||
input {
|
||||
font-size: 28rpx;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
width: 100%;
|
||||
height: 800rpx;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.radio-group {
|
||||
padding: 0 50rpx 30rpx;
|
||||
overflow-y: scroll;
|
||||
|
||||
&-item {
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
radio {
|
||||
transform: scale(0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.searchButton {
|
||||
height: 60rpx;
|
||||
width: 200rpx;
|
||||
border-radius: 10rpx;
|
||||
line-height: 60rpx;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
background-color: rgb(73, 143, 242);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default definePageConfig({
|
||||
navigationBarTitleText: '监督考核',
|
||||
})
|
|
@ -0,0 +1,404 @@
|
|||
<template>
|
||||
<view class="container">
|
||||
<nut-form labelWidth="320rpx" labelAlign="left" @click.stop="openSearch">
|
||||
<nut-form-item label="考核单位:">
|
||||
<view class="input_width">
|
||||
<input style="width: 300rpx" disabled="true" v-model="enterprisesName" placeholder="请选择考核单位:" />
|
||||
<IconFont name="arrow-down"></IconFont>
|
||||
</view>
|
||||
</nut-form-item>
|
||||
</nut-form>
|
||||
|
||||
<!-- <picker mode="selector" :range="selector" rangeKey="label" @change="onChange">
|
||||
<view class="picker">
|
||||
考核单位:
|
||||
<view style="display: flex; align-items: center">
|
||||
<view v-if="selectorChecked.length === 0" style="color: #606266">请选择考核单位:</view>
|
||||
<view> {{ selectorChecked }}</view>
|
||||
<IconFont name="arrow-right"></IconFont>
|
||||
</view>
|
||||
</view>
|
||||
</picker> -->
|
||||
|
||||
<picker v-if="(selectorType?.length ?? 0) > 0" mode="selector" :range="selectorType" rangeKey="label" @change="onChangeType">
|
||||
<view class="picker">
|
||||
当前考核项目:
|
||||
<view style="display: flex; align-items: center">
|
||||
<view v-if="selectorCheckedType.length === 0" style="color: #606266">请选择考核项目</view>
|
||||
<view> {{ selectorCheckedType }}</view>
|
||||
<IconFont name="arrow-right"></IconFont>
|
||||
</view>
|
||||
</view>
|
||||
</picker>
|
||||
|
||||
<view class="exit" v-for="item in starRating" :key="item.snowFlakeId" @click="Onrating(item.name, item.snowFlakeId)">
|
||||
<view class="exitItem">
|
||||
<text style="margin-left: 30rpx; font-size: 16px">
|
||||
<text>{{ item.name }}({{ item?.totalScore }}分) </text>
|
||||
</text>
|
||||
</view>
|
||||
<view style="margin-right: 30rpx; display: flex; align-items: center">
|
||||
<view v-if="item.currentScore > 0" style="color: #ff0000"> -{{ item?.currentScore }}</view>
|
||||
<IconFont name="arrow-right"></IconFont>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
<nut-form labelWidth="320rpx" labelAlign="left">
|
||||
<nut-form-item label="备注">
|
||||
<nut-input v-model="_form.remark" placeholder="请输入备注" type="text" />
|
||||
</nut-form-item>
|
||||
|
||||
<nut-form-item label="考核人员签名:">
|
||||
<navigator :url="`/subPages/select/signature/signature?index=${1}&name=考核人员签名`" hover-class="navigator-hover">
|
||||
<nut-button style="height: 50rpx" shape="square" type="info">考核人员签字</nut-button>
|
||||
</navigator>
|
||||
</nut-form-item>
|
||||
<view style="display: flex; justify-content: center">
|
||||
<image v-if="_form.assessmentUserSignature" :src="_form.assessmentUserSignature" mode="aspectFit" style="height: 300rpx"></image>
|
||||
</view>
|
||||
|
||||
<nut-form-item label="被考评学校签名:">
|
||||
<navigator :url="`/subPages/select/signature/signature?index=${2}&name=被考评学校签名`" hover-class="navigator-hover">
|
||||
<nut-button style="height: 50rpx" shape="square" type="info">被考评学校负责人</nut-button>
|
||||
</navigator>
|
||||
</nut-form-item>
|
||||
<view style="display: flex; justify-content: center">
|
||||
<image v-if="_form.byAssessmentEnterprisesUnitUserSignature" :src="_form.byAssessmentEnterprisesUnitUserSignature" mode="heightFix" style="height: 300rpx"></image>
|
||||
</view>
|
||||
</nut-form>
|
||||
</view>
|
||||
<view style="height: 150rpx"></view>
|
||||
<view style="display: flex; width: 100%; justify-content: center; position: fixed; bottom: 50rpx">
|
||||
<nut-button :loading="isLoading" shape="round" type="info" @click="onSubmit" style="height: 80rpx; width: 702rpx; margin: 10rpx auto">确认提交</nut-button>
|
||||
</view>
|
||||
|
||||
<nut-popup v-model:visible="show" position="bottom" :round="true">
|
||||
<view style="height: 1031rpx">
|
||||
<view class="uiwu-picker-search">
|
||||
<view class="uiwu-picker-search-btn uiwu-flex uiwu-flex-space">
|
||||
<text @tap.stop="show = false">取消</text>
|
||||
<text @tap.stop="determine">确定</text>
|
||||
</view>
|
||||
<view class="uiwu-picker-search-input uiwu-flex uiwu-flex-align">
|
||||
<input v-model="inputText" type="text" placeholder="请输入单位名称" confirm-type="search" @confirm="confirm_" />
|
||||
<view @click.stop="confirm" class="searchButton">搜索</view>
|
||||
</view>
|
||||
<scroll-view class="scroll-view" :scroll-y="true">
|
||||
<!-- <radio-group class="radio-group" @change="radioChange">
|
||||
<view class="radio-group-item uiwu-flex uiwu-flex-space" v-for="(item, index) in selector" :key="index">
|
||||
<text>{{ item.label }}</text>
|
||||
<radio :value="item.value" color="#687CFF" />
|
||||
</view>
|
||||
</radio-group> -->
|
||||
<nut-radio-group v-if="(selectorCopy?.length ?? 0) > 0" style="margin-left: 30rpx" v-model="selectedID">
|
||||
<nut-radio icon-size="20" v-for="(item, index) in selectorCopy" :key="index" :label="item.value"> {{ item.label }}</nut-radio>
|
||||
<view style="height: 40rpx"></view>
|
||||
</nut-radio-group>
|
||||
<nut-empty v-else description="暂无单位"></nut-empty>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</nut-popup>
|
||||
</view>
|
||||
<!-- <picker-search ref="picker_search" @change="changeSearch" /> -->
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// import PickerSearch from '@/components/PickerSearch.vue'
|
||||
// import picker-search from
|
||||
import { IconFont } from '@nutui/icons-vue-taro'
|
||||
import Taro, { useLoad, useUnload } from '@tarojs/taro'
|
||||
import './dailyInspection.scss'
|
||||
import { ref, computed, reactive, watch } from 'vue'
|
||||
import api from '@/request/index'
|
||||
import { useDailyStore } from '@/store/daily'
|
||||
|
||||
// const picker_search = ref()
|
||||
const starRating = ref<any[]>([])
|
||||
const store = useDailyStore()
|
||||
const daily = computed(() => store.getdailyinspection)
|
||||
const base64_1 = computed(() => store.get_base64_1)
|
||||
const base64_2 = computed(() => store.get_base64_2)
|
||||
|
||||
const currentCkProjectId = ref('')
|
||||
const submitData = ref<Item[]>([])
|
||||
const enterprisesName = ref('')
|
||||
const _form = reactive({
|
||||
enterprisesUnitId: '', //企事业单位id
|
||||
ckProjectId: '', //考核项目
|
||||
assessmentUserSignature: '', //考核人员签字
|
||||
byAssessmentEnterprisesUnitUserSignature: '', // 被考核单位人员签字
|
||||
remark: '', //考核备注
|
||||
})
|
||||
watch(
|
||||
[daily, base64_1, base64_2],
|
||||
([newDaily, newBase64_1, newBase64_2]) => {
|
||||
_form.assessmentUserSignature = newBase64_1
|
||||
_form.byAssessmentEnterprisesUnitUserSignature = newBase64_2
|
||||
|
||||
if (newDaily.length > 0) {
|
||||
starRating.value = newDaily
|
||||
}
|
||||
submitData.value = newDaily
|
||||
// console.log('watch_______________', _form, submitData.value)
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
useLoad(async () => {
|
||||
await getUnitEnterprisesUnitList()
|
||||
})
|
||||
|
||||
const Onrating = function (name: string, snowFlakeId: string) {
|
||||
let index = starRating.value.findIndex((item) => item.snowFlakeId === snowFlakeId)
|
||||
Taro.navigateTo({
|
||||
url: `/subPages/select/dailyLife/dailyLife?name=${name}&index=${index}`,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @assessmentCriteriaRulesByCkProjectId 获取考核规则
|
||||
*/
|
||||
|
||||
const assessmentCriteriaRulesByCkProjectId = async function (ckProjectId) {
|
||||
// Taro.showLoading({
|
||||
// title: '加载中...',
|
||||
// mask: true,
|
||||
// })
|
||||
const res = await api.get<StarRating[]>(`/mp/sa/assessmentCriteriaRulesByCkProjectId`, { ckProjectId })
|
||||
|
||||
res.data?.forEach((item) => {
|
||||
item.currentScore = 0
|
||||
|
||||
item.itemList.forEach((element: ItemList) => {
|
||||
element.standardList.forEach((ele) => {
|
||||
ele.isSelected = false
|
||||
})
|
||||
element.standardList.unshift({
|
||||
ckItemId: 'null',
|
||||
deductionPoints: 0,
|
||||
name: '达标',
|
||||
snowFlakeId: 'null',
|
||||
isSelected: true,
|
||||
})
|
||||
element.selectedID = element.standardList[0].snowFlakeId
|
||||
element.selected_points = 0 // 默认达标 默认扣 0 分
|
||||
// 多选
|
||||
if (element.type.value === 'multiple') {
|
||||
element.selectedGroup = [element.selectedID]
|
||||
}
|
||||
})
|
||||
})
|
||||
starRating.value = res.data ?? []
|
||||
// console.log('starRating.value______________________________', starRating.value)
|
||||
|
||||
store.dailyinspectionList(starRating.value)
|
||||
// Taro.hideLoading()
|
||||
}
|
||||
/**
|
||||
* @ckProjectListByType 根据类型获取考核标准列表
|
||||
*/
|
||||
|
||||
const selectorCheckedType = ref<string>('')
|
||||
const selectorType = ref<CkProjectListByType[]>()
|
||||
const ckProjectListByType = async function (type) {
|
||||
const res = await api.get<CkProjectListByType[]>(`/mp/sa/ckProjectListByType`, { type })
|
||||
console.log(res.data)
|
||||
|
||||
if (res.data?.length === 0) {
|
||||
let timeID = setTimeout(() => {
|
||||
Taro.showToast({
|
||||
title: '该单位下面没有考核标准',
|
||||
icon: 'none',
|
||||
duration: 2000,
|
||||
})
|
||||
clearTimeout(timeID)
|
||||
}, 500)
|
||||
}
|
||||
selectorType.value = res.data
|
||||
}
|
||||
|
||||
const onChangeType = function (e: any) {
|
||||
let index = Number(e.detail.value)
|
||||
selectorCheckedType.value = selectorType.value?.[index].label as string
|
||||
currentCkProjectId.value = selectorType.value?.[index].value as string
|
||||
assessmentCriteriaRulesByCkProjectId(currentCkProjectId.value)
|
||||
_form.ckProjectId = selectorType.value?.[index].value as string
|
||||
}
|
||||
|
||||
const selector = ref<UnitEnterprisesUnitList[]>()
|
||||
const selectorCopy = ref<UnitEnterprisesUnitList[]>()
|
||||
// const selectorChecked = ref<string>('')
|
||||
// const onChange = function (e: any) {
|
||||
// try {
|
||||
// let index = Number(e.detail.value)
|
||||
// selectorChecked.value = selector.value?.[index].label as string
|
||||
// let type = selector.value?.[index].extData.type.value
|
||||
// ckProjectListByType(type)
|
||||
// _form.enterprisesUnitId = selector.value?.[index].value as string
|
||||
// } catch (error) {
|
||||
// console.log('🚀 ~ onChange ~ error:', error)
|
||||
// }
|
||||
// }
|
||||
|
||||
const getUnitEnterprisesUnitList = async function () {
|
||||
const res = await api.get<UnitEnterprisesUnitList[]>(`/policeIndex/getUnitEnterprisesUnitList`)
|
||||
|
||||
selector.value = res.data
|
||||
selectorCopy.value = res.data
|
||||
}
|
||||
|
||||
const _showToast = function (title) {
|
||||
Taro.showToast({
|
||||
title,
|
||||
icon: 'none',
|
||||
duration: 1500,
|
||||
mask: true,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @onSubmit 提交
|
||||
* @assessmentRecordDetails 选择后的数据用于提交
|
||||
* @clearData 清空数据
|
||||
*/
|
||||
|
||||
const assessmentRecordDetails = ref<any[]>([])
|
||||
const clearData = function () {
|
||||
store.clearSignData()
|
||||
store.dailyinspectionList([])
|
||||
assessmentRecordDetails.value = []
|
||||
_form.assessmentUserSignature = ''
|
||||
_form.byAssessmentEnterprisesUnitUserSignature = ''
|
||||
_form.remark = ''
|
||||
assessmentCriteriaRulesByCkProjectId(currentCkProjectId.value) //重新获取数据
|
||||
}
|
||||
const isLoading = ref(false)
|
||||
const onSubmit = async function () {
|
||||
if (_form.enterprisesUnitId === '') {
|
||||
_showToast('请选择企事业单位')
|
||||
return
|
||||
}
|
||||
if (_form.ckProjectId === '') {
|
||||
_showToast('请选择考核项目')
|
||||
return
|
||||
}
|
||||
if (_form.assessmentUserSignature === '') {
|
||||
_showToast('请考核人员签字')
|
||||
return
|
||||
}
|
||||
if (_form.byAssessmentEnterprisesUnitUserSignature === '') {
|
||||
_showToast('请被考核单位人员签字')
|
||||
return
|
||||
}
|
||||
isLoading.value = true
|
||||
|
||||
submitData.value.forEach((element: StarRating) => {
|
||||
element?.itemList.forEach((item: ItemList) => {
|
||||
item.standardList.forEach((ele: StandardList) => {
|
||||
if (ele.snowFlakeId === item.selectedID && !item.hasOwnProperty('selectedGroup') && item.selectedID != 'null') {
|
||||
assessmentRecordDetails.value.push({
|
||||
ckGroupId: element.snowFlakeId, //选项的雪花Id
|
||||
ckItemId: ele.ckItemId, //已选择的ID
|
||||
ckStandardId: item.selectedID, //已选择的雪花ID
|
||||
})
|
||||
}
|
||||
})
|
||||
if (item.hasOwnProperty('selectedGroup')) {
|
||||
item.selectedGroup.forEach((selectedItem) => {
|
||||
item.standardList.forEach((standard_Element) => {
|
||||
if (selectedItem != 'null' && selectedItem === standard_Element.snowFlakeId) {
|
||||
assessmentRecordDetails.value.push({
|
||||
ckGroupId: element.snowFlakeId, //选项的雪花Id
|
||||
ckItemId: standard_Element.ckItemId, //已选择的ID
|
||||
ckStandardId: selectedItem, //已选择的雪花ID
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const assessmentRecordParams = {
|
||||
assessmentRecordDetails: [] as any[],
|
||||
}
|
||||
Object.assign(assessmentRecordParams, _form)
|
||||
assessmentRecordParams.assessmentRecordDetails = [...assessmentRecordDetails.value]
|
||||
const result = await api.post('/mp/sa/submitAssessmentRecord', assessmentRecordParams)
|
||||
|
||||
clearData() //清空数据
|
||||
if (result.code === 200) {
|
||||
isLoading.value = false
|
||||
|
||||
let timeID = setTimeout(() => {
|
||||
Taro.showToast({
|
||||
title: result.message,
|
||||
icon: 'success',
|
||||
duration: 2000,
|
||||
mask: true,
|
||||
})
|
||||
clearTimeout(timeID)
|
||||
}, 500)
|
||||
} else {
|
||||
_showToast(result.message)
|
||||
}
|
||||
}
|
||||
|
||||
useUnload(() => {
|
||||
store.clearSignData()
|
||||
store.dailyinspectionList([])
|
||||
assessmentRecordDetails.value = []
|
||||
_form.assessmentUserSignature = ''
|
||||
_form.byAssessmentEnterprisesUnitUserSignature = ''
|
||||
_form.remark = ''
|
||||
})
|
||||
|
||||
const show = ref(false)
|
||||
const inputText = ref('')
|
||||
const selectedID = ref('')
|
||||
|
||||
const openSearch = () => {
|
||||
show.value = true
|
||||
}
|
||||
|
||||
const fuzzySearch = function (query) {
|
||||
selectorCopy.value = selector.value?.filter((item) => item.label.includes(query))
|
||||
}
|
||||
const confirm = () => {
|
||||
console.log(inputText.value)
|
||||
if (inputText.value.trim() === '') {
|
||||
selectorCopy.value = selector.value
|
||||
} else {
|
||||
fuzzySearch(inputText.value.trim())
|
||||
}
|
||||
}
|
||||
const confirm_ = ({ detail: { value } }) => {
|
||||
console.log('confirm', value)
|
||||
if (inputText.value.trim() === '') {
|
||||
selectorCopy.value = selector.value
|
||||
} else {
|
||||
fuzzySearch(inputText.value.trim())
|
||||
}
|
||||
}
|
||||
|
||||
const determine = () => {
|
||||
console.log(selectedID.value)
|
||||
if (selectedID.value === '' && (selector.value?.length as number) > 0) {
|
||||
Taro.showToast({
|
||||
title: '请选择单位',
|
||||
icon: 'none',
|
||||
duration: 1500,
|
||||
mask: true,
|
||||
})
|
||||
return
|
||||
}
|
||||
let index: number = selector.value?.findIndex((item) => item.value === selectedID.value) as number
|
||||
_form.enterprisesUnitId = selectedID.value
|
||||
let type = selector.value?.[index].extData.type.value
|
||||
enterprisesName.value = selector.value?.[index].label as string
|
||||
show.value = false
|
||||
ckProjectListByType(type)
|
||||
}
|
||||
</script>
|
|
@ -17,16 +17,13 @@ page {
|
|||
}
|
||||
|
||||
.project {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-flow: wrap;
|
||||
text-align: center;
|
||||
//display: flex;
|
||||
//justify-content: space-between;
|
||||
//flex-flow: wrap;
|
||||
//text-align: center;
|
||||
|
||||
view {
|
||||
width: 45%;
|
||||
height: 100rpx;
|
||||
border: 1px solid #cccccc;
|
||||
line-height: 100rpx;
|
||||
width: 100%;
|
||||
margin: 8px 0 8px 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,54 @@
|
|||
<template>
|
||||
<view class="myProject">
|
||||
<view class="myProjectItem" v-for="(item,index) in myProjectList" :key="index">
|
||||
<view style="display: flex;justify-content: space-between">
|
||||
<view v-if="number !== 0" class="myProjectItem" v-for="(item, index) in myProjectList" :key="index">
|
||||
<view style="display: flex; justify-content: space-between">
|
||||
<text>{{ item?.name }}</text>
|
||||
<!--<text>进行中</text>-->
|
||||
<text>单位类型:{{ item?.type?.label }}</text>
|
||||
</view>
|
||||
<view class="myProjectIndex">地址:
|
||||
<view class="myProjectIndex"
|
||||
>地址:
|
||||
<text>{{ item?.provinceName }}{{ item.cityName }}{{ item.districtsName }}{{ item.streetName }}</text>
|
||||
</view>
|
||||
<view style="display: flex;justify-content: space-between">
|
||||
<view style="display: flex; justify-content: space-between">
|
||||
<text>联系人:{{ item?.contactPersonInfo.name }}</text>
|
||||
<text>电话:{{ item?.contactPersonInfo.telephone }}</text>
|
||||
</view>
|
||||
<view class="project">
|
||||
<view @click="projectClick(item?.name,serviceProject)" v-for="(serviceProject,index) in item.serviceProjectList"
|
||||
:key="index">
|
||||
{{ serviceProject.name }}
|
||||
<view @click="projectClick(item?.name, serviceProject)" v-for="(serviceProject, index) in item.serviceProjectList" :key="index">
|
||||
<view style="border: 1px solid #cccccc; color: #9b9b9f">
|
||||
<view style="display: flex; justify-content: space-between">
|
||||
<text>项目名称:{{ serviceProject.name }}</text>
|
||||
<text>项目类型:{{ serviceProject.type?.label }}</text>
|
||||
</view>
|
||||
<view style="display: flex; justify-content: space-between">
|
||||
<text>项目负责人:{{ serviceProject.projectManagerMiniProgramUserInfo?.name ? serviceProject.projectManagerMiniProgramUserInfo?.name : '无分配项目经理' }}</text>
|
||||
</view>
|
||||
<view>责任单位:{{ serviceProject.securityUnitName }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="myProject">
|
||||
<nut-empty image="empty" description="暂无项目">
|
||||
<div style="margin-top: 10px"></div>
|
||||
</nut-empty>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import api from "@/request/index";
|
||||
import {onMounted, ref} from "vue";
|
||||
import Taro from "@tarojs/taro";
|
||||
import api from '@/request/index'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import Taro from '@tarojs/taro'
|
||||
import './myEnterprisesUnit.scss'
|
||||
import {MyProjectList, ServiceProjectList} from "@/types/subPages/projectManager/myProject";
|
||||
import { MyProjectList, ServiceProjectList } from '@/types/subPages/projectManager/myProject'
|
||||
|
||||
const myProjectList = ref<MyProjectList[]>()
|
||||
const number = ref(0)
|
||||
const getMyServiceProject = async () => {
|
||||
const resp = await api.get<MyProjectList[]>(`/policeIndex/getUnitServiceProjectList`)
|
||||
myProjectList.value = resp.data
|
||||
number.value = resp.data?.length || 0
|
||||
}
|
||||
|
||||
const projectClick = (enterprisesUnitName: string, serviceProject: ServiceProjectList) => {
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
<view class="projectDetails">
|
||||
<view class="projectDetailsItem" style="line-height: 50rpx">
|
||||
<view>
|
||||
<view style="display: flex;justify-content: space-between">
|
||||
<view style="display: flex; justify-content: space-between">
|
||||
<text style="font-size: 18px">{{ enterprisesUnitName }}-----{{ serviceProject?.name }}项目</text>
|
||||
<!-- <text>进行中</text>-->
|
||||
</view>
|
||||
<view>
|
||||
<view style="float: left;width: 50%;" class="content">
|
||||
经理名称:{{ serviceProject?.projectManagerMiniProgramUserInfo.name }}
|
||||
</view>
|
||||
<view style="float: left; width: 50%" class="content"> 经理名称:{{ serviceProject?.projectManagerMiniProgramUserInfo.name }} </view>
|
||||
<view class="content">手机号:{{ serviceProject?.projectManagerMiniProgramUserInfo.telephone }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
@ -47,26 +45,33 @@
|
|||
<!--表格-->
|
||||
<view class="projectDetailsTableDrop">
|
||||
<view style="padding: 0 12px">项目人员</view>
|
||||
<scroll-view :scroll-y="true" style="height: 80%;" @scrolltoupper="upper" @scrolltolower="lower"
|
||||
:scroll-into-view="toView" :scroll-top="scrollTop" :refresherEnabled="true"
|
||||
@refresherrefresh="onRefresherRefresh" :refresher-triggered="isRefresher"
|
||||
<scroll-view
|
||||
:scroll-y="true"
|
||||
style="height: 80%"
|
||||
@scrolltoupper="upper"
|
||||
@scrolltolower="lower"
|
||||
:scroll-into-view="toView"
|
||||
:scroll-top="scrollTop"
|
||||
:refresherEnabled="true"
|
||||
@refresherrefresh="onRefresherRefresh"
|
||||
:refresher-triggered="isRefresher"
|
||||
>
|
||||
<view class="projectDetailsTable" v-for="(item,index) in securityUserList" :key="index">
|
||||
<view class="projectDetailsTable" v-for="(item, index) in securityUserList" :key="index">
|
||||
<view>
|
||||
<view class="projectDetailsTableItem">
|
||||
<view>
|
||||
<view style="display: flex;justify-content: space-between">
|
||||
<view style="display: flex; justify-content: space-between">
|
||||
<text>姓名:{{ item?.name ? item?.name : '创建者' }}</text>
|
||||
<text>性别:{{ item.sex?.label ? item.sex?.label : ' 隐藏' }}</text>
|
||||
<text>职位:{{ item.workPost ? item.workPost : '创建者' }}</text>
|
||||
</view>
|
||||
<view style="display: flex;justify-content: space-between">
|
||||
<text>保安证件:{{ item.securityNumber ? item.securityNumber : '125241256451' }}</text>
|
||||
<view style="display: flex; justify-content: space-between">
|
||||
<text>保安证件:{{ item.securityNumber ? item.securityNumber : '无' }}</text>
|
||||
<text>出生年月:{{ dayjs(item.dateOfBirth).format('YYYY-MM-DD') }}</text>
|
||||
</view>
|
||||
<view style="display: flex;justify-content: space-between">
|
||||
<view style="display: flex; justify-content: space-between">
|
||||
<text>创建时间:{{ item.createTime }}</text>
|
||||
<text>身份证:{{ item.idCard }}</text>
|
||||
<text>身份证:{{ item.idCard?.desensitizedValue }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
@ -74,16 +79,15 @@
|
|||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Taro, {useLoad} from "@tarojs/taro";
|
||||
import Taro, { useLoad } from '@tarojs/taro'
|
||||
import './projectDetails.scss'
|
||||
import {ref} from "vue";
|
||||
import api from "@/request/index";
|
||||
import { ref } from 'vue'
|
||||
import api from '@/request/index'
|
||||
import dayjs from 'dayjs'
|
||||
import {ServiceProjectSecurityUserPagerVo} from "@/types/subPages/projectManager/myProject";
|
||||
import { ServiceProjectSecurityUserPagerVo } from '@/types/subPages/projectManager/myProject'
|
||||
|
||||
const serviceProject = ref()
|
||||
const enterprisesUnitName = ref('')
|
||||
|
@ -91,11 +95,10 @@ const securityUserList = ref<ServiceProjectSecurityUserPagerVo[]>([])
|
|||
useLoad(async (options) => {
|
||||
enterprisesUnitName.value = options.enterprisesUnitName
|
||||
serviceProject.value = JSON.parse(options.serviceProject)
|
||||
console.log(serviceProject.value);
|
||||
console.log(serviceProject.value)
|
||||
await projectDetailsTable()
|
||||
})
|
||||
const projectDetailsTable = async () => {
|
||||
// if (total.value === projectData.value.length) return
|
||||
Taro.showLoading({
|
||||
title: '加载中',
|
||||
})
|
||||
|
@ -105,10 +108,10 @@ const projectDetailsTable = async () => {
|
|||
},
|
||||
page: {
|
||||
size: 4,
|
||||
current: current.value
|
||||
current: current.value,
|
||||
},
|
||||
}
|
||||
}
|
||||
const resp = await api.post<PagerVo<ServiceProjectSecurityUserPagerVo>>('/miniProgramUser/securityUserPager', queryParams)
|
||||
const resp = await api.post<PagerVo<ServiceProjectSecurityUserPagerVo>>('/mp/user/securityUserPager', queryParams)
|
||||
securityUserList.value = [...securityUserList.value, ...resp.data!.records]
|
||||
total.value = resp.data!.total
|
||||
isRefresher.value = false
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
page {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
.myProject {
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
background: #f1f1f1;
|
||||
|
||||
.myProjectItem {
|
||||
//height: 20%;
|
||||
margin: 20px;
|
||||
border-radius: 10px;
|
||||
background: #ffffff;
|
||||
|
@ -18,16 +16,8 @@
|
|||
}
|
||||
|
||||
.project {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-flow: wrap;
|
||||
text-align: center;
|
||||
|
||||
view {
|
||||
width: 45%;
|
||||
height: 100rpx;
|
||||
border: 1px solid #cccccc;
|
||||
line-height: 100rpx;
|
||||
width: 100%;
|
||||
margin: 8px 0 8px 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<view class="myProjectItem" v-for="(item,index) in myProjectList" :key="index">
|
||||
<view style="display: flex;justify-content: space-between">
|
||||
<text>{{ item?.name }}</text>
|
||||
<text>单位类型:{{ item?.type.label }}</text>
|
||||
</view>
|
||||
<view class="myProjectIndex">地址:
|
||||
<text>{{ item?.provinceName }}{{ item.cityName }}{{ item.districtsName }}{{ item.streetName }}</text>
|
||||
|
@ -13,9 +14,17 @@
|
|||
<text>电话:{{ item?.contactPersonInfo.telephone }}</text>
|
||||
</view>
|
||||
<view class="project">
|
||||
<view @click="projectClick(item.name,serviceProject)"
|
||||
v-for="(serviceProject,index) in item.serviceProjectList" :key="index">
|
||||
{{ serviceProject.name }}
|
||||
<view @click="projectClick(item?.name, serviceProject)" v-for="(serviceProject, index) in item.serviceProjectList" :key="index">
|
||||
<view style="border: 1px solid #cccccc;color: #9b9b9f">
|
||||
<view style="display: flex; justify-content: space-between">
|
||||
<text>项目名称:{{serviceProject.name}}</text>
|
||||
<text>项目类型:{{serviceProject.type.label}}</text>
|
||||
</view>
|
||||
<view style="display: flex; justify-content: space-between">
|
||||
<text>项目负责人:{{serviceProject.projectManagerMiniProgramUserInfo?.name?serviceProject.projectManagerMiniProgramUserInfo?.name:'无分配项目经理'}}</text>
|
||||
</view>
|
||||
<view>责任单位:{{serviceProject.securityUnitName}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
@ -37,10 +46,9 @@ import './myProject.scss'
|
|||
import {MyProjectList, ServiceProjectList} from "@/types/subPages/projectManager/myProject";
|
||||
|
||||
const myProjectList = ref<MyProjectList[]>()
|
||||
|
||||
const number = ref(0)
|
||||
const getMyServiceProject = async () => {
|
||||
const resp = await api.get<MyProjectList[]>(`/projectManageIndex/getMyServiceProject`)
|
||||
const resp = await api.get<MyProjectList[]>(`/mp/pmi/get_my_sp`)
|
||||
myProjectList.value = resp.data
|
||||
number.value = (resp.data?.length || 0)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<view style="display: flex;justify-content: space-between">
|
||||
<text style="font-size: 18px">{{ enterprisesUnitName }}-----{{ serviceProject?.name }}
|
||||
</text>
|
||||
<text>进行中</text>
|
||||
<!-- <text>进行中</text>-->
|
||||
</view>
|
||||
<view>
|
||||
<view style="float: left;width: 50%;" class="content">
|
||||
|
@ -62,12 +62,12 @@
|
|||
<text>职位:{{ item.workPost ? item.workPost : '无' }}</text>
|
||||
</view>
|
||||
<view style="display: flex;justify-content: space-between">
|
||||
<text>保安证件:{{ item.securityNumber ? item.securityNumber : '125241256451' }}</text>
|
||||
<text>保安证件:{{ item.securityNumber ? item.securityNumber : '无' }}</text>
|
||||
<text>出生年月:{{ dayjs(item.dateOfBirth).format('YYYY-MM-DD') }}</text>
|
||||
</view>
|
||||
<view style="display: flex;justify-content: space-between">
|
||||
<text>创建时间:{{ item.createTime }}</text>
|
||||
<text>身份证:{{ item.idCard }}</text>
|
||||
<text>身份证:{{ item.idCard?.desensitizedValue }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="projectDetailsTableIndex">
|
||||
|
@ -169,7 +169,7 @@ const projectDetailsTable = async () => {
|
|||
current: current.value
|
||||
}
|
||||
}
|
||||
const resp = await api.post<PagerVo<ServiceProjectSecurityUserPagerVo>>('/miniProgramUser/securityUserPager', queryParams)
|
||||
const resp = await api.post<PagerVo<ServiceProjectSecurityUserPagerVo>>('/mp/user/securityUserPager', queryParams)
|
||||
securityUserList.value = [...securityUserList.value, ...resp.data!.records]
|
||||
total.value = resp.data!.total
|
||||
isRefresher.value = false
|
||||
|
@ -189,7 +189,9 @@ const formAdd = () => {
|
|||
securityNumber: '',
|
||||
remark: '',
|
||||
homeAddress: '',
|
||||
telephone: ''
|
||||
telephone: '',
|
||||
photo:'',
|
||||
noSecurityNumberDesc:''
|
||||
} as SecurityUserFormParams
|
||||
Taro.navigateTo({url: `/subPages/projectManager/securityUserForm/securityUserForm?securityUser=${JSON.stringify(params)}&&type=formInput`})
|
||||
}
|
||||
|
@ -228,7 +230,7 @@ const deleteUssrID = (snowFlakeId: string) => {
|
|||
}
|
||||
// 二次删除
|
||||
const dialogOk = async () => {
|
||||
await api.delete(`/projectManageIndex/deleteSecurityUserByServiceProjectId`, {securityUserId: securityUserId.value})
|
||||
await api.delete(`/mp/user/del_security_user_id`, {securityUserId: securityUserId.value})
|
||||
initServiceProjectSecurityUserList()
|
||||
}
|
||||
// 详情
|
||||
|
@ -237,6 +239,7 @@ const detail = (item: ServiceProjectSecurityUserPagerVo) => {
|
|||
securityUserDetail.value = item
|
||||
}
|
||||
const securityUserEdit = (item: ServiceProjectSecurityUserPagerVo) => {
|
||||
console.log(item)
|
||||
const params = {...item, sex: item.sex.value}
|
||||
Taro.navigateTo({url: `/subPages/projectManager/securityUserForm/securityUserForm?securityUser=${JSON.stringify(params)}&type=formInput`})
|
||||
}
|
||||
|
@ -248,7 +251,7 @@ const generateMiniProgramQRCode = async () => {
|
|||
width: 200,
|
||||
}
|
||||
qrcodeVisible.value = true
|
||||
const resp = await api.get('/projectManageIndex/shareForm_QR_Code', paramsData, {
|
||||
const resp = await api.get('/wx/qrCode', paramsData, {
|
||||
header: {
|
||||
"content-type": 'application/x-www-form-urlencoded'
|
||||
},
|
||||
|
|
|
@ -1,8 +1,20 @@
|
|||
.form {
|
||||
.formButton {
|
||||
//position: fixed;
|
||||
bottom: 60px;
|
||||
display: flex;
|
||||
margin-top: auto;
|
||||
justify-content: space-around;
|
||||
margin-bottom: 30px
|
||||
-webkit-justify-content: space-around;
|
||||
margin-bottom: 10rpx;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 140px
|
||||
}
|
||||
}
|
||||
.uploadPictures{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 220px;
|
||||
height: 254px;
|
||||
border: 2px solid #d5d3d3;
|
||||
}
|
||||
|
|
|
@ -1,135 +1,243 @@
|
|||
<template>
|
||||
<view class="form">
|
||||
<nut-form ref="formRef" :model-value="formData" :rules="rules">
|
||||
<nut-form-item label="头像" prop="avatar">
|
||||
<!-- <view class="uploadPictures" @click="chooseImage">-->
|
||||
<!-- <view v-if="!formData.photo">-->
|
||||
<!-- <IconFont name="uploader" size="25" color="#98a7b0"></IconFont>-->
|
||||
<!-- </view>-->
|
||||
<!-- <image v-else :src="minioBaseUrl +formData.photo" style="width: 100%; height: 100%"></image>-->
|
||||
<!-- </view>-->
|
||||
<view @click="chooseImage" size>
|
||||
<image v-if="!formData.photo" src="@/assets/logo/avatar1.png" style="width: 50px; height: 50px"></image>
|
||||
<image v-else :src="minioBaseUrl +formData.photo" style="width: 160px; height: 128px"></image>
|
||||
</view>
|
||||
</nut-form-item>
|
||||
<nut-form-item label="身份证" prop="idCard">
|
||||
<view style="display: flex; justify-content: space-between; align-items: center">
|
||||
<nut-input v-model="formData.idCard" placeholder="请填写身份证" type="text" @blur="cardBlur" />
|
||||
<view style="color: #3a6bbe; width: 70px; text-align: center" @click="idCardBlur(formData, 0)">查询</view>
|
||||
</view>
|
||||
</nut-form-item>
|
||||
<nut-form-item label="姓名" prop="name">
|
||||
<nut-input v-model="formData.name" placeholder="请输入姓名" type="text"/>
|
||||
<nut-input v-model="formData.name" placeholder="请输入姓名" type="text" />
|
||||
</nut-form-item>
|
||||
<nut-form-item label="性别" prop="sex">
|
||||
<nut-radio-group v-model="formData.sex" direction="horizontal">
|
||||
<nut-radio v-for="item in SEX" :key="item.value" :label="item.value"
|
||||
>{{ item.label }}
|
||||
</nut-radio>
|
||||
<nut-radio v-for="item in SEX" :key="item.value" :label="item.value">{{ item.label }} </nut-radio>
|
||||
</nut-radio-group>
|
||||
</nut-form-item>
|
||||
<nut-form-item label="身份证" prop="idCard">
|
||||
<nut-input v-model="formData.idCard" placeholder="请填写身份证" type="text" @blur="idCardBlur"/>
|
||||
</nut-form-item>
|
||||
<nut-form-item label="出生日期" prop="dateOfBirth">
|
||||
<view @click="showPicker = true">
|
||||
{{
|
||||
formData.dateOfBirth ? dayjs(formData.dateOfBirth).format('YYYY-MM-DD') : '请选择出生年月'
|
||||
}}
|
||||
{{ formData.dateOfBirth ? dayjs(formData.dateOfBirth).format('YYYY-MM-DD') : '请选择出生年月' }}
|
||||
</view>
|
||||
</nut-form-item>
|
||||
<nut-form-item label="工作岗位" prop="workPost">
|
||||
<nut-input v-model="formData.workPost" placeholder="请输入工作岗位" type="text"/>
|
||||
<nut-input v-model="formData.workPost" placeholder="请输入工作岗位" type="text" />
|
||||
</nut-form-item>
|
||||
|
||||
<nut-form-item label="手机号" prop="telephone">
|
||||
<nut-input v-model="formData.telephone" placeholder="请输入手机号" type="text"/>
|
||||
<nut-input v-model="formData.telephone" placeholder="请输入手机号" type="text" />
|
||||
</nut-form-item>
|
||||
<nut-form-item label="籍贯" prop="nativePlace">
|
||||
<nut-input v-model="formData.nativePlace" placeholder="请输入籍贯" type="text"/>
|
||||
<nut-input v-model="formData.nativePlace" placeholder="请输入籍贯" type="text" />
|
||||
</nut-form-item>
|
||||
<nut-form-item label="地址" prop="homeAddress">
|
||||
<nut-input v-model="formData.homeAddress" placeholder="请输入地址" type="text"/>
|
||||
<nut-input v-model="formData.homeAddress" placeholder="请输入地址" type="text" />
|
||||
</nut-form-item>
|
||||
<nut-form-item label="保安证号" prop="securityNumber">
|
||||
<nut-input v-model="formData.securityNumber" placeholder="请输入保安证号" type="text"/>
|
||||
<nut-form-item label="保安证件号" prop="securityNumber">
|
||||
<nut-input v-model="formData.securityNumber" placeholder="请输入保安证号" type="text" />
|
||||
</nut-form-item>
|
||||
<nut-form-item label="无证说明" v-if="!formData.securityNumber">
|
||||
<nut-input v-model="formData.noSecurityNumberDesc" placeholder="无证说明" type="text" />
|
||||
</nut-form-item>
|
||||
<nut-form-item label="备注" prop="remark">
|
||||
<nut-input v-model="formData.remark" placeholder="请填写备注" type="text"/>
|
||||
<nut-input v-model="formData.remark" placeholder="请填写备注" type="text" />
|
||||
</nut-form-item>
|
||||
</nut-form>
|
||||
<view class="formButton">
|
||||
<nut-button style="width: 45%" type="success" size="small" @click="submit">提交</nut-button>
|
||||
<nut-button style="width: 45%" size="small" @click="formRef?.reset()">重置表单</nut-button>
|
||||
<nut-button style="width: 45%" size="small" @click="reset">重置表单</nut-button>
|
||||
</view>
|
||||
<nut-popup v-model:visible="showPicker" position="bottom">
|
||||
<nut-date-picker
|
||||
v-model="formData.dateOfBirth"
|
||||
:three-dimensional="false"
|
||||
:min-date="new Date(1900,1,1)"
|
||||
:max-date="new Date(2100,1,1)"
|
||||
:min-date="new Date(1900, 1, 1)"
|
||||
:max-date="new Date(2100, 1, 1)"
|
||||
@confirm="showPicker = false"
|
||||
@cancel="showPicker = false"
|
||||
></nut-date-picker>
|
||||
</nut-popup>
|
||||
<nut-dialog content="详情" v-model:visible="visible" @ok="onOk" @cancel="cancel">
|
||||
<slot>
|
||||
<view style="margin-bottom: 5px">
|
||||
<view>姓名:{{ securityNumberByIdCard?.name ? securityNumberByIdCard?.name : '无' }}</view>
|
||||
<view>保安证件号:{{ securityNumberByIdCard?.bayzh ? securityNumberByIdCard?.bayzh : '无' }}</view>
|
||||
<view>身份证:{{ securityNumberByIdCard?.sfzhm ? securityNumberByIdCard?.sfzhm : '无' }}</view>
|
||||
</view>
|
||||
</slot>
|
||||
</nut-dialog>
|
||||
</view>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import {ref} from "vue";
|
||||
import {enumSelectNodes} from "@/enums";
|
||||
import {FormRules} from "@nutui/nutui-taro/dist/types/__VUE/form/types";
|
||||
import api from "@/request";
|
||||
import { ref } from 'vue'
|
||||
import { enumSelectNodes } from '@/enums'
|
||||
import { FormRules } from '@nutui/nutui-taro/dist/types/__VUE/form/types'
|
||||
import api from '@/request'
|
||||
import './securityUserForm.scss'
|
||||
import Taro, {useLoad} from "@tarojs/taro";
|
||||
import dayjs from "dayjs";
|
||||
import {SecurityUserFormParams} from "@/types/subPages/projectManager/securityUserForm";
|
||||
import {FormInstance} from "@nutui/nutui-taro";
|
||||
import Taro, { useLoad } from '@tarojs/taro'
|
||||
import dayjs from 'dayjs'
|
||||
import { SecurityUserFormParams, securityNumberByIdCard } from '@/types/subPages/projectManager/securityUserForm'
|
||||
import { FormInstance } from '@nutui/nutui-taro'
|
||||
import { generateSimpleObjectName, getResignedObjectUrl } from '@/utils'
|
||||
import {IconFont} from "@nutui/icons-vue-taro";
|
||||
|
||||
const SEX = enumSelectNodes('Sex')
|
||||
|
||||
const minioBaseUrl = process.env.TARO_APP_MINIO_URL
|
||||
const showPicker = ref(false)
|
||||
|
||||
const type = ref<'formInput' | 'QcCodeInput'>(null!);
|
||||
|
||||
const Url = ref('')
|
||||
const type = ref<'formInput' | 'QcCodeInput'>(null!)
|
||||
const formData = ref<SecurityUserFormParams>({} as any)
|
||||
const formRef = ref<FormInstance>(null!)
|
||||
const visible = ref<boolean>(false)
|
||||
const securityNumberByIdCard = ref<securityNumberByIdCard>()
|
||||
const uploadRef = ref<any>(null)
|
||||
const modelValue = ref('')
|
||||
|
||||
const rules: FormRules = {
|
||||
name: [
|
||||
{required: true, message: "请输入姓名"},
|
||||
],
|
||||
sex: [{required: true, message: "请选择性别"}],
|
||||
name: [{ required: true, message: '请输入姓名' }],
|
||||
sex: [{ required: true, message: '请选择性别' }],
|
||||
idCard: [
|
||||
{required: true, message: "请输入身份证号"},
|
||||
{ required: true, message: '请输入身份证号' },
|
||||
{
|
||||
regex: /^(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))((0[1-9])|([12][0-9])|(30|31))\d{3}(\d|X)$)/,
|
||||
message: "身份证格式错误",
|
||||
message: '身份证格式错误',
|
||||
},
|
||||
],
|
||||
telephone: [
|
||||
{required: true, message: "请输入手机号"},
|
||||
]
|
||||
};
|
||||
telephone: [{ required: true, message: '请输入手机号' }],
|
||||
}
|
||||
|
||||
useLoad((options) => {
|
||||
type.value = options.type;
|
||||
type.value = options.type
|
||||
if (type.value === 'QcCodeInput') {
|
||||
formData.value = {
|
||||
name: '',
|
||||
serviceProjectId: options.pid,
|
||||
securityUnitId: options.uid,
|
||||
sex: 0,
|
||||
idCard: '',
|
||||
dateOfBirth: null
|
||||
idCard: null,
|
||||
telephone: null,
|
||||
dateOfBirth: null,
|
||||
noSecurityNumberDesc: options.noSecurityNumberDesc,
|
||||
photo: '',
|
||||
}
|
||||
} else {
|
||||
formData.value = JSON.parse(options.securityUser)
|
||||
const form = JSON.parse(options.securityUser)
|
||||
formData.value = Object.assign({}, form, {
|
||||
idCard: form.idCard.originalValue,
|
||||
telephone: form.telephone.originalValue,
|
||||
photo: form.photo
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const idCardBlur = (e: any) => {
|
||||
const value = e.detail.value
|
||||
const idCardBlur = async (e: any, num: number) => {
|
||||
const value = e.idCard
|
||||
if (value) {
|
||||
Taro.request({
|
||||
url: 'https://www.hnjinglian.cn:5678/common/querySecurityNumberByIdCard',
|
||||
data: {
|
||||
idCard: value,
|
||||
},
|
||||
method: 'GET',
|
||||
success: ({ data }) => {
|
||||
visible.value = true
|
||||
securityNumberByIdCard.value = data.data
|
||||
},
|
||||
})
|
||||
return
|
||||
} else {
|
||||
visible.value = false
|
||||
console.log(value)
|
||||
}
|
||||
cardBlur(value, num)
|
||||
}
|
||||
|
||||
const cardBlur = (e, num) => {
|
||||
let value = ''
|
||||
if (num === 0) {
|
||||
value = e
|
||||
} else {
|
||||
value = e.detail.value
|
||||
}
|
||||
if (!value?.length || value.length < 18) {
|
||||
formData.value.dateOfBirth = null;
|
||||
formData.value.dateOfBirth = null
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
const birthDate = value.substring(6, 14);
|
||||
const year = birthDate.substring(0, 4);
|
||||
const month = birthDate.substring(4, 6);
|
||||
const day = birthDate.substring(6, 8);
|
||||
const birthDate = value.substring(6, 14)
|
||||
const year = birthDate.substring(0, 4)
|
||||
const month = birthDate.substring(4, 6)
|
||||
const day = birthDate.substring(6, 8)
|
||||
formData.value.dateOfBirth = new Date(parseInt(year), parseInt(month) - 1, parseInt(day))
|
||||
}
|
||||
|
||||
const onOk = () => {
|
||||
formData.value.securityNumber = securityNumberByIdCard.value?.bayzh
|
||||
formData.value.name = securityNumberByIdCard.value?.name
|
||||
}
|
||||
const cancel = () => {
|
||||
formData.value.securityNumber = ''
|
||||
formData.value.name = ''
|
||||
visible.value = false
|
||||
}
|
||||
const chooseImage = () => {
|
||||
Taro.chooseMedia({
|
||||
count: 1, // 选择一个文件
|
||||
mediaType: ['image', 'video'],
|
||||
sourceType: ['album', 'camera'],
|
||||
sizeType:['original', 'compressed'],
|
||||
camera: 'front',
|
||||
success: async (res) => {
|
||||
Url.value = res.tempFiles[0].tempFilePath
|
||||
const objectName = generateSimpleObjectName(Url.value, '/securityUser')
|
||||
const uploadUrl = await getResignedObjectUrl(process.env.TARO_APP_MINIO_BUCKET, objectName)
|
||||
|
||||
modelValue.value = '/' + process.env.TARO_APP_MINIO_BUCKET + objectName
|
||||
// 使用 wx.getFileSystemManager().readFileSync 读取文件的二进制内容
|
||||
const fs = Taro.getFileSystemManager()
|
||||
const fileData = fs.readFileSync(Url.value) // 返回的是文件的二进制内容
|
||||
// 发送 PUT 请求上传二进制文件
|
||||
Taro.request({
|
||||
url: uploadUrl, // 后端上传接口
|
||||
method: 'PUT',
|
||||
header: {
|
||||
'Content-Type': 'application/octet-stream', // 设置为二进制流
|
||||
},
|
||||
data: fileData, // 传递二进制数据
|
||||
success(res) {
|
||||
formData.value.photo = modelValue.value
|
||||
console.log('上传成功', res)
|
||||
},
|
||||
fail(err) {
|
||||
console.error('上传失败', err)
|
||||
},
|
||||
})
|
||||
},
|
||||
fail(err) {
|
||||
console.error('选择文件失败', err)
|
||||
},
|
||||
})
|
||||
}
|
||||
const submit = () => {
|
||||
formRef.value?.validate().then(async ({valid}) => {
|
||||
formData.value.photo = modelValue.value
|
||||
formRef.value?.validate().then(async ({ valid }) => {
|
||||
if (valid) {
|
||||
let url: string;
|
||||
let url: string
|
||||
if (type.value === 'formInput') {
|
||||
url = '/projectManageIndex/saveOrUpdateSecurityUser'
|
||||
url = '/mp/user/add_security_user_upd'
|
||||
} else {
|
||||
url = '/miniProgramUser/qrCodeFormInputSecurityUser'
|
||||
url = '/mp/user/qrCodeFormInputSecurityUser'
|
||||
}
|
||||
const resp = await api.post(url, formData.value)
|
||||
Taro.showToast({
|
||||
|
@ -144,16 +252,23 @@ const submit = () => {
|
|||
securityUnitId: formData.value.securityUnitId,
|
||||
name: '',
|
||||
workPost: '',
|
||||
telephone: '',
|
||||
telephone: null,
|
||||
sex: 0,
|
||||
nativePlace: '',
|
||||
idCard: '',
|
||||
idCard: null,
|
||||
dateOfBirth: null,
|
||||
securityNumber: '',
|
||||
remark: '',
|
||||
homeAddress: ''
|
||||
homeAddress: '',
|
||||
noSecurityNumberDesc: '',
|
||||
photo: '',
|
||||
}
|
||||
uploadRef.value?.clearUploadQueue()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
formRef.value?.reset()
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
.userinform {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.userItem {
|
||||
color: #7b7b7b;
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.textIndex {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
width: 96%;
|
||||
}
|
||||
|
||||
.singleChoice {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin: 0 20px;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export default definePageConfig({
|
||||
navigationBarTitleText: '',
|
||||
})
|
|
@ -0,0 +1,121 @@
|
|||
<template>
|
||||
<view class="userinform">
|
||||
<view class="userItem">
|
||||
<!-- v-model="item.snowFlakeId" 展开所有 -->
|
||||
<nut-collapse v-model="item.snowFlakeId" accordion v-for="(item, index) in starRating[findIndex].itemList" :key="item.snowFlakeId">
|
||||
<nut-collapse-item :name="item.snowFlakeId" :title="item.name">
|
||||
<view class="singleChoice">
|
||||
<nut-radio-group v-if="item.type.value === 'radio'" v-model="item.selectedID" @change="(modelValue) => onChange(modelValue, item.name)">
|
||||
<nut-radio v-for="(items, indexs) in item.standardList" size="40" :label="items.snowFlakeId" :key="indexs"> {{ items.name }}</nut-radio>
|
||||
</nut-radio-group>
|
||||
<!-- 不能直接去更改 v-model 绑定的 这个数据 ,否则会造成无限递归-->
|
||||
<nut-checkbox-group v-else v-model="item.selectedGroup" @change="(arr) => checkboxGroupChange(arr, index)" style="display: flex; flex-direction: column">
|
||||
<nut-checkbox
|
||||
v-model="items.isSelected"
|
||||
@change="(state, label) => checkboxChange(state, label, index, i)"
|
||||
v-for="(items, i) in item.standardList"
|
||||
size="40"
|
||||
:label="items.snowFlakeId"
|
||||
:key="i"
|
||||
style="margin-bottom: 20rpx"
|
||||
shape="button"
|
||||
>{{ items.name}}</nut-checkbox
|
||||
>
|
||||
</nut-checkbox-group>
|
||||
</view>
|
||||
</nut-collapse-item>
|
||||
</nut-collapse>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Taro, { useLoad, useUnload } from '@tarojs/taro'
|
||||
import { ref, computed, watch, nextTick } from 'vue'
|
||||
|
||||
import { useDailyStore } from '@/store/daily.ts'
|
||||
const store = useDailyStore()
|
||||
const starRating = ref([])
|
||||
const findIndex = ref(0)
|
||||
const airdefenceEnumdata = ref([])
|
||||
useLoad((options) => {
|
||||
Taro.setNavigationBarTitle({
|
||||
title: options.name,
|
||||
})
|
||||
|
||||
findIndex.value = options.index
|
||||
})
|
||||
|
||||
const daily = computed(() => store.getdailyinspection)
|
||||
|
||||
watch(
|
||||
daily,
|
||||
(newData) => {
|
||||
starRating.value = newData
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
/**
|
||||
* @assessmentRecordDetails 选择后的数据用于提交
|
||||
*/
|
||||
const assessmentRecordDetails = ref([])
|
||||
|
||||
const onChange = (modelValue, name) => {
|
||||
starRating.value[findIndex.value].itemList.forEach((element) => {
|
||||
if (name === element.name) {
|
||||
element.selectedID = modelValue
|
||||
element.standardList.forEach((item) => {
|
||||
if (item.snowFlakeId == modelValue) {
|
||||
element.selected_points = item.deductionPoints //添加扣分项
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const checkboxGroupChange = function (arr, index) {
|
||||
let points = 0
|
||||
|
||||
starRating.value[findIndex.value].itemList.forEach((element, i) => {
|
||||
if (i === index) {
|
||||
element.selectedGroup.forEach((selectedId) => {
|
||||
element.standardList.forEach((standardItem) => {
|
||||
if (selectedId === standardItem.snowFlakeId) {
|
||||
points += standardItem.deductionPoints
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
starRating.value[findIndex.value].itemList[index].selected_points = points
|
||||
}
|
||||
const checkboxChange = async function (state, label, index, i) {
|
||||
// DOM 还未更新
|
||||
await nextTick() //等待下一次 DOM 更新刷新的工具方法。
|
||||
// DOM 此时已经更新
|
||||
|
||||
let arr
|
||||
|
||||
if (label === '达标' && i === 0) {
|
||||
arr = ['null']
|
||||
} else {
|
||||
arr = starRating.value[findIndex.value].itemList[index].selectedGroup.filter((selectedId) => selectedId != 'null')
|
||||
}
|
||||
if (arr?.length === 0) {
|
||||
arr = ['null']
|
||||
}
|
||||
|
||||
if (JSON.stringify(arr) !== JSON.stringify(starRating.value[findIndex.value].itemList[index].selectedGroup)) {
|
||||
starRating.value[findIndex.value].itemList[index].selectedGroup = arr
|
||||
}
|
||||
}
|
||||
useUnload(() => {
|
||||
let points = 0
|
||||
starRating.value[findIndex.value].itemList.forEach((element) => {
|
||||
points += element.selected_points
|
||||
})
|
||||
starRating.value[findIndex.value].currentScore = points
|
||||
store.dailyinspectionList([...starRating.value])
|
||||
})
|
||||
</script>
|
|
@ -0,0 +1,65 @@
|
|||
.sign-box {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.fixedIcon {
|
||||
z-index: 1000;
|
||||
position: fixed;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
height: 100rpx;
|
||||
width: 100rpx;
|
||||
}
|
||||
|
||||
.sign-view {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sigh_btns_false {
|
||||
position: absolute;
|
||||
bottom: 15rpx;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100rpx;
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.sigh_btns {
|
||||
transform: rotate(90deg);
|
||||
transform-origin: center
|
||||
}
|
||||
|
||||
.sigh_btns_noRotate {}
|
||||
|
||||
.sigh_btns_true {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 20%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
.mycanvas {
|
||||
width: 100%;
|
||||
background-color: #ececec;
|
||||
}
|
||||
|
||||
.canvsborder {
|
||||
border: 1rpx solid #333;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 10000rpx;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export default definePageConfig({
|
||||
navigationBarTitleText: '签名',
|
||||
disableScroll: true
|
||||
})
|
|
@ -0,0 +1,174 @@
|
|||
<template>
|
||||
<!-- 签字功能 -->
|
||||
<view catchtouchmove="true">
|
||||
<view class="sign-box">
|
||||
<view class="fixedIcon" @click.stop="changeDirection">
|
||||
<image style="height: 100rpx; width: 100rpx" :src="icon"></image>
|
||||
</view>
|
||||
|
||||
<canvas class="mycanvas" :style="{ height: height + 'px' }" canvas-id="mycanvas" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend"></canvas>
|
||||
<canvas canvas-id="camCacnvs" :style="{ height: width + 'px' }" class="canvsborder"></canvas>
|
||||
|
||||
<view :class="direction ? 'sigh_btns_true' : 'sigh_btns_false'">
|
||||
<nut-button :class="direction ? 'sigh_btns' : 'sigh_btns_noRotate'" style="height: 60rpx" shape="square" type="info" @click="handleCancel"> 取消 </nut-button>
|
||||
<nut-button :class="direction ? 'sigh_btns' : 'sigh_btns_noRotate'" style="height: 60rpx" shape="square" type="info" @click="handleReset"> 重写 </nut-button>
|
||||
<nut-button :class="direction ? 'sigh_btns' : 'sigh_btns_noRotate'" style="height: 60rpx" shape="square" type="info" @click="handleConfirm"> 确认 </nut-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import './signature.scss'
|
||||
import Taro, { useLoad, useUnload } from '@tarojs/taro'
|
||||
import { ref, onMounted, watch, computed } from 'vue'
|
||||
import icon from '@/assets/images/rotate1.png'
|
||||
const _index = ref(0)
|
||||
import { useDailyStore } from '@/store/daily'
|
||||
const store = useDailyStore()
|
||||
|
||||
const width = ref(0)
|
||||
const height = ref(300)
|
||||
const points = ref([]) // 画笔路径点集合
|
||||
const tempPoint = ref([]) // 当前签名路径
|
||||
let that
|
||||
let id
|
||||
let type
|
||||
useLoad((options) => {
|
||||
_index.value = Number(options.index)
|
||||
Taro.setNavigationBarTitle({
|
||||
title: options.name,
|
||||
})
|
||||
})
|
||||
const ctx = ref(null)
|
||||
onMounted(() => {
|
||||
that = this
|
||||
const { windowWidth, windowHeight } = Taro.getSystemInfoSync()
|
||||
width.value = windowWidth
|
||||
height.value = windowHeight * 0.98 // 控制画板的宽高
|
||||
|
||||
// 创建绘图上下文
|
||||
ctx.value = Taro.createCanvasContext('mycanvas', this)
|
||||
ctx.value.lineWidth = 2
|
||||
ctx.value.lineCap = 'round'
|
||||
ctx.value.lineJoin = 'round'
|
||||
})
|
||||
|
||||
const touchstart = (e) => {
|
||||
const startX = e.changedTouches[0].x
|
||||
const startY = e.changedTouches[0].y
|
||||
points.value.push({ X: startX, Y: startY })
|
||||
ctx.value.beginPath()
|
||||
}
|
||||
|
||||
const touchmove = (e) => {
|
||||
const moveX = e.changedTouches[0].x
|
||||
const moveY = e.changedTouches[0].y
|
||||
points.value.push({ X: moveX, Y: moveY })
|
||||
if (points.value.length >= 2) {
|
||||
draw()
|
||||
}
|
||||
tempPoint.value.push({ X: moveX, Y: moveY })
|
||||
}
|
||||
|
||||
const touchend = () => {
|
||||
points.value = []
|
||||
}
|
||||
|
||||
const draw = () => {
|
||||
const point1 = points.value[0]
|
||||
const point2 = points.value[1]
|
||||
points.value.shift()
|
||||
ctx.value.moveTo(point1.X, point1.Y)
|
||||
ctx.value.lineTo(point2.X, point2.Y)
|
||||
ctx.value.stroke()
|
||||
ctx.value.draw(true)
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
Taro.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const handleReset = () => {
|
||||
ctx.value.clearRect(0, 0, width.value, height.value)
|
||||
ctx.value.draw(true)
|
||||
tempPoint.value = []
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (tempPoint.value.length === 0) {
|
||||
Taro.showToast({ title: '请先签名', icon: 'none', duration: 2000 })
|
||||
return
|
||||
}
|
||||
|
||||
Taro.canvasToTempFilePath({
|
||||
canvasId: 'mycanvas',
|
||||
success: (res) => {
|
||||
console.log('canvasToTempFilePath______________', res)
|
||||
|
||||
const tempPath = res.tempFilePath
|
||||
const ctx = Taro.createCanvasContext('camCacnvs', that)
|
||||
const scale = 0.5
|
||||
var targetWidth
|
||||
var targetHeight
|
||||
// 前置图片旋转处理 ___________________________________________________________________
|
||||
if (direction.value) {
|
||||
targetWidth = height.value * scale
|
||||
targetHeight = width.value * scale
|
||||
// 计算旋转后的外接矩形尺寸
|
||||
const angle = (270 * Math.PI) / 180 // 逆时针旋转 270 度
|
||||
const rotatedWidth = Math.abs(width.value * Math.cos(angle)) + Math.abs(height.value * Math.sin(angle))
|
||||
const rotatedHeight = Math.abs(height.value * Math.cos(angle)) + Math.abs(width.value * Math.sin(angle))
|
||||
// 计算平移量
|
||||
const offsetX = 0 // 如果不需要水平偏移,则为 0
|
||||
const offsetY = rotatedHeight - targetHeight // 计算 y 轴的平移量
|
||||
// 将画布原点平移到适当位置
|
||||
ctx.translate(offsetX, offsetY)
|
||||
// 旋转画布
|
||||
ctx.rotate(angle)
|
||||
ctx.drawImage(tempPath, 0, 0, targetHeight, targetWidth)
|
||||
} else {
|
||||
targetWidth = width.value * scale
|
||||
targetHeight = height.value * scale
|
||||
ctx.drawImage(tempPath, 0, 0, targetWidth, targetHeight)
|
||||
}
|
||||
|
||||
ctx.draw(false, () => {
|
||||
Taro.canvasToTempFilePath({
|
||||
canvasId: 'camCacnvs',
|
||||
width: targetWidth,
|
||||
height: targetHeight,
|
||||
success: (compressedRes) => {
|
||||
Taro.getFileSystemManager().readFile({
|
||||
filePath: compressedRes.tempFilePath,
|
||||
encoding: 'base64',
|
||||
success: (res) => {
|
||||
const base64Image = 'data:image/jpeg;base64,' + res.data
|
||||
|
||||
console.log('base64Image_________________________', base64Image)
|
||||
|
||||
if (_index.value === 1) {
|
||||
store.change_base64_1(base64Image)
|
||||
Taro.navigateBack({ delta: 1 })
|
||||
} else {
|
||||
store.change_base64_2(base64Image)
|
||||
Taro.navigateBack({ delta: 1 })
|
||||
}
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @direction false 竖屏,true 横屏
|
||||
*/
|
||||
|
||||
const direction = ref(true)
|
||||
const changeDirection = () => {
|
||||
direction.value = !direction.value
|
||||
Taro.vibrateShort({ type: 'medium' }).then()
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,23 @@
|
|||
import dayjs from "dayjs";
|
||||
import api from "@/request";
|
||||
|
||||
export const generateSimpleObjectName = (fileName: string, parentDir?: String): string => {
|
||||
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
let objectName = parentDir + dayjs().format('/YYYY/MM/DD/') + uuid.replace(/-/g, '');
|
||||
console.log(fileName,objectName,'4444')
|
||||
if (fileName && fileName.length > 0) {
|
||||
objectName += fileName.substring(fileName.lastIndexOf('.'))
|
||||
}
|
||||
console.log(objectName,'888')
|
||||
return objectName;
|
||||
}
|
||||
|
||||
export const getResignedObjectUrl = async (bucketName: string, objectName: string): Promise<string> => {
|
||||
return (await api.get<string>('/common/getResignedObjectUrl', {
|
||||
bucketName,
|
||||
objectName
|
||||
})).data as string;
|
||||
}
|
|
@ -25,6 +25,10 @@ declare namespace NodeJS {
|
|||
TARO_APP_ID: string
|
||||
/** 后台服务接口地址 **/
|
||||
TARO_APP_BASE_API: string
|
||||
|
||||
TARO_APP_MINIO_BUCKET:string
|
||||
|
||||
TARO_APP_MINIO_URL:string
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,3 +106,59 @@ interface BaseEnum<T, E = Record<string, any>> {
|
|||
label: string;
|
||||
extData: E;
|
||||
}
|
||||
|
||||
interface StandardList {
|
||||
ckItemId: string
|
||||
deductionPoints: number
|
||||
name: string
|
||||
snowFlakeId: string
|
||||
isSelected: boolean
|
||||
}
|
||||
interface ItemList {
|
||||
ckGroupId: string
|
||||
name: string
|
||||
remark: string
|
||||
snowFlakeId: string
|
||||
standardList: StandardList[]
|
||||
type: { value: string; label: string }
|
||||
selectedID: string
|
||||
selected_points: number
|
||||
selectedGroup: any[]
|
||||
}
|
||||
interface StarRating {
|
||||
itemList: ItemList[]
|
||||
name: string
|
||||
remark: string
|
||||
snowFlakeId: string
|
||||
totalScore: number
|
||||
currentScore: number
|
||||
}
|
||||
interface UnitEnterprisesUnitList {
|
||||
label: string
|
||||
value: string
|
||||
extData: {
|
||||
type: {
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
}
|
||||
}
|
||||
interface CkProjectListByType {
|
||||
label: string
|
||||
value: string
|
||||
extData: {
|
||||
createTime: string
|
||||
remark: string
|
||||
totalScore: number
|
||||
type: {
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
}
|
||||
}
|
||||
interface Item {
|
||||
itemList: any[] // 根据实际情况调整类型
|
||||
snowFlakeId: string
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
export interface DataStatisticsRes {
|
||||
/*企事业单位数量 */
|
||||
enterprisesUnitCount: number;
|
||||
|
||||
/*服务项目数量 */
|
||||
serviceProjectCount: number;
|
||||
|
||||
/*保安人员数量 */
|
||||
securityUserCount: number;
|
||||
|
||||
/*无证保安人员数量 */
|
||||
noCardSecurityUserCount: number;
|
||||
}
|
|
@ -15,6 +15,7 @@ export interface MyProjectList {
|
|||
securityUnitId: string;
|
||||
street?: string;
|
||||
streetName?: string;
|
||||
type?:any
|
||||
}
|
||||
|
||||
export interface ContactPersonInfo {
|
||||
|
@ -30,24 +31,27 @@ export interface ServiceProjectList {
|
|||
name?: string;
|
||||
remark?: string;
|
||||
securityUserTotal?: number;
|
||||
securityUnitName?:string;
|
||||
serviceArea?: number;
|
||||
snowFlakeId?: string;
|
||||
staffTotal?: number;
|
||||
type?: string;
|
||||
type?: any;
|
||||
projectManagerMiniProgramUserInfo?: ProgramUserInfo
|
||||
}
|
||||
|
||||
export interface ProgramUserInfo {
|
||||
idCard: null
|
||||
name: string
|
||||
telephone: string
|
||||
idCard?: null
|
||||
name?: string
|
||||
telephone?: string
|
||||
}
|
||||
|
||||
export interface ServiceProjectSecurityUserPagerVo {
|
||||
createTime?: string;
|
||||
dateOfBirth?: string;
|
||||
homeAddress?: string;
|
||||
idCard?: string;
|
||||
idCard?: {
|
||||
desensitizedValue?:string
|
||||
originalValue?:string
|
||||
};
|
||||
name?: string;
|
||||
nativePlace?: string;
|
||||
remark?: string;
|
||||
|
@ -59,3 +63,4 @@ export interface ServiceProjectSecurityUserPagerVo {
|
|||
workPost?: string;
|
||||
sex: BaseEnum<number>
|
||||
}
|
||||
|
||||
|
|
|
@ -2,14 +2,27 @@ export interface SecurityUserFormParams {
|
|||
snowFlakeId?: string;
|
||||
securityUnitId: string;
|
||||
serviceProjectId: string;
|
||||
name?: string;
|
||||
name: string | undefined;
|
||||
workPost?: string;
|
||||
telephone?: string;
|
||||
telephone: value | null;
|
||||
sex: number;
|
||||
nativePlace?: string;
|
||||
idCard: string;
|
||||
idCard: value | null;
|
||||
dateOfBirth?: Date | null;
|
||||
securityNumber?: string;
|
||||
photo?:string;
|
||||
remark?: string;
|
||||
noSecurityNumberDesc:string;
|
||||
homeAddress?: string
|
||||
}
|
||||
|
||||
export interface value{
|
||||
desensitizedValue?:string
|
||||
originalValue?:string
|
||||
}
|
||||
|
||||
export interface securityNumberByIdCard{
|
||||
name: string | undefined
|
||||
bayzh?: string
|
||||
sfzhm?: string
|
||||
}
|
||||
|
|
|
@ -7,7 +7,22 @@ VITE_DROP_CONSOLE=false
|
|||
VITE_APP_BASE_API=/api
|
||||
# VITE_APP_PROXY_URL=http://localhost:8765
|
||||
VITE_APP_PROXY_URL=http://172.10.10.93:8765
|
||||
|
||||
#
|
||||
|
||||
# rsa 公钥
|
||||
VITE_APP_RSA_PUBLIC_KEY=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJps/EXxxSpEM1Ix4R0NWIOBciHCr7P7coDT8tNKfelgR7txcJOqHCO/MIWe7T04aHQTcpQxqx9hMca7dbqz8TZpz9jvLzE/6ZonVKxHsoFnNlHMp1/CPAJ9f6D9wYicum2KltJkmQ0g//D9W2zPCYoGOmSRFcZx/KEBa4EM53jQIDAQAB
|
||||
|
||||
# 高德 myx
|
||||
# VITE_APP_GAODE_KEY=ca549d915cb38803582ca7e85c5f972c
|
||||
# VITE_APP_GAODE_VERSION=2.0
|
||||
# VITE_APP_SECURITY_JS_CODE=f464462874676b3f1469780a62e5b921
|
||||
|
||||
|
||||
# 高德 lz
|
||||
VITE_APP_GAODE_KEY=f379a3f860a68d7438526275d6a94b05
|
||||
VITE_APP_GAODE_VERSION=2.0
|
||||
VITE_APP_SECURITY_JS_CODE=432125a0f8d8cad2dac38b77d6f6728f
|
||||
|
||||
# minio
|
||||
VITE_APP_MINIO_URL=http://118.253.177.137:9000
|
||||
VITE_APP_MINIO_BUCKET=police-security-dev
|
|
@ -5,4 +5,15 @@ VITE_DROP_CONSOLE=true
|
|||
|
||||
# axios
|
||||
VITE_APP_BASE_API=/api
|
||||
VITE_APP_PROXY_URL=https://172.10.10.238:8765
|
||||
VITE_APP_PROXY_URL=http://172.10.10.93:8765
|
||||
# rsa 公钥
|
||||
VITE_APP_RSA_PUBLIC_KEY=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpu1C3JHZ+Ng/eVVCZtwKsOZv9RktpAL13pKy4FoRHyNv2t8TPV2AMzLzfEzlWx001nBxyVxEMR2N9jAcqFLHv7r16ciOzbtzB9dky2G+bc9jIs4/EdVK5bAZcPRh5Jrb78sC9PHyR4AeceDyCIKHLUbWBJB4NTZE0s1Wh5kMynQIDAQAB
|
||||
|
||||
# 高德
|
||||
VITE_APP_GAODE_KEY=f379a3f860a68d7438526275d6a94b05
|
||||
VITE_APP_GAODE_VERSION=2.0
|
||||
VITE_APP_SECURITY_JS_CODE=432125a0f8d8cad2dac38b77d6f6728f
|
||||
|
||||
# minio
|
||||
VITE_APP_MINIO_URL=https://www.hnjinglian.cn:9002
|
||||
VITE_APP_MINIO_BUCKET=police-security
|
|
@ -9,6 +9,8 @@ lerna-debug.log*
|
|||
|
||||
node_modules
|
||||
dist
|
||||
policeManagement
|
||||
package-lock.json
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ declare module 'vue' {
|
|||
export interface GlobalComponents {
|
||||
AAvatar: typeof import('ant-design-vue/es')['Avatar']
|
||||
AButton: typeof import('ant-design-vue/es')['Button']
|
||||
ACard: typeof import('ant-design-vue/es')['Card']
|
||||
ACascader: typeof import('ant-design-vue/es')['Cascader']
|
||||
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
|
||||
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
|
||||
|
@ -17,10 +16,11 @@ declare module 'vue' {
|
|||
AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
|
||||
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
|
||||
ADivider: typeof import('ant-design-vue/es')['Divider']
|
||||
ADrawer: typeof import('ant-design-vue/es')['Drawer']
|
||||
AdministrativeDivisionTree: typeof import('./src/components/tree/AdministrativeDivisionTree.vue')['default']
|
||||
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
|
||||
AForm: typeof import('ant-design-vue/es')['Form']
|
||||
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||
AImage: typeof import('ant-design-vue/es')['Image']
|
||||
AInput: typeof import('ant-design-vue/es')['Input']
|
||||
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
|
||||
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
||||
|
@ -34,12 +34,11 @@ declare module 'vue' {
|
|||
APagination: typeof import('ant-design-vue/es')['Pagination']
|
||||
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
||||
APopover: typeof import('ant-design-vue/es')['Popover']
|
||||
ARadio: typeof import('ant-design-vue/es')['Radio']
|
||||
AProgress: typeof import('ant-design-vue/es')['Progress']
|
||||
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
||||
ARangePicker: typeof import('ant-design-vue/es')['RangePicker']
|
||||
ARow: typeof import('ant-design-vue/es')['Row']
|
||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||
ASpace: typeof import('ant-design-vue/es')['Space']
|
||||
ASpin: typeof import('ant-design-vue/es')['Spin']
|
||||
ASubMenu: typeof import('ant-design-vue/es')['SubMenu']
|
||||
|
@ -53,15 +52,14 @@ declare module 'vue' {
|
|||
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
||||
ATreeSelect: typeof import('ant-design-vue/es')['TreeSelect']
|
||||
FormProMax: typeof import('./src/components/form/FormProMax.vue')['default']
|
||||
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
|
||||
IconFont: typeof import('./src/components/iconfont/IconFont.vue')['default']
|
||||
Layout: typeof import('./src/components/layout/layout.vue')['default']
|
||||
LayoutHeader: typeof import('./src/components/layout/header/LayoutHeader.vue')['default']
|
||||
MapContainer: typeof import('./src/components/aMap/MapContainer.vue')['default']
|
||||
MenuItem: typeof import('./src/components/layout/MenuItem.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
SingleImageFileUpload: typeof import('./src/components/upload/SingleImageFileUpload.vue')['default']
|
||||
Sliber: typeof import('./src/components/layout/sliber/sliber.vue')['default']
|
||||
SystemMenus: typeof import('./src/components/layout/SystemMenus.vue')['default']
|
||||
TableProMax: typeof import('./src/components/table/TableProMax.vue')['default']
|
||||
TelephoneLogin: typeof import('./src/components/login/TelephoneLogin.vue')['default']
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
declare const __APP_ENV: ImportMetaEnv;
|
||||
|
||||
declare global {
|
||||
/**
|
||||
* 全局返回
|
||||
*/
|
||||
interface JsonResult<T> {
|
||||
code: number;
|
||||
message: string;
|
||||
data?: T;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export interface SecurityUnitPagerQueryParams {
|
||||
/** 名称 **/
|
||||
name?: string;
|
||||
/** 社会编码 **/
|
||||
socialCode?: string;
|
||||
/** 行政区划编码 **/
|
||||
administrativeDivisionCodes?: string[];
|
||||
/** 是否启用 **/
|
||||
isEnable?: number;
|
||||
/** 审核状态 **/
|
||||
checkStatus?: number;
|
||||
}
|
||||
interface BaseEnum<T> {
|
||||
value: T;
|
||||
label: string
|
||||
}
|
||||
class TreeNodeVo<T, E = Record<string, any>> {
|
||||
value: T;
|
||||
parentValue: T;
|
||||
label: string;
|
||||
orderIndex?: number;
|
||||
children?: TreeNodeVo<T>[]
|
||||
extData?: E;
|
||||
}
|
||||
declare interface Grid {
|
||||
//栅格占据的列数
|
||||
span?: number;
|
||||
//栅格左侧的间隔格数
|
||||
offset?: number;
|
||||
//栅格向右移动格数
|
||||
push?: number;
|
||||
//栅格向左移动格数
|
||||
pull?: number;
|
||||
//<768px 响应式栅格数或者栅格属性对象
|
||||
xs?: number;
|
||||
//≥768px 响应式栅格数或者栅格属性对象
|
||||
sm?: number;
|
||||
//≥992px 响应式栅格数或者栅格属性对象
|
||||
md?: number;
|
||||
//≥1200px 响应式栅格数或者栅格属性对象
|
||||
lg?: number;
|
||||
//≥1920px 响应式栅格数或者栅格属性对象
|
||||
xl?: number;
|
||||
}
|
||||
interface dataStatus {
|
||||
account: string;
|
||||
password: string;
|
||||
remark: string;
|
||||
checkStatus: {
|
||||
extData: {
|
||||
color: string;
|
||||
};
|
||||
label: string;
|
||||
value: number;
|
||||
};
|
||||
}
|
||||
class SelectNodeVo<T, E = Record<string, any>> {
|
||||
value: T;
|
||||
label: string;
|
||||
options?: SelectNodeVo<T>[]
|
||||
orderIndex?: number;
|
||||
disabled?: boolean;
|
||||
extData?: E
|
||||
}
|
||||
|
||||
interface ExtData {
|
||||
color?: string;
|
||||
}
|
||||
|
||||
interface Option {
|
||||
label: string;
|
||||
value: string | number;
|
||||
extData?: ExtData | null;
|
||||
}
|
||||
|
||||
interface OptionsResponse {
|
||||
IsEnable: Option[];
|
||||
IsOrNot: Option[];
|
||||
Sex: Option[];
|
||||
CheckStatus: Option[];
|
||||
ServiceProjectType: Option[];
|
||||
DeleteFlag: Option[];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,15 +1,18 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script type="module" src="/src/assets/iconfont/iconfont.js"></script>
|
||||
|
||||
<title>Vite + Vue + TS</title>
|
||||
<title>公安后台</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -6,30 +6,36 @@
|
|||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"build": "vite build --mode production",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amap/amap-jsapi-loader": "^1.0.1",
|
||||
"@vueuse/core": "^11.2.0",
|
||||
"ant-design-vue": "^4.2.3",
|
||||
"axios": "^1.7.5",
|
||||
"dayjs": "^1.11.13",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"pinia": "^2.2.2",
|
||||
"pinia-plugin-persistedstate": "^3.2.0",
|
||||
"vue-component-type-helpers": "^2.1.2",
|
||||
"sass": "^1.77.8",
|
||||
"vue": "^3.4.37",
|
||||
"vue-component-type-helpers": "^2.1.2",
|
||||
"vue-router": "4",
|
||||
"vue-uuid": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@amap/amap-jsapi-types": "^0.0.15",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^22.5.1",
|
||||
"@types/react": "^18.3.12",
|
||||
"@vitejs/plugin-vue": "^5.1.2",
|
||||
"@vitejs/plugin-vue-jsx": "^4.0.1",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"postcss": "^8.4.41",
|
||||
"tailwindcss": "^3.4.10",
|
||||
"terser": "^5.36.0",
|
||||
"typescript": "^5.5.3",
|
||||
"unplugin-vue-components": "^0.27.4",
|
||||
"vite": "^5.4.1",
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/* 扩展ant design pro按钮组件颜色 */
|
||||
$--my-antd-important: !important;
|
||||
|
||||
.btn-danger {
|
||||
color: #ffffff;
|
||||
background-color: #F5222D;
|
||||
border-color: #F5222D;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #ff4d4f $--my-antd-important;
|
||||
border-color: #ff4d4f $--my-antd-important;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #cf1322 $--my-antd-important;
|
||||
border-color: #cf1322 $--my-antd-important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-volcano {
|
||||
color: #ffffff;
|
||||
background-color: #FA541C;
|
||||
border-color: #FA541C;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #ff7a45 $--my-antd-important;
|
||||
border-color: #ff7a45 $--my-antd-important;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #d4380d $--my-antd-important;
|
||||
border-color: #d4380d $--my-antd-important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-warn {
|
||||
color: #ffffff;
|
||||
background-color: #FAAD14;
|
||||
border-color: #FAAD14;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #ffc53d $--my-antd-important;
|
||||
border-color: #ffc53d $--my-antd-important;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #d48806 $--my-antd-important;
|
||||
border-color: #d48806 $--my-antd-important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
color: #ffffff;
|
||||
background-color: #52C41A;
|
||||
border-color: #52C41A;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #73d13d $--my-antd-important;
|
||||
border-color: #73d13d $--my-antd-important;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #389e0d $--my-antd-important;
|
||||
border-color: #389e0d $--my-antd-important;
|
||||
}
|
||||
}
|
||||
|
||||
.button-color-cyan {
|
||||
color: #ffffff;
|
||||
background-color: #13C2C2;
|
||||
border-color: #13C2C2;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #36cfc9 $--my-antd-important;
|
||||
border-color: #36cfc9 $--my-antd-important;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #08979c $--my-antd-important;
|
||||
border-color: #08979c $--my-antd-important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-daybreak {
|
||||
color: #ffffff;
|
||||
background-color: #1890FF;
|
||||
border-color: #1890FF;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #096dd9 $--my-antd-important;
|
||||
border-color: #096dd9 $--my-antd-important;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #40a9ff $--my-antd-important;
|
||||
border-color: #40a9ff $--my-antd-important;
|
||||
}
|
||||
}
|
||||
|
||||
.button-color-geekblue {
|
||||
color: #ffffff;
|
||||
background-color: #2F54EB;
|
||||
border-color: #2F54EB;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #1d39c4 $--my-antd-important;
|
||||
border-color: #1d39c4 $--my-antd-important;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #597ef7 $--my-antd-important;
|
||||
border-color: #597ef7 $--my-antd-important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-purple {
|
||||
color: #ffffff;
|
||||
background-color: #722ED1;
|
||||
border-color: #722ED1;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #9254de $--my-antd-important;
|
||||
border-color: #9254de $--my-antd-important;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
color: #ffffff $--my-antd-important;
|
||||
background-color: #531dab $--my-antd-important;
|
||||
border-color: #531dab $--my-antd-important;
|
||||
}
|
||||
}
|
||||
|
||||
.table-row-warn td {
|
||||
background-color: #fefca6;
|
||||
}
|
||||
|
||||
.table-row-danger td {
|
||||
background-color: #f79988;
|
||||
}
|
||||
|
||||
.table-row-success td {
|
||||
background-color: #b6fcbe;
|
||||
}
|
||||
|
||||
.ant-table-summary td {
|
||||
background: #edeff6;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<div :id="mapId" class="mapContainer">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, shallowRef } from 'vue'
|
||||
import { initMap } from '@/utils/aMapUtil'
|
||||
import { MapContainerProps, MapPlugins } from '@/types/components/map/index.ts'
|
||||
|
||||
const props = withDefaults(defineProps<MapContainerProps>(), {
|
||||
plugins: (): MapPlugins[] => {
|
||||
return []
|
||||
},
|
||||
mapOptions: (): AMap.MapOptions => {
|
||||
return {
|
||||
// 是否为3D地图模式
|
||||
viewMode: '3D',
|
||||
// 初始化地图级别
|
||||
zoom: 11,
|
||||
mapStyle: 'amap://styles/darkblue',
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const mapId = 'mapContainer'
|
||||
const map = shallowRef<AMap.Map>(null)
|
||||
|
||||
defineExpose({
|
||||
mapInstance: map,
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
initMap(props.plugins).then((AMap) => {
|
||||
map.value = new AMap.Map(mapId, props.mapOptions)
|
||||
props.initCallback && props.initCallback(map.value)
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
map.value?.destroy()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
#mapContainer {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -67,6 +67,7 @@
|
|||
:allowClear="item.componentsProps?.allowClear ?? true"
|
||||
:options="item.options"
|
||||
/>
|
||||
<administrative-division-tree-comp v-else-if="item.type === 'administrativeDivisionTree'" style="width: 100%" v-model:value="modelValue[field]" v-bind="item.componentsProps" />
|
||||
<a-range-picker
|
||||
v-else-if="item.type === 'rangePicker'"
|
||||
style="width: 100%"
|
||||
|
@ -111,10 +112,14 @@
|
|||
|
||||
<script setup lang="ts" generic="T extends Record<string,any>">
|
||||
import { FormInstance } from 'ant-design-vue'
|
||||
import { ref } from 'vue'
|
||||
import { defineAsyncComponent, ref } from 'vue'
|
||||
import { FormExpose } from 'ant-design-vue/es/form/Form'
|
||||
import { QuestionCircleOutlined } from '@ant-design/icons-vue'
|
||||
import { FormProMaxItemOptions, FormProMaxItemProps, FormProMaxProps } from '@/types/components/form/index.ts'
|
||||
import { ComponentProps } from 'vue-component-type-helpers'
|
||||
import AdministrativeDivisionTree from '@/components/tree/AdministrativeDivisionTree.vue'
|
||||
|
||||
const AdministrativeDivisionTreeComp: ComponentProps<typeof AdministrativeDivisionTree> = defineAsyncComponent(() => import('@/components/tree/AdministrativeDivisionTree.vue'))
|
||||
|
||||
const modelValue = defineModel<T>('value', {
|
||||
default: {},
|
||||
|
@ -147,7 +152,7 @@ const props = withDefaults(defineProps<FormProMaxProps<T>>(), {
|
|||
scrollToFirstError: undefined,
|
||||
validateOnRuleChange: undefined,
|
||||
})
|
||||
console.log(props)
|
||||
|
||||
const formProMaxRef = ref<FormInstance>(null!)
|
||||
|
||||
const getResponsive = (item: FormProMaxItemProps): Grid => {
|
||||
|
|
|
@ -144,7 +144,7 @@ const props = withDefaults(defineProps<TableProMaxProps<T, P>>(), {
|
|||
showExpandColumn: undefined,
|
||||
sticky: undefined,
|
||||
})
|
||||
console.log(props)
|
||||
// console.log(props)
|
||||
|
||||
const slots = defineSlots<TableProMaxSlots<T>>()
|
||||
|
||||
|
@ -189,7 +189,7 @@ const {
|
|||
props.dataCallback,
|
||||
props.requestError
|
||||
)
|
||||
console.log('pageParams', pageParams)
|
||||
// console.log('pageParams', pageParams)
|
||||
|
||||
onMounted(() => props.requestAuto && requestGetTableData(true))
|
||||
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
<template>
|
||||
<a-cascader
|
||||
v-model:value="modelValue"
|
||||
:placeholder="placeholder"
|
||||
:change-on-select="changeOnSelect"
|
||||
:options="administrativeDivisionTree"
|
||||
:load-data="loadData"
|
||||
:allow-clear="allowClear"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import api from "@/axios";
|
||||
import {onMounted, ref} from "vue";
|
||||
import {CascaderProps} from "ant-design-vue";
|
||||
import {isEmpty} from "lodash-es";
|
||||
|
||||
withDefaults(defineProps<{
|
||||
placeholder?: string,
|
||||
changeOnSelect?: boolean
|
||||
allowClear?: boolean
|
||||
}>(), {
|
||||
placeholder: '请选择行政区划',
|
||||
changeOnSelect: true,
|
||||
allowClear: true
|
||||
})
|
||||
|
||||
|
||||
const modelValue = defineModel('value', {
|
||||
default: []
|
||||
})
|
||||
|
||||
const administrativeDivisionTree = ref<TreeNodeVo<string>[]>([])
|
||||
|
||||
const loadData: CascaderProps['loadData'] = selectedOptions => {
|
||||
const targetOption = selectedOptions[selectedOptions.length - 1];
|
||||
targetOption.loading = true;
|
||||
administrativeDivisionByParentCode(targetOption.value as string).then(data => {
|
||||
targetOption.loading = false
|
||||
targetOption.children = data
|
||||
administrativeDivisionTree.value = [...administrativeDivisionTree.value]
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据父级编码查询行政区划
|
||||
* @param code
|
||||
*/
|
||||
const administrativeDivisionByParentCode = async (code: string = '0'): Promise<TreeNodeVo<string>[]> => {
|
||||
const resp = await api.get<TreeNodeVo<string>[]>('/common/administrativeDivisionByParentCode', {
|
||||
parentCode: code
|
||||
})
|
||||
//解决点击无加载提示
|
||||
return resp.data.map(item => {
|
||||
delete item.children
|
||||
return item
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
administrativeDivisionTree.value = await administrativeDivisionByParentCode()
|
||||
if (!isEmpty(modelValue.value)) {
|
||||
const ps = modelValue.value.map(code => administrativeDivisionByParentCode(code))
|
||||
Promise.all(ps).then(data => {
|
||||
let i = 0;
|
||||
const deepChildren = (treeData: TreeNodeVo<string>[]) => {
|
||||
treeData.forEach(item => {
|
||||
if (item.value === modelValue.value[i]) {
|
||||
item.children = data[i]
|
||||
i++;
|
||||
deepChildren(item.children)
|
||||
}
|
||||
})
|
||||
}
|
||||
deepChildren(administrativeDivisionTree.value)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
|
@ -1,8 +1,9 @@
|
|||
<template>
|
||||
<div class="simpleUploadDiv">
|
||||
<a-progress v-if="uploading" type="circle" :percent="percent" />
|
||||
<a-image height="80%" v-else :src="minioBaseUrl + modelValue" alt="avatar" />
|
||||
<a-button class="btn-success" @click="selectFile">{{ btnLabel }}</a-button>
|
||||
<!-- height="80%" width="80%" -->
|
||||
<a-image v-else :src="minioBaseUrl + modelValue" alt="avatar" />
|
||||
<a-button style="margin-top: 4px" class="btn-success" @click="selectFile">{{ btnLabel }}</a-button>
|
||||
<input id="myFileInput" type="file" style="display: none" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
// global.d.ts不能出现 export 关键字否则这个文件会失效
|
||||
declare const __APP_ENV: ImportMetaEnv;
|
||||
class TreeNodeVo<T, E = Record<string, any>> {
|
||||
value: T;
|
||||
parentValue: T;
|
||||
label: string;
|
||||
orderIndex?: number;
|
||||
children?: TreeNodeVo<T>[]
|
||||
extData?: E;
|
||||
}
|
||||
|
||||
/**
|
||||
* 全局返回
|
||||
*/
|
||||
interface JsonResult<T> {
|
||||
code: number;
|
||||
message: string;
|
||||
data?: T;
|
||||
}
|
||||
|
||||
|
||||
interface SecurityUnitPagerQueryParams {
|
||||
/** 名称 **/
|
||||
name?: string;
|
||||
/** 社会编码 **/
|
||||
socialCode?: string;
|
||||
/** 行政区划编码 **/
|
||||
administrativeDivisionCodes?: string[];
|
||||
/** 是否启用 **/
|
||||
isEnable?: number;
|
||||
/** 审核状态 **/
|
||||
checkStatus?: number;
|
||||
}
|
||||
interface BaseEnum<T> {
|
||||
value: T;
|
||||
label: string
|
||||
}
|
||||
|
||||
interface Grid {
|
||||
//栅格占据的列数
|
||||
span?: number;
|
||||
//栅格左侧的间隔格数
|
||||
offset?: number;
|
||||
//栅格向右移动格数
|
||||
push?: number;
|
||||
//栅格向左移动格数
|
||||
pull?: number;
|
||||
//<768px 响应式栅格数或者栅格属性对象
|
||||
xs?: number;
|
||||
//≥768px 响应式栅格数或者栅格属性对象
|
||||
sm?: number;
|
||||
//≥992px 响应式栅格数或者栅格属性对象
|
||||
md?: number;
|
||||
//≥1200px 响应式栅格数或者栅格属性对象
|
||||
lg?: number;
|
||||
//≥1920px 响应式栅格数或者栅格属性对象
|
||||
xl?: number;
|
||||
}
|
||||
interface dataStatus {
|
||||
account: string;
|
||||
password: string;
|
||||
remark: string;
|
||||
checkStatus: {
|
||||
extData: {
|
||||
color: string;
|
||||
};
|
||||
label: string;
|
||||
value: number;
|
||||
};
|
||||
}
|
||||
class SelectNodeVo<T, E = Record<string, any>> {
|
||||
value: T;
|
||||
label: string;
|
||||
options?: SelectNodeVo<T>[]
|
||||
orderIndex?: number;
|
||||
disabled?: boolean;
|
||||
extData?: E
|
||||
}
|
||||
|
||||
interface ExtData {
|
||||
color?: string;
|
||||
}
|
||||
|
||||
interface Option {
|
||||
label: string;
|
||||
value: string | number;
|
||||
extData?: ExtData | null;
|
||||
}
|
||||
|
||||
interface OptionsResponse {
|
||||
IsEnable: Option[];
|
||||
IsOrNot: Option[];
|
||||
Sex: Option[];
|
||||
CheckStatus: Option[];
|
||||
ServiceProjectType: Option[];
|
||||
DeleteFlag: Option[];
|
||||
}
|
||||
|
||||
interface TypeEnum<T> {
|
||||
value: string;
|
||||
label: string
|
||||
}
|
||||
|
||||
|
|
@ -1,19 +1,16 @@
|
|||
import {createApp} from 'vue'
|
||||
import { createApp } from 'vue'
|
||||
import App from '@/App.vue'
|
||||
import '@/reset.css'
|
||||
import './index.css'
|
||||
// 公共样式
|
||||
import '@/assets/scss/common.scss'
|
||||
// iconfont css
|
||||
import '@/assets/scss/myAntD.scss'
|
||||
import "@/assets/iconfont/iconfont.css";
|
||||
// vue Router
|
||||
import router from "@/router";
|
||||
// pinia stores
|
||||
import pinia from "@/stores";
|
||||
|
||||
const vueApp = createApp(App);
|
||||
import {initEnums} from "@/config/dict.ts";
|
||||
|
||||
import { initEnums } from "@/config/dict.ts";
|
||||
//高德类型声明文件
|
||||
import "@amap/amap-jsapi-types";
|
||||
initEnums()
|
||||
vueApp
|
||||
.use(router)
|
||||
|
|
|
@ -10,7 +10,7 @@ import { ROUTER_WHITE_LIST } from "@/config";
|
|||
* createWebHashHistory: 路径带#号 这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理,影响SEO
|
||||
*/
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
history: createWebHistory('/policeManagement/'),
|
||||
routes: [...staticRouter],
|
||||
strict: false,
|
||||
scrollBehavior: () => ({ left: 0, top: 0 })
|
||||
|
|
|
@ -81,7 +81,21 @@ export const staticRouter: RouteRecordRaw[] =
|
|||
keepalive: true
|
||||
},
|
||||
component: () => import('@/views/query/publicUnit.vue')
|
||||
// component: () => import('@/views/query/index.tsx')
|
||||
// component: () => import('@/views/query/EnterprisesUnit')
|
||||
|
||||
|
||||
},
|
||||
{
|
||||
path: 'assessment-record', // 这里使用相对路径而不是 '/register'
|
||||
name: 'assessment-record',
|
||||
meta: {
|
||||
|
||||
title: '考核记录',
|
||||
keepalive: true
|
||||
},
|
||||
component: () => import('@/views/query/assessmentRecord.vue')
|
||||
}
|
||||
// {
|
||||
// path: 'weapp-user', // 这里使用相对路径而不是 '/register'
|
||||
// name: 'weapp-user',
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
} from "ant-design-vue";
|
||||
import { Ref, UnwrapRef, VNode } from "vue";
|
||||
import { ComponentProps } from "vue-component-type-helpers";
|
||||
import AdministrativeDivisionTree from "@/components/tree/AdministrativeDivisionTree.vue";
|
||||
|
||||
type FormProMaxItemType =
|
||||
| 'custom'
|
||||
|
@ -32,7 +33,8 @@ type FormProMaxItemType =
|
|||
| 'datePicker'
|
||||
| 'rangePicker'
|
||||
| 'timeRangePicker'
|
||||
| 'timePicker';
|
||||
| 'timePicker'
|
||||
| 'administrativeDivisionTree'
|
||||
|
||||
interface FormProMaxItemCommonProps extends ComponentProps<typeof FormItem> {
|
||||
label?: string,
|
||||
|
@ -64,6 +66,7 @@ export type FormProMaxItemOptions<T> = {
|
|||
| FormProMaxItemProps<'rangePicker', ComponentProps<typeof RangePicker>>
|
||||
| FormProMaxItemProps<'timeRangePicker', ComponentProps<typeof TimeRangePicker>>
|
||||
| FormProMaxItemProps<'timePicker', ComponentProps<typeof TimePicker>>
|
||||
| FormProMaxItemProps<'administrativeDivisionTree', ComponentProps<typeof AdministrativeDivisionTree>>
|
||||
}
|
||||
|
||||
export interface FormProMaxProps<T = {}> extends FormProps {
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* 高德支持的插件列表
|
||||
* @link https://lbs.amap.com/api/javascript-api-v2/guide/abc/plugins-list
|
||||
*/
|
||||
export type MapPlugins =
|
||||
'AMap.ElasticMarker'
|
||||
| 'AMap.ToolBar'
|
||||
| 'AMap.Scale'
|
||||
| 'AMap.HawkEye'
|
||||
| 'AMap.ControlBar'
|
||||
| 'AMap.MapType'
|
||||
| 'AMap.Geolocation'
|
||||
| 'AMap.AutoComplete'
|
||||
| 'AMap.PlaceSearch'
|
||||
| 'AMap.DistrictSearch'
|
||||
| 'AMap.LineSearch'
|
||||
| 'AMap.StationSearch'
|
||||
| 'AMap.Driving'
|
||||
| 'AMap.TruckDriving'
|
||||
| 'AMap.Transfer'
|
||||
| 'AMap.Walking'
|
||||
| 'AMap.Riding'
|
||||
| 'AMap.DragRoute'
|
||||
| 'AMap.Geocoder'
|
||||
| 'AMap.CitySearch'
|
||||
| 'AMap.IndoorMap'
|
||||
| 'AMap.MouseTool'
|
||||
| 'AMap.CircleEditor'
|
||||
| 'AMap.PolygonEditor'
|
||||
| 'AMap.PolylineEditor'
|
||||
| 'AMap.RectangleEditor'
|
||||
| 'AMap.EllipseEditor'
|
||||
| 'AMap.BezierCurveEditor'
|
||||
| 'AMap.MarkerCluster'
|
||||
| 'AMap.RangingTool'
|
||||
| 'AMap.CloudDataSearch'
|
||||
| 'AMap.Weather'
|
||||
| 'AMap.HeatMap'
|
||||
|
||||
export interface MapContainerProps {
|
||||
plugins?: MapPlugins[],
|
||||
initCallback?: (map: AMap.Map) => void,
|
||||
mapOptions?: AMap.MapOptions
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import {BaseTableRowRecord} from "@/types/components/table";
|
||||
import {BaseEnum} from "../../../global";
|
||||
|
||||
|
||||
|
||||
export interface AssessmentRecordPagerVo extends BaseTableRowRecord {
|
||||
/** 企事业单位名称 **/
|
||||
enterprisesUnitName: string;
|
||||
/** 考核项目名称 **/
|
||||
ckProjectName: string;
|
||||
/** 考核项目总分 **/
|
||||
totalScore: number;
|
||||
/** 考核项目类型 **/
|
||||
type: BaseEnum<string>;
|
||||
/** 考核项目备注 **/
|
||||
ckProjectRemark: string;
|
||||
/** 公安单位名称 **/
|
||||
policeUnitName: string;
|
||||
/** 考核人员签字 **/
|
||||
assessmentUserSignature: string;
|
||||
/** 被考核单位人员签字 **/
|
||||
byAssessmentEnterprisesUnitUserSignature: string;
|
||||
/** 考核备注 **/
|
||||
remark: string;
|
||||
/** 总扣分 **/
|
||||
deductionPointsTotal: number;
|
||||
}
|
||||
|
||||
|
||||
export interface AssessmentRecordPagerQueryParams {
|
||||
type: string
|
||||
}
|
||||
|
||||
export interface DeductedDetailRes {
|
||||
/*考核分组id */
|
||||
ckGroupId: number;
|
||||
groupRowSpan: number;
|
||||
/*考核分组名字 */
|
||||
groupName: string;
|
||||
/*考核分组总分 */
|
||||
groupTotalScore: number;
|
||||
/*考核分组备注 */
|
||||
groupRemark: string;
|
||||
/*考核项id */
|
||||
ckItemId: number;
|
||||
itemRowSpan: number;
|
||||
/*考核项名字 */
|
||||
itemName: string;
|
||||
/*组件类型,可用值:RADIO,MULTIPLE */
|
||||
itemType: BaseEnum<string>;
|
||||
/*考核项备注 */
|
||||
itemRemark: string;
|
||||
/*考核标准id */
|
||||
ckStandardId: number;
|
||||
/*考核标准 */
|
||||
standardName: string;
|
||||
/*扣分数 */
|
||||
deductionPoints: Record<string, unknown>;
|
||||
/*是否选中 */
|
||||
isSelected: boolean;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { BaseTableRowRecord } from "@/types/components/table";
|
||||
|
||||
export interface serviceProjectSaveOrUpdateParams_ extends BaseTableRowRecord {
|
||||
snowFlakeId: string
|
||||
enterprisesUnitId: string,
|
||||
enterprisesUnitName: string,
|
||||
projectManagerMiniProgramUserId: string,
|
||||
projectManagerMiniProgramUserName: string,
|
||||
name: string,
|
||||
type: TypeEnum<string>,
|
||||
twoType: BaseEnum<any>,
|
||||
outsourceName: string,
|
||||
isFiling: BaseEnum<number>,
|
||||
idNumber: string,
|
||||
serviceArea: number,
|
||||
buildingTotal: number,
|
||||
houseTotal: number,
|
||||
staffTotal: number,
|
||||
securityUserTotal: number,
|
||||
remark: string,
|
||||
createUserName: string,
|
||||
createTime: string,
|
||||
enterprisesUnitAdministrativeDivisionCodes: Record<string, any>
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
import { BaseTableRowRecord } from "@/types/components/table";
|
||||
|
||||
export interface PoliceUnitPagerQueryParams {
|
||||
/** 名称 **/
|
||||
name?: string;
|
||||
/** 代码 **/
|
||||
code?: string;
|
||||
/** 行政区划 **/
|
||||
administrativeDivisionCodes?: string[];
|
||||
/** 是否启用 **/
|
||||
isEnable?: BaseEnum<number>;
|
||||
/** 审核状态 **/
|
||||
checkStatus?: BaseEnum<number>;
|
||||
}
|
||||
|
||||
export interface PoliceUnitPagerVo extends BaseTableRowRecord {
|
||||
|
||||
sex: { label: string }
|
||||
/** 名称 **/
|
||||
name?: string;
|
||||
/** 代码 **/
|
||||
code?: string;
|
||||
/** 省编码 **/
|
||||
province?: string;
|
||||
/** 省名字 **/
|
||||
provinceName?: string;
|
||||
/** 市编码 **/
|
||||
city?: string;
|
||||
/** 市名字 **/
|
||||
cityName?: string;
|
||||
/** 区/县编码 **/
|
||||
districts?: string;
|
||||
/** 区/县名字 **/
|
||||
districtsName?: string;
|
||||
/** 街道编码 **/
|
||||
street?: string;
|
||||
/** 街道编码 **/
|
||||
streetName?: string;
|
||||
/** 详细地址 **/
|
||||
address?: string;
|
||||
/** 联系人 **/
|
||||
contactPersonInfo?: {
|
||||
name: string;
|
||||
telephone: string;
|
||||
};
|
||||
/** 是否启用 **/
|
||||
isEnable?: BaseEnum<number>;
|
||||
/** 审核状态 **/
|
||||
checkStatus?: BaseEnum<number>;
|
||||
}
|
||||
|
||||
export interface EnterprisesUnitPagerQueryParams {
|
||||
/** 公安单位id **/
|
||||
policeUnitId: string;
|
||||
}
|
||||
|
||||
export interface EnterprisesUnitPagerVo extends BaseTableRowRecord {
|
||||
sex: { label: string }
|
||||
/** 名字 **/
|
||||
name?: string;
|
||||
type: BaseEnum<string>
|
||||
/** 公安单位id **/
|
||||
policeUnitId: string;
|
||||
/** 省编码 **/
|
||||
province?: string;
|
||||
/** 省名称 **/
|
||||
provinceName?: string;
|
||||
/** 市编码 **/
|
||||
city?: string;
|
||||
/** 市名称 **/
|
||||
cityName?: string;
|
||||
/** 区编码 **/
|
||||
districts?: string;
|
||||
/** 区名称 **/
|
||||
districtsName?: string;
|
||||
/** 街编码 **/
|
||||
street?: string;
|
||||
/** 街名称 **/
|
||||
streetName?: string;
|
||||
/** 地址 **/
|
||||
address?: string;
|
||||
point: [number, number]
|
||||
/** 联系方式 **/
|
||||
contactPersonInfo?: {
|
||||
name: string;
|
||||
telephone: string;
|
||||
};
|
||||
/** 备注 **/
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
export interface EnterprisesUnitSaveOrUpdateParams {
|
||||
/** id **/
|
||||
snowFlakeId?: string;
|
||||
|
||||
/** 公安单位id **/
|
||||
policeUnitId: string;
|
||||
/** 名称 **/
|
||||
name: string;
|
||||
/** 类型 **/
|
||||
type: string;
|
||||
/** 行政区划编码 **/
|
||||
administrativeDivisionCodes: string[];
|
||||
/** 详细地址 **/
|
||||
address?: string;
|
||||
point?: [number, number]
|
||||
/** 联系人 **/
|
||||
contactPersonInfo?: {
|
||||
name: string;
|
||||
telephone: string;
|
||||
};
|
||||
/** 备注 **/
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface securityUnitIdListParams {
|
||||
snowFlakeId?: string;
|
||||
serviceProjectId?: string;
|
||||
securityUnitId?: string;
|
||||
name?: string;
|
||||
remark?: string;
|
||||
photo?: string;
|
||||
telephone?: string;
|
||||
workPost?: string;
|
||||
sex?: string;
|
||||
nativePlace?: string;
|
||||
idCard?: string;
|
||||
dateOfBirth?: string;
|
||||
securityNumber?: string;
|
||||
noSecurityNumberDesc?: string;
|
||||
homeAddress?: string;
|
||||
}
|
||||
export interface securityUnitIdListPagerVo {
|
||||
snowFlakeId?: string;
|
||||
serviceProjectId?: string;
|
||||
securityUnitId?: string;
|
||||
name?: string;
|
||||
remark?: string;
|
||||
photo?: string;
|
||||
telephone?: {
|
||||
desensitizedValue?: string;
|
||||
originalValue?: string;
|
||||
};
|
||||
workPost?: string;
|
||||
sex?: {
|
||||
label?: string;
|
||||
value: number | string
|
||||
};
|
||||
nativePlace?: string;
|
||||
idCard?: {
|
||||
desensitizedValue?: string;
|
||||
originalValue?: string;
|
||||
};
|
||||
dateOfBirth?: string;
|
||||
securityNumber?: string;
|
||||
noSecurityNumberDesc?: string;
|
||||
homeAddress?: string;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import AMapLoader from "@amap/amap-jsapi-loader";
|
||||
import { MapPlugins } from "@/types/components/map/index";
|
||||
|
||||
export const initMap = (plugins?: MapPlugins[]): Promise<typeof AMap> => new Promise((resolve, reject) => {
|
||||
//@ts-ignore
|
||||
window._AMapSecurityConfig = {
|
||||
securityJsCode: __APP_ENV.VITE_APP_SECURITY_JS_CODE
|
||||
}
|
||||
AMapLoader.load({
|
||||
key: __APP_ENV.VITE_APP_GAODE_KEY,
|
||||
version: __APP_ENV.VITE_APP_GAODE_VERSION,
|
||||
plugins
|
||||
}).then((aMap: typeof AMap) => {
|
||||
resolve(aMap)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
|
@ -1,4 +1,4 @@
|
|||
<template><div>111111</div></template>
|
||||
<template><div>公安后台</div></template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
import api from '@/axios'
|
||||
import { AssessmentRecordPagerVo, DeductedDetailRes } from '@/types/views/assessmentRecord.ts'
|
||||
import { ColumnsType } from 'ant-design-vue/es/table'
|
||||
import { Modal, Table } from 'ant-design-vue'
|
||||
|
||||
export const deductedDetail = async (assessmentRecord: AssessmentRecordPagerVo) => {
|
||||
const { data } = await api.get<DeductedDetailRes[]>('/m1/ar/deductedDetail', { assessmentRecordId: assessmentRecord.snowFlakeId })
|
||||
const groupRowSpan: Record<string, { firstIndex: number; count: number }> = {}
|
||||
const itemRowSpan: Record<string, { firstIndex: number; count: number }> = {}
|
||||
|
||||
data.forEach((item, index) => {
|
||||
//如果第一次没有值
|
||||
if (item.ckGroupId) {
|
||||
if (!groupRowSpan[item.ckGroupId]) {
|
||||
groupRowSpan[item.ckGroupId] = { count: 1, firstIndex: index }
|
||||
} else {
|
||||
groupRowSpan[item.ckGroupId].count++
|
||||
data[index].groupRowSpan = 0
|
||||
}
|
||||
}
|
||||
|
||||
if (item.ckItemId) {
|
||||
if (!itemRowSpan[item.ckItemId]) {
|
||||
itemRowSpan[item.ckItemId] = { count: 1, firstIndex: index }
|
||||
} else {
|
||||
itemRowSpan[item.ckItemId].count++
|
||||
data[index].itemRowSpan = 0
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Object.values(groupRowSpan).forEach(({ count, firstIndex }) => {
|
||||
data[firstIndex].groupRowSpan = count
|
||||
})
|
||||
|
||||
Object.values(itemRowSpan).forEach(({ count, firstIndex }) => {
|
||||
data[firstIndex].itemRowSpan = count
|
||||
})
|
||||
|
||||
const ckProjectDetailTableColumns: ColumnsType<DeductedDetailRes> = [
|
||||
{
|
||||
dataIndex: 'groupName',
|
||||
title: '考核分组',
|
||||
customCell: (_record) => {
|
||||
return {
|
||||
rowspan: _record.groupRowSpan,
|
||||
}
|
||||
},
|
||||
customRender: ({ record: _record }) => {
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
{_record.groupName}({_record.groupTotalScore})
|
||||
</p>
|
||||
<p>{_record.groupRemark}</p>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'itemName',
|
||||
title: '考核项',
|
||||
customCell: (_record) => {
|
||||
return {
|
||||
rowspan: _record.itemRowSpan,
|
||||
}
|
||||
},
|
||||
customRender: ({ record: _record }) => {
|
||||
if (!_record.ckItemId) {
|
||||
return '/'
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
{_record.itemName}({_record.itemType?.label})
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'standardName',
|
||||
title: '标准',
|
||||
customRender: ({ record: _record }) => {
|
||||
if (!_record.ckStandardId) {
|
||||
return '/'
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<p style={{ color: _record.isSelected ? 'red' : '' }}>
|
||||
{_record.standardName}扣{_record.deductionPoints}分
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
Modal.info({
|
||||
title: `【${assessmentRecord.enterprisesUnitName}/${assessmentRecord.ckProjectName}】扣分详情`,
|
||||
icon: ' ',
|
||||
width: '80%',
|
||||
centered: true,
|
||||
content: () => (
|
||||
<div style={{ height: '80vh', overflow: 'auto' }}>
|
||||
<Table size='small' bordered pagination={false} class='margin-top-xs' columns={ckProjectDetailTableColumns} data-source={data}></Table>
|
||||
</div>
|
||||
),
|
||||
})
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
<template>
|
||||
<div>
|
||||
<TableProMax ref="tableRef" :request-api="reqApi" :columns="columns"> </TableProMax>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import TableProMax from '@/components/table/TableProMax.vue'
|
||||
import api from '@/axios'
|
||||
import { TableProMaxProps } from '@/types/components/table'
|
||||
import { AssessmentRecordPagerQueryParams, AssessmentRecordPagerVo } from '@/types/views/assessmentRecord.ts'
|
||||
import { ComponentExposed } from 'vue-component-type-helpers'
|
||||
import { ref } from 'vue'
|
||||
import { Modal } from 'ant-design-vue'
|
||||
import { deductedDetail } from '@/views/query/assessmentIndex.tsx'
|
||||
const tableRef = ref<ComponentExposed<typeof TableProMax>>(null!)
|
||||
type TableProps = TableProMaxProps<AssessmentRecordPagerVo, AssessmentRecordPagerQueryParams>
|
||||
const reqApi: TableProps['requestApi'] = (params) => api.post('/m1/ar/pager', params) //分页
|
||||
const columns: TableProps['columns'] = [
|
||||
{
|
||||
dataIndex: 'enterprisesUnitName',
|
||||
title: '单位名称',
|
||||
},
|
||||
{
|
||||
dataIndex: 'type',
|
||||
title: '类型',
|
||||
customRender: ({ text }) => text?.label,
|
||||
},
|
||||
{
|
||||
dataIndex: 'ckProjectName',
|
||||
title: '考核项目',
|
||||
},
|
||||
{
|
||||
dataIndex: 'totalScore',
|
||||
title: '总分',
|
||||
},
|
||||
{
|
||||
dataIndex: 'deductionPointsTotal',
|
||||
title: '扣分',
|
||||
customRender: ({ record }) => {
|
||||
if (!record.deductionPointsTotal) {
|
||||
return <a-tag color='green'>0</a-tag>
|
||||
}
|
||||
return (
|
||||
<a-tag class='pointer' color='red' onClick={() => deductedDetail(record)}>
|
||||
{record.deductionPointsTotal}
|
||||
</a-tag>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'result',
|
||||
title: '得分',
|
||||
customRender: ({ record }) => record.totalScore - record.deductionPointsTotal,
|
||||
},
|
||||
{
|
||||
dataIndex: 'policeUnitName',
|
||||
title: '考核单位',
|
||||
},
|
||||
{
|
||||
dataIndex: 'createUserName',
|
||||
title: '考核人',
|
||||
},
|
||||
{
|
||||
dataIndex: 'createTime',
|
||||
title: '考核时间',
|
||||
},
|
||||
{
|
||||
dataIndex: 'remark',
|
||||
title: '考核备注',
|
||||
},
|
||||
{
|
||||
dataIndex: 'signature',
|
||||
title: '签字',
|
||||
customRender: ({ record }) => {
|
||||
return (
|
||||
<a-button
|
||||
onClick={() => {
|
||||
Modal.info({
|
||||
title: `${record.enterprisesUnitName}${record.ckProjectName} 签字结果`,
|
||||
content: () => (
|
||||
<>
|
||||
<div>
|
||||
审核人签字: <a-image src={record.assessmentUserSignature} />
|
||||
</div>
|
||||
<div>
|
||||
被审核单位人员签字: <a-image src={record.byAssessmentEnterprisesUnitUserSignature} />
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
})
|
||||
}}
|
||||
>
|
||||
查看
|
||||
</a-button>
|
||||
)
|
||||
},
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
|
@ -0,0 +1,365 @@
|
|||
import dayjs from 'dayjs'
|
||||
import { TableProMaxProps, TableProMaxSlots } from '@/types/components/table'
|
||||
import { EnterprisesUnitPagerQueryParams, securityUnitIdListPagerVo, securityUnitIdListParams, PoliceUnitPagerVo } from '@/types/views/unitManage/police/policeUnit.ts'
|
||||
import { reactive, ref, h } from 'vue'
|
||||
import { FormExpose } from 'ant-design-vue/es/form/Form'
|
||||
import { ComponentExposed } from 'vue-component-type-helpers'
|
||||
import { FormProMaxItemOptions } from '@/types/components/form'
|
||||
import { dictSelectNodes } from '@/config/dict.ts'
|
||||
import { Button, message, Modal, Space, Tag, Input } from 'ant-design-vue'
|
||||
import api from '@/axios'
|
||||
import TableProMax from '@/components/table/TableProMax.vue'
|
||||
import { deleteDataModal } from '@/components/tsx/ModalPro.tsx'
|
||||
import { PageParams } from '@/types/hooks/useTableProMax.ts'
|
||||
import FormProMax from '@/components/form/FormProMax.vue'
|
||||
import { debounce } from 'lodash-es'
|
||||
import { SearchOutlined } from '@ant-design/icons-vue'
|
||||
import axios from 'axios'
|
||||
import SingleImageFileUpload from '@/components/upload/SingleImageFileUpload.vue'
|
||||
type _TableProps = TableProMaxProps<securityUnitIdListPagerVo, EnterprisesUnitPagerQueryParams>
|
||||
|
||||
const _formParams = reactive<securityUnitIdListParams>({
|
||||
snowFlakeId: '', //
|
||||
serviceProjectId: '', // 服务项目id
|
||||
securityUnitId: '', // 保安单位id
|
||||
name: '', //
|
||||
photo: '',
|
||||
telephone: '',
|
||||
workPost: '',
|
||||
sex: '',
|
||||
nativePlace: '',
|
||||
idCard: '',
|
||||
dateOfBirth: '',
|
||||
securityNumber: '',
|
||||
noSecurityNumberDesc: '',
|
||||
homeAddress: '',
|
||||
remark: '',
|
||||
})
|
||||
const cardBlur = () => {
|
||||
let value = _formParams.idCard
|
||||
if (!value?.length || value.length < 18) {
|
||||
_formParams.dateOfBirth = ''
|
||||
return
|
||||
}
|
||||
const birthDate = value.substring(6, 14)
|
||||
const year = birthDate.substring(0, 4)
|
||||
const month = birthDate.substring(4, 6)
|
||||
const day = birthDate.substring(6, 8)
|
||||
var _data = new Date(parseInt(year), parseInt(month) - 1, parseInt(day))
|
||||
_formParams.dateOfBirth = dayjs(_data).format('YYYY-MM-DD HH:mm:ss')
|
||||
console.log('🚀 ~ cardBlur ~ _data:', _formParams.dateOfBirth)
|
||||
}
|
||||
const searchSecurityUnitId = debounce(async () => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.log('process.env.NODE_ENV === development')
|
||||
const res = await axios.get(`https://www.hnjinglian.cn:5678/common/querySecurityNumberByIdCard?idCard=${_formParams.idCard}`)
|
||||
if (res.data?.data?.hasOwnProperty('bayzh')) {
|
||||
_formParams.securityNumber = res.data.data.bayzh
|
||||
message.success(res.data.message)
|
||||
} else {
|
||||
message.error('未查询到保安证件号')
|
||||
}
|
||||
} else {
|
||||
const res = await api.get<any>('/common/querySecurityNumberByIdCard', { idCard: _formParams.idCard })
|
||||
console.log(res)
|
||||
if (res.data?.hasOwnProperty('bayzh')) {
|
||||
_formParams.securityNumber = res.data.bayzh
|
||||
message.success(res.message)
|
||||
} else {
|
||||
message.error('未查询到保安证件号')
|
||||
}
|
||||
}
|
||||
cardBlur()
|
||||
}, 300)
|
||||
const saveOrUpdateEnterprisesUnit = (callback: Function, params, type: string) => {
|
||||
// console.log('🚀 ~ saveOrUpdateEnterprisesUnit ~ params:', params)
|
||||
if (type === 'add') {
|
||||
_formParams.serviceProjectId = params.snowFlakeId
|
||||
_formParams.securityUnitId = params.securityUnitId
|
||||
} else {
|
||||
_formParams.snowFlakeId = params.snowFlakeId
|
||||
_formParams.serviceProjectId = params.serviceProjectId
|
||||
_formParams.securityUnitId = params.securityUnitId
|
||||
_formParams.name = params.name
|
||||
_formParams.photo = params?.photo
|
||||
_formParams.telephone = params.telephone.originalValue
|
||||
_formParams.workPost = params.workPost
|
||||
_formParams.sex = params.sex.value
|
||||
_formParams.nativePlace = params.nativePlace
|
||||
_formParams.idCard = params.idCard.originalValue
|
||||
_formParams.dateOfBirth = params.dateOfBirth
|
||||
_formParams.securityNumber = params.securityNumber
|
||||
_formParams.noSecurityNumberDesc = params?.noSecurityNumberDesc
|
||||
_formParams.homeAddress = params.homeAddress
|
||||
_formParams.remark = params.remark
|
||||
}
|
||||
|
||||
const _formRef = ref<FormExpose>(null)
|
||||
const uploadFileRef = ref(null)
|
||||
const _formOptions = ref<FormProMaxItemOptions<securityUnitIdListParams>>({
|
||||
photo: {
|
||||
type: 'custom',
|
||||
label: '头像',
|
||||
customRender: () => <SingleImageFileUpload height={200} v-model:value={_formParams.photo} ref={uploadFileRef} />,
|
||||
},
|
||||
|
||||
name: {
|
||||
type: 'input',
|
||||
label: '姓名',
|
||||
required: true,
|
||||
},
|
||||
idCard: {
|
||||
type: 'custom',
|
||||
label: '身份证',
|
||||
required: true,
|
||||
customRender: () => (
|
||||
<Space>
|
||||
<Input allow-clear v-model:value={_formParams.idCard} placeholder={'请输入身份证号'} />
|
||||
<Button type={'primary'} icon={h(SearchOutlined)} onClick={() => searchSecurityUnitId()}>
|
||||
搜索保安证号
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
|
||||
telephone: {
|
||||
type: 'input',
|
||||
label: '手机号',
|
||||
required: true,
|
||||
},
|
||||
sex: {
|
||||
type: 'radioGroup',
|
||||
label: '性别',
|
||||
required: true,
|
||||
options: [...dictSelectNodes('Sex')],
|
||||
},
|
||||
securityNumber: {
|
||||
type: 'input',
|
||||
label: '保安证号',
|
||||
required: true,
|
||||
},
|
||||
dateOfBirth: {
|
||||
type: 'datePicker',
|
||||
label: '出生日期',
|
||||
componentsProps: {
|
||||
valueFormat: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
|
||||
workPost: {
|
||||
type: 'input',
|
||||
label: '工作岗位',
|
||||
},
|
||||
nativePlace: {
|
||||
type: 'input',
|
||||
label: '籍贯',
|
||||
},
|
||||
homeAddress: {
|
||||
type: 'input',
|
||||
label: '家庭住址',
|
||||
},
|
||||
noSecurityNumberDesc: {
|
||||
type: 'input',
|
||||
label: '无证说明',
|
||||
},
|
||||
|
||||
remark: {
|
||||
type: 'inputTextArea',
|
||||
label: '备注',
|
||||
},
|
||||
})
|
||||
Modal.confirm({
|
||||
title: params.name ? `【${params.name}】 编辑保安信息` : '新增保安人员',
|
||||
width: 600,
|
||||
icon: ' ',
|
||||
centered: true,
|
||||
content: () => <FormProMax ref={_formRef} v-model:value={_formParams} formItemOptions={_formOptions.value} />,
|
||||
onOk: async () => {
|
||||
await _formRef.value?.validate()
|
||||
const resp = await api.post('/m2/eu/add_upd_sec_user', {
|
||||
..._formParams,
|
||||
})
|
||||
message.success(resp.message)
|
||||
clearForm()
|
||||
callback && callback()
|
||||
},
|
||||
onCancel: async () => {
|
||||
clearForm()
|
||||
},
|
||||
})
|
||||
}
|
||||
const clearForm = () => {
|
||||
_formParams.snowFlakeId = ''
|
||||
_formParams.serviceProjectId = ''
|
||||
_formParams.securityUnitId = ''
|
||||
_formParams.name = ''
|
||||
_formParams.photo = ''
|
||||
_formParams.telephone = ''
|
||||
_formParams.workPost = ''
|
||||
_formParams.sex = ''
|
||||
_formParams.nativePlace = ''
|
||||
_formParams.idCard = ''
|
||||
_formParams.dateOfBirth = ''
|
||||
_formParams.securityNumber = ''
|
||||
_formParams.noSecurityNumberDesc = ''
|
||||
_formParams.homeAddress = ''
|
||||
_formParams.remark = ''
|
||||
}
|
||||
export const showEnterprisesUnit = (record_) => {
|
||||
// console.log('🚀 ~ showEnterprisesUnit ~ record_:', record_)
|
||||
const _tableRef = ref<ComponentExposed<typeof TableProMax>>(null)
|
||||
const _columns: _TableProps['columns'] = [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: '姓名',
|
||||
width: 100,
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
dataIndex: 'idCard',
|
||||
title: '身份证',
|
||||
customRender: ({ text }) => {
|
||||
return text.desensitizedValue
|
||||
},
|
||||
width: 160,
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
dataIndex: 'sex',
|
||||
title: '性别',
|
||||
width: 60,
|
||||
customRender: ({ record }) => {
|
||||
return <Tag color={'success'}>{record.sex.label}</Tag>
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'dateOfBirth',
|
||||
title: '出生日期',
|
||||
width: 100,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'telephone',
|
||||
title: '手机号',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
customRender: ({ text }) => text?.originalValue,
|
||||
},
|
||||
{
|
||||
dataIndex: 'securityNumber',
|
||||
title: '保安证号',
|
||||
width: 150,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'nativePlace',
|
||||
title: '籍贯',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'workPost',
|
||||
title: '工作岗位',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
dataIndex: 'homeAddress',
|
||||
title: '家庭住址',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'remark',
|
||||
title: '备注',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataIndex: 'createTime',
|
||||
title: '创建时间',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
dataIndex: 'opt',
|
||||
title: '操作',
|
||||
width: 200,
|
||||
fixed: 'right',
|
||||
customRender: ({ record }) => (
|
||||
<Space>
|
||||
<Button class='btn-warn' onClick={() => saveOrUpdateEnterprisesUnit(_tableRef.value?.requestGetTableData, record, 'edit')}>
|
||||
编辑
|
||||
</Button>
|
||||
<Button
|
||||
class='btn-danger'
|
||||
onClick={() =>
|
||||
deleteDataModal(record.name, async () => {
|
||||
const resp = await api.delete('/m2/eu/del_security_user_id', {
|
||||
securityUserId: record?.snowFlakeId,
|
||||
})
|
||||
message.success(resp.message)
|
||||
await _tableRef.value?.requestGetTableData()
|
||||
})
|
||||
}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
]
|
||||
const x: number = _columns.reduce((a, b) => a + (b.width as number), 0)
|
||||
const _reqApi: _TableProps['requestApi'] = (params) => {
|
||||
// console.log(record_);
|
||||
|
||||
;(params as PageParams<EnterprisesUnitPagerQueryParams>).params.serviceProjectId = record_.snowFlakeId
|
||||
return api.post('/m2/eu/sec_user_pager', params)
|
||||
}
|
||||
Modal.info({
|
||||
title: `【${record_.name}】 管理保安人员`,
|
||||
width: '80%',
|
||||
centered: true,
|
||||
maskClosable: true,
|
||||
content: () => (
|
||||
<TableProMax
|
||||
scroll={{ x: x }}
|
||||
ref={_tableRef}
|
||||
size='small'
|
||||
columns={_columns}
|
||||
requestApi={_reqApi}
|
||||
// searchFormOptions={{
|
||||
// name: {
|
||||
// type: 'input',
|
||||
// label: '姓名',
|
||||
// },
|
||||
// securityNumber: {
|
||||
// type: 'input',
|
||||
// label: '保安证号',
|
||||
// },
|
||||
// telephone: {
|
||||
// type: 'input',
|
||||
// label: '手机号',
|
||||
// },
|
||||
// }}
|
||||
v-slots={
|
||||
{
|
||||
tableHeader: (_) => {
|
||||
return (
|
||||
<Space>
|
||||
<Button class='btn-success' onClick={() => saveOrUpdateEnterprisesUnit(_tableRef.value?.requestGetTableData, record_, 'add')}>
|
||||
新增
|
||||
</Button>
|
||||
</Space>
|
||||
)
|
||||
},
|
||||
} as TableProMaxSlots<PoliceUnitPagerVo>
|
||||
}
|
||||
/>
|
||||
),
|
||||
})
|
||||
}
|
|
@ -1,197 +1,716 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 企事业单位 -->
|
||||
<TableProMax ref="tableRef" :request-api="reqApi" :columns="columns" :searchFormOptions="searchFormOptions"
|
||||
:scroll="{ x }">
|
||||
<!-- <template #tableHeader>
|
||||
<TableProMax
|
||||
style="width: 100%"
|
||||
:expandedRowRender="expandedRowRender"
|
||||
:expand-column-width="50"
|
||||
:defaultExpandAllRows="false"
|
||||
ref="tableRef"
|
||||
:request-api="reqApi"
|
||||
:columns="columns"
|
||||
:searchFormOptions="searchFormOptions"
|
||||
:scroll="{ x: x }"
|
||||
>
|
||||
<template #tableHeader>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="addUserManagement">新增用户</a-button>
|
||||
<a-button type="primary" @click="saveOrUpdateEnterprisesUnit">新增企事业单位</a-button>
|
||||
</a-space>
|
||||
</template> -->
|
||||
</template>
|
||||
</TableProMax>
|
||||
<a-modal v-model:open="visible" :title="title" @ok="submit" @cancel="closeModal">
|
||||
<!-- <FormProMax ref="formRef" v-model:value="formParams" :form-item-options="formItemOptions" /> -->
|
||||
<a-modal v-model:open="visible" :title="serviceTitle" @ok="submit" @cancel="closeModal">
|
||||
<FormProMax ref="formRef" v-model:value="formParams" :form-item-options="formItemOptions" />
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import {storeTreeData, loadTreeFromCache} from '@/utils/DB.ts'
|
||||
import { deleteDataModal } from '@/components/tsx/ModalPro.tsx'
|
||||
import { EnterprisesUnitSaveOrUpdateParams } from '@/types/views/unitManage/police/policeUnit.ts'
|
||||
import MapContainer from '@/components/aMap/MapContainer.vue'
|
||||
import { AutoComplete, Button, Input, message, Modal, Space } from 'ant-design-vue'
|
||||
import { debounce } from 'lodash-es'
|
||||
import FormProMax from '@/components/form/FormProMax.vue'
|
||||
import api from '@/axios'
|
||||
import {ref, reactive} from 'vue'
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import TableProMax from '@/components/table/TableProMax.vue'
|
||||
import {TableProMaxProps} from '@/types/components/table/index.ts'
|
||||
import {ComponentExposed} from 'vue-component-type-helpers'
|
||||
import {dictSelectNodes} from '@/config/dict.ts'
|
||||
import {publicUnitPagerQueryParams, FromItem} from '@/types/views/publicUnit.ts'
|
||||
// import FormProMax from '@/components/form/FormProMax.vue'
|
||||
import {FormProMaxItemOptions} from '@/types/components/form//index.ts'
|
||||
import {FormExpose} from 'ant-design-vue/es/form/Form'
|
||||
import {message} from 'ant-design-vue'
|
||||
|
||||
const formRef = ref<FormExpose>(null)
|
||||
import { TableProMaxProps } from '@/types/components/table/index.ts'
|
||||
import { ComponentExposed } from 'vue-component-type-helpers'
|
||||
import { dictSelectNodes } from '@/config/dict.ts'
|
||||
import { publicUnitPagerQueryParams } from '@/types/views/publicUnit.ts'
|
||||
import { FormProMaxItemOptions } from '@/types/components/form//index.ts'
|
||||
import { FormExpose } from 'ant-design-vue/es/form/Form'
|
||||
import { serviceProjectSaveOrUpdateParams_ } from '@/types/views/serviceManagement'
|
||||
import { showEnterprisesUnit } from './index.tsx'
|
||||
type _FormType = EnterprisesUnitSaveOrUpdateParams & {
|
||||
contactPersonInfoName?: string
|
||||
contactPersonInfoTelephone?: string
|
||||
}
|
||||
type TableProps = TableProMaxProps<publicUnitPagerQueryParams>
|
||||
const tableRef = ref<ComponentExposed<typeof TableProMax>>(null!)
|
||||
const reqApi: TableProps['requestApi'] = (params) => api.post('/management/police/enterprisesUnitPager', params) //分页
|
||||
|
||||
const reqApi: TableProps['requestApi'] = (params) => api.post('/eu/pager', params) //分页
|
||||
const tableRef = ref<ComponentExposed<typeof TableProMax>>(null)
|
||||
const columns: TableProps['columns'] = [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: '单位名称',
|
||||
width: 200,
|
||||
},
|
||||
// {
|
||||
// dataIndex: 'code',
|
||||
// title: '单位代码',
|
||||
// },
|
||||
|
||||
{
|
||||
dataIndex: 'provinceName',
|
||||
title: '行政区划',
|
||||
customRender: ({record}) => {
|
||||
customRender: ({ record }) => {
|
||||
return `${record?.provinceName}/${record?.cityName}/${record?.districtsName}/${record?.streetName}`
|
||||
},
|
||||
width: 300,
|
||||
},
|
||||
|
||||
// {
|
||||
// dataIndex: 'isEnable',
|
||||
// title: '是否启用',
|
||||
// customRender: ({ text }) => <a-tag color={text?.extData?.color}>{text?.label}</a-tag>,
|
||||
// width: 150,
|
||||
// },
|
||||
// {
|
||||
// dataIndex: 'checkStatus',
|
||||
// title: '是否审核',
|
||||
// customRender: ({ record }) => {
|
||||
// return record.checkStatus?.extData?.color === 'success' ? <a-tag color='green'>{record?.checkStatus?.label}</a-tag> : <a-tag color='#f50'>{record?.checkStatus?.label}</a-tag>
|
||||
// },
|
||||
// },
|
||||
{
|
||||
dataIndex: 'address',
|
||||
title: '详细地址',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
dataIndex: 'contactPersonInfo',
|
||||
title: '联系人姓名',
|
||||
customRender: ({record}) => {
|
||||
customRender: ({ record }) => {
|
||||
return record?.contactPersonInfo?.name
|
||||
},
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
dataIndex: 'contactPersonInfo',
|
||||
title: '联系人手机号',
|
||||
customRender: ({record}) => {
|
||||
customRender: ({ record }) => {
|
||||
return record?.contactPersonInfo?.telephone
|
||||
},
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
dataIndex: 'createTime',
|
||||
title: '创建时间',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'remark',
|
||||
title: '备注',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
width: 200,
|
||||
dataIndex: 'opt',
|
||||
title: '操作',
|
||||
customRender: ({ record }) => (
|
||||
<Space>
|
||||
<Button
|
||||
class='btn-warn'
|
||||
onClick={() =>
|
||||
saveOrUpdateEnterprisesUnit(
|
||||
{
|
||||
snowFlakeId: record.snowFlakeId,
|
||||
policeUnitId: record.policeUnitId,
|
||||
name: record.name,
|
||||
type: record.type.value,
|
||||
administrativeDivisionCodes: [record.province, record.city, record.districts, record.street].filter(Boolean),
|
||||
address: record.address,
|
||||
point: record.point,
|
||||
contactPersonInfoName: record.contactPersonInfo?.name,
|
||||
contactPersonInfoTelephone: record.contactPersonInfo?.telephone,
|
||||
remark: record.remark,
|
||||
},
|
||||
tableRef.value?.requestGetTableData
|
||||
)
|
||||
}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
<Button
|
||||
class='btn-danger'
|
||||
onClick={() =>
|
||||
deleteDataModal(record.name, async () => {
|
||||
// const resp = await api.delete('/enterprisesUnit/deleteById', {
|
||||
const resp = await api.delete('/eu/del_id', {
|
||||
enterprisesUnitId: record.snowFlakeId,
|
||||
})
|
||||
message.success(resp.message)
|
||||
await tableRef.value?.requestGetTableData()
|
||||
})
|
||||
}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
]
|
||||
const x: number = columns.reduce((a, b) => a + (b.width as number), 0)
|
||||
const visible = ref(false)
|
||||
const title = ref('新增用户')
|
||||
const addUserManagement = () => {
|
||||
visible.value = true
|
||||
title.value = ''
|
||||
// const x: number = columns.reduce((a, b) => a + (b.width as number), 0)
|
||||
const x: number = columns.reduce((a, b) => {
|
||||
// console.log('x_____________________', a, b, b.width)
|
||||
return a + (b.width as number)
|
||||
}, 0)
|
||||
|
||||
const saveOrUpdateEnterprisesUnit = (params: _FormType, callback: Function) => {
|
||||
const _formRef = ref<FormExpose>(null)
|
||||
const _mapRef = ref<ComponentExposed<typeof MapContainer>>(null)
|
||||
const _formParams = ref<_FormType>({ ...params })
|
||||
|
||||
let city = ''
|
||||
const initMarker = (map: AMap.Map) => {
|
||||
//添加maker点 设置point
|
||||
const maker = new AMap.Marker({
|
||||
position: _formParams.value.point,
|
||||
draggable: true,
|
||||
})
|
||||
maker.on('dragend', ({ lnglat }) => {
|
||||
_formParams.value.point = lnglat
|
||||
})
|
||||
map.clearMap()
|
||||
map.add(maker)
|
||||
map.setFitView()
|
||||
}
|
||||
const autoAddress = ref<SelectNodeVo<string>[]>([])
|
||||
|
||||
const _formOptions = ref<FormProMaxItemOptions<_FormType>>({
|
||||
name: {
|
||||
type: 'custom',
|
||||
label: '单位名称',
|
||||
required: true,
|
||||
customRender: () => {
|
||||
return (
|
||||
// AutoComplete 自动完成 组件
|
||||
<AutoComplete
|
||||
v-model:value={_formParams.value.name}
|
||||
options={autoAddress.value}
|
||||
onSelect={(_, options: SelectNodeVo<string>) => {
|
||||
_formParams.value.point = options.extData?.location
|
||||
_formParams.value.address = options.extData?.address
|
||||
initMarker(_mapRef.value?.mapInstance)
|
||||
}}
|
||||
onSearch={debounce((val: string) => {
|
||||
//@ts-ignore
|
||||
const auto = new AMap.AutoComplete({
|
||||
city: city,
|
||||
// input: 'tipinput',
|
||||
citylimit: true,
|
||||
})
|
||||
auto.search(val, (status, result) => {
|
||||
if (status === 'complete') {
|
||||
// 生成组件需要数据
|
||||
autoAddress.value = result.tips?.map((e) => {
|
||||
return {
|
||||
value: e.name,
|
||||
label: e.name,
|
||||
extData: {
|
||||
district: e.district,
|
||||
address: e.address,
|
||||
location: e.location,
|
||||
},
|
||||
} as SelectNodeVo<string>
|
||||
})
|
||||
} else {
|
||||
autoAddress.value = []
|
||||
}
|
||||
})
|
||||
}, 300)}
|
||||
v-slots={{
|
||||
option: (item: SelectNodeVo<string>) => {
|
||||
return (
|
||||
<div>
|
||||
<p>{item.label}</p>
|
||||
<p style={{ color: '#9a9c9d' }}>
|
||||
{item.extData?.district} {item.extData?.address}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Input placeholder='请输入单位名称' />
|
||||
</AutoComplete>
|
||||
)
|
||||
},
|
||||
},
|
||||
type: {
|
||||
type: 'select',
|
||||
label: '单位类型',
|
||||
required: true,
|
||||
// @ts-ignore
|
||||
options: dictSelectNodes('EnterprisesUnitType'),
|
||||
},
|
||||
administrativeDivisionCodes: {
|
||||
type: 'administrativeDivisionTree',
|
||||
label: '行政区划',
|
||||
required: true,
|
||||
componentsProps: {
|
||||
// @ts-ignore
|
||||
displayRender: ({ labels }): string => {
|
||||
city = labels[1]
|
||||
return labels.join(' / ')
|
||||
},
|
||||
},
|
||||
},
|
||||
address: {
|
||||
type: 'inputTextArea',
|
||||
label: '详细地址',
|
||||
},
|
||||
map: {
|
||||
type: 'custom',
|
||||
label: '经纬度',
|
||||
customRender: () => (
|
||||
<MapContainer
|
||||
ref={_mapRef}
|
||||
plugins={['AMap.AutoComplete', 'AMap.PlaceSearch']}
|
||||
style={{ width: '100%', height: '300px', position: 'relative' }}
|
||||
initCallback={(map) => {
|
||||
const contextMenu = new AMap.ContextMenu()
|
||||
contextMenu.addItem(
|
||||
'标记',
|
||||
() => {
|
||||
const { lng, lat } = contextMenu.getPosition()
|
||||
_formParams.value.point = [lng, lat]
|
||||
initMarker(map)
|
||||
},
|
||||
0
|
||||
)
|
||||
map.on('rightclick', ({ lnglat }) => {
|
||||
contextMenu.open(map, lnglat)
|
||||
})
|
||||
if (_formParams.value.point) {
|
||||
initMarker(map)
|
||||
}
|
||||
}}
|
||||
></MapContainer>
|
||||
),
|
||||
},
|
||||
contactPersonInfoName: {
|
||||
type: 'input',
|
||||
label: '联系人名称',
|
||||
},
|
||||
contactPersonInfoTelephone: {
|
||||
type: 'input',
|
||||
label: '联系人电话',
|
||||
},
|
||||
remark: {
|
||||
type: 'inputTextArea',
|
||||
label: '备注',
|
||||
},
|
||||
})
|
||||
Modal.confirm({
|
||||
title: params.snowFlakeId ? `【${params.name}】 信息编辑` : '新增企事业单位',
|
||||
width: 600,
|
||||
icon: ' ',
|
||||
centered: true,
|
||||
content: () => <FormProMax ref={_formRef} v-model:value={_formParams.value} formItemOptions={_formOptions.value} />,
|
||||
onOk: debounce(async () => {
|
||||
await _formRef.value?.validate()
|
||||
|
||||
const resp = await api.post('/eu/add_upd', {
|
||||
..._formParams.value,
|
||||
contactPersonInfo: {
|
||||
name: _formParams.value.contactPersonInfoName,
|
||||
telephone: _formParams.value.contactPersonInfoTelephone,
|
||||
},
|
||||
})
|
||||
message.success(resp.message)
|
||||
await tableRef.value?.requestGetTableData()
|
||||
|
||||
callback && callback()
|
||||
}, 300),
|
||||
})
|
||||
}
|
||||
|
||||
const getTree = async () => {
|
||||
// 先尝试从缓存中加载数据
|
||||
const cachedData = await loadTreeFromCache()
|
||||
if (cachedData) {
|
||||
console.log('未发请求')
|
||||
// 如果缓存存在,直接使用缓存数据
|
||||
return cachedData
|
||||
} else {
|
||||
console.log('发起了请求')
|
||||
// 如果缓存不存在,发起 API 请求
|
||||
const res = await api.get<any>('/common/administrativeDivisionTree')
|
||||
await storeTreeData(res.data)
|
||||
return res.data
|
||||
}
|
||||
}
|
||||
const loadOptions = async () => {
|
||||
const treeData = await getTree()
|
||||
searchFormOptions.treeSelect.options = treeData
|
||||
}
|
||||
loadOptions()
|
||||
const searchFormOptions = reactive<TableProps['searchFormOptions']>({
|
||||
name: {
|
||||
type: 'input',
|
||||
label: '名称',
|
||||
},
|
||||
treeSelect: {
|
||||
type: 'cascader',
|
||||
// type: 'cascader',
|
||||
type: 'administrativeDivisionTree',
|
||||
label: '行政区划',
|
||||
},
|
||||
telephone: {
|
||||
type: 'input',
|
||||
label: '手机号',
|
||||
},
|
||||
// isEnable: {
|
||||
// type: 'select',
|
||||
// label: '是否启用',
|
||||
// options: [
|
||||
// {
|
||||
// value: null,
|
||||
// label: '全部',
|
||||
// },
|
||||
// ...dictSelectNodes('IsEnable'),
|
||||
// ],
|
||||
// },
|
||||
})
|
||||
|
||||
type _TableProps = TableProMaxProps<any>
|
||||
const isRecruitSecurityHidden = ref<boolean>(false)
|
||||
const visible = ref(false)
|
||||
const serviceTitle = ref('新增服务项目')
|
||||
const idNumberDisabled = ref<boolean>(true)
|
||||
const formRef = ref<FormExpose>(null)
|
||||
const enterprisesUnitId = ref('')
|
||||
const netType = computed(() => {
|
||||
//@ts-ignore
|
||||
return formParams.value.type === 'security' ? dictSelectNodes('ServiceProjectTwoType') : dictSelectNodes('UserType' as any)
|
||||
})
|
||||
const formParams = ref<{
|
||||
snowFlakeId?: string
|
||||
enterprisesUnitId: string
|
||||
securityUnitId: string
|
||||
administrativeDivisionCodes?: null
|
||||
projectManagerMiniProgramUserId?: string
|
||||
projectManagerMiniProgramUserName?: string
|
||||
name: string
|
||||
sex: number
|
||||
telephone: string
|
||||
isEnable: any
|
||||
type: string
|
||||
twoType?: number
|
||||
outsourceName?: string
|
||||
isFiling?: number
|
||||
idNumber?: string
|
||||
serviceArea?: number
|
||||
buildingTotal?: number
|
||||
houseTotal?: number
|
||||
staffTotal?: number
|
||||
securityUserTotal?: number
|
||||
remark?: string
|
||||
}>({
|
||||
name: '',
|
||||
sex: 0,
|
||||
telephone: '',
|
||||
isEnable: 0,
|
||||
enterprisesUnitId: null,
|
||||
type: 'security',
|
||||
securityUnitId: null,
|
||||
})
|
||||
|
||||
const submit = async () => {
|
||||
// await formRef.value.validate()
|
||||
}
|
||||
const closeModal = () => {
|
||||
visible.value = false
|
||||
}
|
||||
const formItemOptions = ref<FormProMaxItemOptions<FromItem>>({
|
||||
const securityUnitIdList = ref<any>([])
|
||||
const formItemOptions = ref<FormProMaxItemOptions<serviceProjectSaveOrUpdateParams_>>({
|
||||
name: {
|
||||
type: 'input',
|
||||
label: '姓名',
|
||||
label: '服务项目名称',
|
||||
required: true,
|
||||
},
|
||||
sex: {
|
||||
|
||||
securityUnitId: {
|
||||
type: 'select',
|
||||
label: '保安单位',
|
||||
required: true,
|
||||
options: securityUnitIdList,
|
||||
},
|
||||
type: {
|
||||
type: 'radioGroup',
|
||||
label: '性别',
|
||||
options: dictSelectNodes('Sex'),
|
||||
label: '服务类型',
|
||||
//@ts-ignore
|
||||
options: dictSelectNodes('ServiceProjectType'),
|
||||
required: true,
|
||||
componentsProps: {
|
||||
onChange: (e) => {
|
||||
if (e.target?.value === 'security') {
|
||||
isRecruitSecurityHidden.value = false
|
||||
formParams.value.twoType = null
|
||||
} else {
|
||||
formParams.value.twoType = null
|
||||
isRecruitSecurityHidden.value = true
|
||||
}
|
||||
},
|
||||
telephone: {
|
||||
},
|
||||
},
|
||||
twoType: {
|
||||
required: true,
|
||||
type: 'radioGroup',
|
||||
label: '二级类型',
|
||||
options: netType,
|
||||
componentsProps: {
|
||||
onChange: (e) => {
|
||||
if (e.target.value !== 'outsource') {
|
||||
idNumberDisabled.value = true
|
||||
formParams.value.outsourceName = ''
|
||||
} else {
|
||||
idNumberDisabled.value = false
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
outsourceName: {
|
||||
type: 'input',
|
||||
label: '手机号',
|
||||
required: true,
|
||||
label: '外包公司名称',
|
||||
hidden: idNumberDisabled as any,
|
||||
},
|
||||
isEnable: {
|
||||
type: 'radioGroup',
|
||||
label: '启用状态',
|
||||
options: dictSelectNodes('IsEnable'),
|
||||
isFiling: {
|
||||
required: true,
|
||||
type: 'radioGroup',
|
||||
label: '是否备案',
|
||||
options: dictSelectNodes('IsOrNot'),
|
||||
},
|
||||
idNumber: {
|
||||
type: 'input',
|
||||
label: '保安服务许可证',
|
||||
},
|
||||
serviceArea: {
|
||||
type: 'inputNumber',
|
||||
label: '服务区域面积',
|
||||
},
|
||||
buildingTotal: {
|
||||
type: 'inputNumber',
|
||||
label: '楼栋数量',
|
||||
componentsProps: {
|
||||
formatter: (value: any) => {
|
||||
return Math.round(value) ? Math.round(value) : ('' as any)
|
||||
},
|
||||
min: 0,
|
||||
},
|
||||
},
|
||||
houseTotal: {
|
||||
type: 'inputNumber',
|
||||
label: '户数',
|
||||
componentsProps: {
|
||||
formatter: (value: any) => {
|
||||
return Math.round(value) ? Math.round(value) : ('' as any)
|
||||
},
|
||||
min: 0,
|
||||
},
|
||||
},
|
||||
staffTotal: {
|
||||
type: 'inputNumber',
|
||||
label: '工作人员数量',
|
||||
componentsProps: {
|
||||
formatter: (value: any) => {
|
||||
return Math.round(value) ? Math.round(value) : ('' as any)
|
||||
},
|
||||
min: 0,
|
||||
},
|
||||
},
|
||||
securityUserTotal: {
|
||||
type: 'inputNumber',
|
||||
label: '保安人员数量',
|
||||
componentsProps: {
|
||||
formatter: (value: any) => {
|
||||
return Math.round(value) ? Math.round(value) : ('' as any)
|
||||
},
|
||||
min: 0,
|
||||
},
|
||||
},
|
||||
remark: {
|
||||
type: 'inputTextArea',
|
||||
label: '备注',
|
||||
},
|
||||
})
|
||||
|
||||
const _tableRef = ref(null)
|
||||
|
||||
const deleteAccount = async (snowFlakeId) => {
|
||||
const resp = await api.delete('/m2/eu/deleteSpById', {
|
||||
serviceProjectId: snowFlakeId,
|
||||
})
|
||||
message.success(resp.message)
|
||||
await _tableRef.value?.requestGetTableData()
|
||||
}
|
||||
const expandedRowRender: TableProMaxProps['expandedRowRender'] = ({ record }) => {
|
||||
const _columns: _TableProps['columns'] = [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: '服务项目名称',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataIndex: 'type',
|
||||
title: '服务类型',
|
||||
customRender: ({ text }) => <a-tag>{text?.label}</a-tag>,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataIndex: 'twoType',
|
||||
title: '二级类型',
|
||||
customRender: ({ text }) => <a-tag>{text?.label}</a-tag>,
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataIndex: 'outsourceName',
|
||||
title: '外包公司名称',
|
||||
customRender: ({ record }) => {
|
||||
if (record.twoType.value === 'outsource') {
|
||||
return record.outsourceName
|
||||
}
|
||||
},
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'isFiling',
|
||||
title: '是否备案',
|
||||
customRender: ({ text }) => {
|
||||
if (text?.label === '是') {
|
||||
return <a-tag color={'success'}>{text?.label}</a-tag>
|
||||
} else {
|
||||
return <a-tag color={'error'}>{text?.label}</a-tag>
|
||||
}
|
||||
},
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataIndex: 'idNumber',
|
||||
title: '保安服务许可证',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
dataIndex: 'serviceArea',
|
||||
title: '服务区域面积',
|
||||
width: 60,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'buildingTotal',
|
||||
title: '楼栋数量',
|
||||
width: 60,
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
dataIndex: 'houseTotal',
|
||||
title: '户数',
|
||||
width: 60,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'staffTotal',
|
||||
title: '工作人员数量',
|
||||
width: 60,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'securityUserTotal',
|
||||
title: '保安人员数量',
|
||||
width: 60,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'remark',
|
||||
title: '备注',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataIndex: 'createUserInfo',
|
||||
title: '创建人',
|
||||
width: 200,
|
||||
ellipsis: true,
|
||||
customRender: ({ record }) => {
|
||||
return (
|
||||
<div>
|
||||
<p>创建人:{record.createUserInfo.name} </p>
|
||||
|
||||
<p>创建人单位:{record.createUserInfo.unitName} </p>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
dataIndex: 'createTime',
|
||||
title: '创建时间',
|
||||
width: 120,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'opt',
|
||||
title: '操作',
|
||||
fixed: 'right',
|
||||
width: 300,
|
||||
customRender({ record }) {
|
||||
return (
|
||||
<a-space>
|
||||
<a-button class='btn-success' onClick={() => showEnterprisesUnit(record)}>
|
||||
保安人员
|
||||
</a-button>
|
||||
<a-button
|
||||
class='btn-warn'
|
||||
onClick={async () => {
|
||||
visible.value = true
|
||||
serviceTitle.value = '编辑服务项目'
|
||||
idNumberDisabled.value = record.twoType.value !== 'outsource'
|
||||
formParams.value.securityUnitId = record.securityUnitId //企事业单位id
|
||||
formParams.value.enterprisesUnitId = record.enterprisesUnitId //企事业单位id
|
||||
formParams.value.snowFlakeId = record.snowFlakeId //id
|
||||
formParams.value.projectManagerMiniProgramUserId = record.projectManagerMiniProgramUserId //项目经理小程序用户id
|
||||
formParams.value.name = record.name
|
||||
formParams.value.type = record.type.value //服务类型
|
||||
formParams.value.twoType = record.twoType.value //二级类型
|
||||
formParams.value.outsourceName = record.outsourceName //外包公司名称
|
||||
formParams.value.isFiling = record.isFiling.value //是否备案
|
||||
formParams.value.remark = record.remark //备注
|
||||
formParams.value.idNumber = record.idNumber //证件号(保安服务许可证/备案证
|
||||
formParams.value.serviceArea = record.serviceArea //服务区域面积
|
||||
formParams.value.buildingTotal = record.buildingTotal //楼栋数量
|
||||
formParams.value.houseTotal = record.houseTotal //户数
|
||||
formParams.value.staffTotal = record.staffTotal //工作人员数量
|
||||
formParams.value.securityUserTotal = record.securityUserTotal //保安人员数量
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</a-button>
|
||||
<a-popconfirm title='确认删除账号吗?' onConfirm={() => deleteAccount(record.snowFlakeId)}>
|
||||
<a-button danger>删除</a-button>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
)
|
||||
},
|
||||
},
|
||||
]
|
||||
const x2: number = _columns.reduce((a, b) => a + (b.width as number), 0)
|
||||
const _reqApi: _TableProps['requestApi'] = async () => {
|
||||
// @ts-ignore
|
||||
return await api.get('/m2/eu/listSp', { enterprisesUnitId: record?.snowFlakeId })
|
||||
}
|
||||
return (
|
||||
<TableProMax
|
||||
scroll={{ x: x2 }}
|
||||
ref={_tableRef}
|
||||
size='small'
|
||||
columns={_columns}
|
||||
requestApi={_reqApi}
|
||||
isPagination={false}
|
||||
v-slots={{
|
||||
tableHeader: () => {
|
||||
return (
|
||||
<Space>
|
||||
<Button type={'primary'} onClick={() => addService(record)}>
|
||||
新增服务项目
|
||||
</Button>
|
||||
</Space>
|
||||
)
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const closeModal = async () => {
|
||||
visible.value = false
|
||||
formParams.value = {
|
||||
securityUnitId: '',
|
||||
enterprisesUnitId: '',
|
||||
administrativeDivisionCodes: '',
|
||||
name: '',
|
||||
type: 'security',
|
||||
idNumber: '',
|
||||
serviceArea: null,
|
||||
buildingTotal: null,
|
||||
houseTotal: null,
|
||||
staffTotal: null,
|
||||
securityUserTotal: null,
|
||||
remark: '',
|
||||
}
|
||||
formRef.value.resetFields()
|
||||
enterprisesUnitId.value = ''
|
||||
serviceTitle.value = '新增服务项目'
|
||||
idNumberDisabled.value = false
|
||||
}
|
||||
|
||||
const submit = async () => {
|
||||
await formRef.value.validate()
|
||||
const serviceProjectSaveOrUpdateParams = { ...formParams.value }
|
||||
const resp = await api.post('/m2/eu/add_upd_sp', serviceProjectSaveOrUpdateParams)
|
||||
message.success(resp.message)
|
||||
await _tableRef.value.requestGetTableData()
|
||||
await closeModal()
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const res = await api.get('/management/listSecurityUnit')
|
||||
securityUnitIdList.value = res.data
|
||||
})
|
||||
const addService = function (record) {
|
||||
formParams.value.enterprisesUnitId = record.snowFlakeId //企事业单位Id
|
||||
visible.value = true
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
<div style="height: 100%">
|
||||
<a-form-item v-if="options.length > 0" label="行政区划">
|
||||
<a-cascader
|
||||
change-on-select
|
||||
:load-data="loadData"
|
||||
:field-names="{ label: 'label', value: 'value', children: 'children' }"
|
||||
@change="cascaderChange"
|
||||
style="width: 300px"
|
||||
|
@ -77,7 +79,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { storeTreeData, loadTreeFromCache } from '@/utils/DB.ts'
|
||||
// import { storeTreeData, loadTreeFromCache } from '@/utils/DB.ts'
|
||||
import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
|
||||
|
@ -89,35 +91,53 @@ defineComponent({
|
|||
name: 'Register',
|
||||
})
|
||||
onMounted(() => {
|
||||
getTree()
|
||||
getTree(0)
|
||||
})
|
||||
import type { CascaderProps } from 'ant-design-vue'
|
||||
const loadData: CascaderProps['loadData'] = async (selectedOptions) => {
|
||||
const targetOption = selectedOptions[selectedOptions.length - 1]
|
||||
targetOption.loading = true
|
||||
const res = await api.get<any>('/common/administrativeDivisionByParentCode', { parentCode: targetOption.value })
|
||||
for (let index = 0; index < res.data.length; index++) {
|
||||
delete res.data[index].children
|
||||
}
|
||||
targetOption.children = [...res.data]
|
||||
options.value = [...options.value]
|
||||
targetOption.loading = false
|
||||
}
|
||||
const labelCol = { style: { width: '120px' } }
|
||||
const wrapperCol = { span: 14 }
|
||||
const filter: ShowSearchType['filter'] = (inputValue, path) => {
|
||||
return path.some((option) => option.title.toLowerCase().indexOf(inputValue.toLowerCase()) > -1)
|
||||
}
|
||||
const value = ref<string[]>([])
|
||||
const options = ref<any[]>([])
|
||||
const options = ref<CascaderProps['options']>([])
|
||||
|
||||
const cascaderChange = (value: any): void => {
|
||||
formState.administrativeDivisionCodes = [...value]
|
||||
}
|
||||
|
||||
// 获取树形结构数据并存储在 IndexedDB 中的主函数
|
||||
const getTree = async () => {
|
||||
// 先尝试从缓存中加载数据
|
||||
const cachedData = await loadTreeFromCache()
|
||||
if (cachedData) {
|
||||
console.log('未发请求')
|
||||
// 如果缓存存在,直接使用缓存数据
|
||||
options.value = cachedData
|
||||
// console.log('Loaded from cache:', cachedData)
|
||||
} else {
|
||||
console.log('发起了请求')
|
||||
// 如果缓存不存在,发起 API 请求
|
||||
const res = await api.get<any>('/common/administrativeDivisionTree')
|
||||
options.value = res.data
|
||||
await storeTreeData(res.data)
|
||||
const getTree = async (parentCode: string | number) => {
|
||||
const res = await api.get<any>('/common/administrativeDivisionByParentCode', { parentCode })
|
||||
for (let index = 0; index < res.data.length; index++) {
|
||||
delete res.data[index].children
|
||||
}
|
||||
options.value = res.data
|
||||
// // 先尝试从缓存中加载数据
|
||||
// const cachedData = await loadTreeFromCache()
|
||||
// if (cachedData) {
|
||||
// console.log('未发请求')
|
||||
// // 如果缓存存在,直接使用缓存数据
|
||||
// options.value = cachedData
|
||||
// // console.log('Loaded from cache:', cachedData)
|
||||
// } else {
|
||||
// console.log('发起了请求')
|
||||
// // 如果缓存不存在,发起 API 请求
|
||||
// const res = await api.get<any>('/common/administrativeDivisionTree', { level: 0 })
|
||||
// options.value = res.data
|
||||
// await storeTreeData(res.data)
|
||||
// }
|
||||
}
|
||||
import type { Rule } from 'ant-design-vue/es/form'
|
||||
import type { FormInstance } from 'ant-design-vue'
|
||||
|
@ -245,6 +265,7 @@ const getCheckStatus = async () => {
|
|||
})
|
||||
}
|
||||
import { useUserStore } from '@/stores/modules/userStore.ts'
|
||||
import { log } from 'console'
|
||||
const showConfirm = (columnsDate: dataStatus) => {
|
||||
if (columnsDate.checkStatus.value === 0) {
|
||||
Modal.success({
|
||||
|
|
|
@ -2,13 +2,7 @@
|
|||
<!-- 后台用户 -->
|
||||
<!-- template 内部必须有一个根节点 div,否则<Transition>将会失效,所以这个<a-modal></a-modal> 组件必须放在 根节点 div 里面 -->
|
||||
<div>
|
||||
<TableProMax
|
||||
ref="tableRef"
|
||||
:request-api="reqApi"
|
||||
:columns="columns"
|
||||
:searchFormOptions="searchFormOptions"
|
||||
:scroll="{x}"
|
||||
>
|
||||
<TableProMax ref="tableRef" :request-api="reqApi" :columns="columns" :searchFormOptions="searchFormOptions" :scroll="{ x }">
|
||||
<template #tableHeader>
|
||||
<a-space>
|
||||
<a-button type="primary" @click="addUserManagement">新增用户</a-button>
|
||||
|
@ -17,36 +11,37 @@
|
|||
</TableProMax>
|
||||
<!-- template 内部必须有一个根节点 div,否则<Transition>将会失效,所以这个<a-modal></a-modal> 组件必须放在 根节点 div 里面 -->
|
||||
<a-modal v-model:open="visible" :title="title" @ok="submit" @cancel="closeModal">
|
||||
<FormProMax ref="formRef" v-model:value="formParams" :form-item-options="formItemOptions"/>
|
||||
<FormProMax ref="formRef" v-model:value="formParams" :form-item-options="formItemOptions" />
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import TableProMax from "@/components/table/TableProMax.vue";
|
||||
import {TableProMaxProps} from "@/types/components/table";
|
||||
import {message} from 'ant-design-vue'
|
||||
import {dictSelectNodes} from '@/config/dict.ts'
|
||||
import TableProMax from '@/components/table/TableProMax.vue'
|
||||
import { TableProMaxProps } from '@/types/components/table'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { dictSelectNodes } from '@/config/dict.ts'
|
||||
// const enumsSex = ref<any[]>(dictSelectNodes('Sex'))
|
||||
// const enumsIsEnable = ref<any[]>(dictSelectNodes('IsEnable'))
|
||||
import api from '@/axios/index.ts'
|
||||
import {ref, reactive, onMounted} from 'vue'
|
||||
import FormProMax from "@/components/form/FormProMax.vue";
|
||||
import {FormProMaxItemOptions} from "@/types/components/form";
|
||||
import {FormExpose} from "ant-design-vue/es/form/Form";
|
||||
import {publicUnitPagerQueryParams, FromItem} from "@/types/views/publicUnit.ts";
|
||||
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import FormProMax from '@/components/form/FormProMax.vue'
|
||||
import { FormProMaxItemOptions } from '@/types/components/form'
|
||||
import { FormExpose } from 'ant-design-vue/es/form/Form'
|
||||
import { publicUnitPagerQueryParams, FromItem } from '@/types/views/publicUnit.ts'
|
||||
import { ComponentExposed } from 'vue-component-type-helpers'
|
||||
const tableRef = ref<ComponentExposed<typeof TableProMax>>(null!)
|
||||
const formRef = ref<FormExpose>(null)
|
||||
type TableProps = TableProMaxProps<publicUnitPagerQueryParams>
|
||||
const reqApi: TableProps['requestApi'] = (params) => api.post('/management/police/user/pager', params) //分页
|
||||
const formParams = ref<{
|
||||
snowFlakeId?: string,
|
||||
name: string,
|
||||
sex: number,
|
||||
telephone: string,
|
||||
isEnable: any,
|
||||
// const reqApi: TableProps['requestApi'] = (params) => api.post('/management/police/user/pager', params) //分页
|
||||
const reqApi: TableProps['requestApi'] = (params) => api.post('/m2/user/pager', params) //分页
|
||||
|
||||
const formParams = ref<{
|
||||
snowFlakeId?: string
|
||||
name: string
|
||||
sex: number
|
||||
telephone: string
|
||||
isEnable: any
|
||||
}>({
|
||||
name: '',
|
||||
sex: 0,
|
||||
|
@ -58,9 +53,7 @@ const formItemOptions = ref<FormProMaxItemOptions<FromItem>>({
|
|||
type: 'input',
|
||||
label: '姓名',
|
||||
required: true,
|
||||
rules: [
|
||||
{required: true, message: '请输入姓名'}
|
||||
],
|
||||
rules: [{ required: true, message: '请输入姓名' }],
|
||||
},
|
||||
sex: {
|
||||
type: 'radioGroup',
|
||||
|
@ -73,16 +66,16 @@ const formItemOptions = ref<FormProMaxItemOptions<FromItem>>({
|
|||
label: '手机号',
|
||||
required: true,
|
||||
rules: [
|
||||
{required: true, message: '请输入手机号'},
|
||||
{ required: true, message: '请输入手机号' },
|
||||
{
|
||||
validator: (rule, value) => {
|
||||
const phoneRegex = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/
|
||||
if (!value) {
|
||||
return Promise.reject('手机号不能为空');
|
||||
return Promise.reject('手机号不能为空')
|
||||
} else if (!phoneRegex.test(value)) {
|
||||
return Promise.reject('手机号格式不正确');
|
||||
return Promise.reject('手机号格式不正确')
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve()
|
||||
}
|
||||
},
|
||||
trigger: 'blur',
|
||||
|
@ -101,25 +94,25 @@ const columns: TableProps['columns'] = [
|
|||
dataIndex: 'account',
|
||||
title: '账号',
|
||||
width: 100,
|
||||
ellipsis: true
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'name',
|
||||
title: '名称',
|
||||
width: 200,
|
||||
ellipsis: true
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'sex',
|
||||
title: '性别',
|
||||
customRender: ({text}) => <a-tag>{text?.label}</a-tag>,
|
||||
width: 150
|
||||
customRender: ({ text }) => <a-tag>{text?.label}</a-tag>,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
dataIndex: 'telephone',
|
||||
title: '手机号码',
|
||||
width: 150,
|
||||
ellipsis: true
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
dataIndex: 'createTime',
|
||||
|
@ -131,66 +124,72 @@ const columns: TableProps['columns'] = [
|
|||
{
|
||||
dataIndex: 'isEnable',
|
||||
title: '是否启用',
|
||||
customRender: ({text}) => <a-tag color={text?.extData?.color}>{text?.label}</a-tag>,
|
||||
width: 150
|
||||
customRender: ({ text }) => <a-tag color={text?.extData?.color}>{text?.label}</a-tag>,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
dataIndex: 'opt',
|
||||
title: '操作',
|
||||
fixed: "right",
|
||||
customRender({record}) {
|
||||
return (
|
||||
record.isAdmin.value === 1 ?
|
||||
fixed: 'right',
|
||||
customRender({ record }) {
|
||||
return record.isAdmin.value === 1 ? (
|
||||
<a-space>
|
||||
<a-popconfirm
|
||||
style="width:100%"
|
||||
title="确认删除账号吗?"
|
||||
style='width:100%'
|
||||
title='确认删除账号吗?'
|
||||
onConfirm={async () => {
|
||||
const resp = await api.delete('/management/police/user/deleteById', {
|
||||
{
|
||||
/* const resp = await api.delete('/management/police/user/deleteById', { */
|
||||
}
|
||||
const resp = await api.delete('/m2/user/del_id', {
|
||||
managementPoliceUnitUserId: record.snowFlakeId,
|
||||
})
|
||||
message.success(resp.message)
|
||||
await tableRef.value?.requestGetTableData()
|
||||
}}>
|
||||
<a-button type="primary" danger>删除</a-button>
|
||||
}}
|
||||
>
|
||||
<a-button type='primary' danger>
|
||||
删除
|
||||
</a-button>
|
||||
</a-popconfirm>
|
||||
<a-button type="primary" onClick={async () => {
|
||||
<a-button
|
||||
type='primary'
|
||||
onClick={async () => {
|
||||
visible.value = true
|
||||
title.value = "编辑用户"
|
||||
title.value = '编辑用户'
|
||||
formParams.value.snowFlakeId = record.snowFlakeId
|
||||
formParams.value.name = record.name,
|
||||
formParams.value.sex = record.sex.value,
|
||||
formParams.value.telephone = record.telephone,
|
||||
formParams.value.isEnable = record.isEnable?.value
|
||||
|
||||
}}>
|
||||
;(formParams.value.name = record.name), (formParams.value.sex = record.sex.value), (formParams.value.telephone = record.telephone), (formParams.value.isEnable = record.isEnable?.value)
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</a-button>
|
||||
</a-space>
|
||||
:
|
||||
) : (
|
||||
<div>超级管理员不能编辑</div>
|
||||
)
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
const x: number = columns.reduce((a, b) => a + (b.width as number), 0)
|
||||
const searchFormOptions: TableProps["searchFormOptions"] = {
|
||||
const searchFormOptions: TableProps['searchFormOptions'] = {
|
||||
name: {
|
||||
type: 'input',
|
||||
label: '名称'
|
||||
}, sex: {
|
||||
label: '名称',
|
||||
},
|
||||
sex: {
|
||||
type: 'select',
|
||||
label: '性别',
|
||||
options: [
|
||||
{
|
||||
value: null,
|
||||
label: '全部'
|
||||
}, ...dictSelectNodes('Sex')
|
||||
]
|
||||
label: '全部',
|
||||
},
|
||||
...dictSelectNodes('Sex'),
|
||||
],
|
||||
},
|
||||
telephone: {
|
||||
type: 'input',
|
||||
label: '手机号'
|
||||
label: '手机号',
|
||||
},
|
||||
isEnable: {
|
||||
type: 'select',
|
||||
|
@ -198,10 +197,11 @@ const searchFormOptions: TableProps["searchFormOptions"] = {
|
|||
options: [
|
||||
{
|
||||
value: null,
|
||||
label: '全部'
|
||||
}, ...dictSelectNodes('IsEnable')
|
||||
]
|
||||
}
|
||||
label: '全部',
|
||||
},
|
||||
...dictSelectNodes('IsEnable'),
|
||||
],
|
||||
},
|
||||
}
|
||||
const visible = ref(false)
|
||||
const title = ref('新增用户')
|
||||
|
@ -222,13 +222,13 @@ const submit = async () => {
|
|||
sex: formParams.value.sex,
|
||||
telephone: formParams.value.telephone,
|
||||
isEnable: formParams.value.isEnable,
|
||||
|
||||
}
|
||||
const resp = await api.post('/management/police/user/saveOrUpdate', managementSecurityUnitUserSaveOrUpdateParams)
|
||||
// const resp = await api.post('/management/police/user/saveOrUpdate', managementSecurityUnitUserSaveOrUpdateParams)
|
||||
const resp = await api.post('/m2/user/add_upd', managementSecurityUnitUserSaveOrUpdateParams)
|
||||
|
||||
message.success(resp.message)
|
||||
tableRef.value?.requestGetTableData()
|
||||
closeModal()
|
||||
|
||||
}
|
||||
|
||||
const closeModal = () => {
|
||||
|
@ -236,7 +236,7 @@ const closeModal = () => {
|
|||
name: '',
|
||||
sex: 0,
|
||||
telephone: '',
|
||||
isEnable: 0
|
||||
isEnable: 0,
|
||||
}
|
||||
visible.value = false
|
||||
title.value = '新增用户'
|
||||
|
|
|
@ -1,8 +1,198 @@
|
|||
<template>
|
||||
<div>
|
||||
<!-- 三色预警 -->
|
||||
三色预警
|
||||
<TableProMax ref="tableRef" :request-api="reqApi" :columns="columns">
|
||||
</TableProMax>
|
||||
<div>
|
||||
<a-modal v-model:open="open" :title="title" @ok="open = false" width="80%">
|
||||
<a-table :columns="TableColumns" :data-source="TableData" bordered >
|
||||
<template #bodyCell="{ column, text }">
|
||||
<template v-if="column.dataIndex === 'name'">
|
||||
<div>{{text}}{{column}}</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-modal>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="tsx">
|
||||
import TableProMax from "@/components/table/TableProMax.vue";
|
||||
import api from "@/axios";
|
||||
import {TableProMaxProps} from "@/types/components/table";
|
||||
import {
|
||||
AssessmentRecordPagerQueryParams,
|
||||
AssessmentRecordPagerVo, DeductedDetailRes,
|
||||
} from "@/types/views/assessmentRecord.ts";
|
||||
import {ComponentExposed} from "vue-component-type-helpers";
|
||||
import { ref} from "vue";
|
||||
import {Modal, TableColumnType} from "ant-design-vue";
|
||||
const tableRef = ref<ComponentExposed<typeof TableProMax>>(null!)
|
||||
type TableProps = TableProMaxProps<AssessmentRecordPagerVo,AssessmentRecordPagerQueryParams>
|
||||
|
||||
const open = ref<boolean>(false);
|
||||
const title = ref('扣分项')
|
||||
const reqApi: TableProps['requestApi'] = (params) => api.post('/assessmentRecord/pager', params) //分页
|
||||
const columns: TableProps['columns'] = [
|
||||
{
|
||||
dataIndex: 'enterprisesUnitName',
|
||||
title: '单位名称'
|
||||
}, {
|
||||
dataIndex: 'type',
|
||||
title: '类型',
|
||||
customRender: ({text}) => text?.label
|
||||
}, {
|
||||
dataIndex: 'ckProjectName',
|
||||
title: '考核项目'
|
||||
}, {
|
||||
dataIndex: 'totalScore',
|
||||
title: '总分'
|
||||
}, {
|
||||
dataIndex: 'deductionPointsTotal',
|
||||
title: '扣分',
|
||||
customRender:({record})=>{
|
||||
if (!record.deductionPointsTotal) {
|
||||
return <a-tag color="green">0</a-tag>
|
||||
}
|
||||
return <a-tag class="pointer" color="red" onClick={()=>deductedDetail(record)}>{record.deductionPointsTotal}</a-tag>
|
||||
}
|
||||
}, {
|
||||
dataIndex: 'result',
|
||||
title: '得分',
|
||||
customRender: ({record}) => record.totalScore - record.deductionPointsTotal
|
||||
}, {
|
||||
dataIndex: 'policeUnitName',
|
||||
title: '考核单位'
|
||||
}, {
|
||||
dataIndex: 'createUserName',
|
||||
title: '考核人'
|
||||
}, {
|
||||
dataIndex: 'createTime',
|
||||
title: '考核时间'
|
||||
}, {
|
||||
dataIndex: 'remark',
|
||||
title: '考核备注'
|
||||
}, {
|
||||
dataIndex: 'signature',
|
||||
title: '签字',
|
||||
customRender:({record})=>{
|
||||
return <a-button onClick={()=>{
|
||||
Modal.info({
|
||||
title: `${record.enterprisesUnitName}${record.ckProjectName} 签字结果`,
|
||||
content: () => <>
|
||||
<div>审核人签字: <a-image src={record.assessmentUserSignature}/>
|
||||
</div>
|
||||
<div>被审核单位人员签字: <a-image src={record.byAssessmentEnterprisesUnitUserSignature}/></div>
|
||||
</>
|
||||
})
|
||||
}}>查看</a-button>
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
const TableData = [
|
||||
{
|
||||
key: '1',
|
||||
name: 'John Brown',
|
||||
age: 32,
|
||||
tel: '0571-22098909',
|
||||
phone: 18889898989,
|
||||
address: 'New York No. 1 Lake Park',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: 'Jim Green',
|
||||
tel: '0571-22098333',
|
||||
phone: 18889898888,
|
||||
age: 42,
|
||||
address: 'London No. 1 Lake Park',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: 'Joe Black',
|
||||
age: 32,
|
||||
tel: '0575-22098909',
|
||||
phone: 18900010002,
|
||||
address: 'Sidney No. 1 Lake Park',
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
name: 'Jim Red',
|
||||
age: 18,
|
||||
tel: '0575-22098909',
|
||||
phone: 18900010002,
|
||||
address: 'London No. 2 Lake Park',
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
name: 'Jake White',
|
||||
age: 18,
|
||||
tel: '0575-22098909',
|
||||
phone: 18900010002,
|
||||
address: 'Dublin No. 2 Lake Park',
|
||||
},
|
||||
];
|
||||
const sharedOnCell = (_, index) => {
|
||||
if (index === 4) {
|
||||
return { colSpan: 0 };
|
||||
}
|
||||
};
|
||||
const TableColumns: TableColumnType[] = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
customCell: (_, index) => ({
|
||||
colSpan: index < 4 ? 1 : 5,
|
||||
}),
|
||||
},
|
||||
{
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
customCell: sharedOnCell,
|
||||
},
|
||||
{
|
||||
title: 'Home phone',
|
||||
colSpan: 2,
|
||||
dataIndex: 'tel',
|
||||
customCell: (_, index) => {
|
||||
if (index === 2) {
|
||||
return { rowSpan: 2 };
|
||||
}
|
||||
// These two are merged into above cell
|
||||
if (index === 3) {
|
||||
return { rowSpan: 0 };
|
||||
}
|
||||
if (index === 4) {
|
||||
return { colSpan: 0 };
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Phone',
|
||||
colSpan: 0,
|
||||
dataIndex: 'phone',
|
||||
customCell: sharedOnCell,
|
||||
},
|
||||
{
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
customCell: sharedOnCell,
|
||||
},
|
||||
];
|
||||
const deductedDetail = async (res:any)=>{
|
||||
const {data} = await api.get<DeductedDetailRes[]>('/assessmentRecord/deductedDetail', {assessmentRecordId: res.snowFlakeId})
|
||||
open.value = true
|
||||
console.log(data)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
|
@ -1,20 +1,37 @@
|
|||
// /// <reference types="vite/client" />
|
||||
|
||||
// // vue3导入模块报红解决方案——找不到模块“./XXX.vue”或其相应的类型声明
|
||||
// // 报错原因是:typescript 只能理解 .ts 文件,无法理解 .vue文件
|
||||
// // 因此需要给.vue文件加上类型说明文件
|
||||
// declare module '*.vue' {
|
||||
// import type { DefineComponent } from 'vue'
|
||||
// // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
// const component: DefineComponent<{}, {}, any>
|
||||
// export default component
|
||||
// }
|
||||
|
||||
|
||||
// declare module 'lodash-es' {
|
||||
// import { includes, isEmpty, ceil, divide } from 'lodash';
|
||||
// export { includes, isEmpty, ceil, divide };
|
||||
// }
|
||||
// interface ImportMetaEnv {
|
||||
// // 项目名称
|
||||
// readonly VITE_APP_NAME: string;
|
||||
// // 当前环境
|
||||
// readonly VITE_APP_ENV: 'development' | 'production';
|
||||
// // 启动端口
|
||||
// readonly VITE_APP_PORT: number;
|
||||
|
||||
// // axios
|
||||
// readonly VITE_APP_BASE_API: string;
|
||||
// readonly VITE_APP_PROXY_URL: string;
|
||||
|
||||
// // RSA公钥
|
||||
// readonly VITE_APP_RSA_PUBLIC_KEY: string;
|
||||
// }
|
||||
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
// vue3导入模块报红解决方案——找不到模块“./XXX.vue”或其相应的类型声明
|
||||
// 报错原因是:typescript 只能理解 .ts 文件,无法理解 .vue文件
|
||||
// 因此需要给.vue文件加上类型说明文件
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
|
||||
|
||||
declare module 'lodash-es' {
|
||||
import { includes, isEmpty, ceil, divide } from 'lodash';
|
||||
export { includes, isEmpty, ceil, divide };
|
||||
}
|
||||
interface ImportMetaEnv {
|
||||
// 项目名称
|
||||
readonly VITE_APP_NAME: string;
|
||||
|
@ -22,14 +39,30 @@ interface ImportMetaEnv {
|
|||
readonly VITE_APP_ENV: 'development' | 'production';
|
||||
// 启动端口
|
||||
readonly VITE_APP_PORT: number;
|
||||
// 模块名称
|
||||
readonly VITE_APP_MODULE_NAME: string;
|
||||
|
||||
// axios
|
||||
readonly VITE_APP_BASE_API: string;
|
||||
readonly VITE_APP_PROXY_URL: string;
|
||||
|
||||
// minio
|
||||
readonly VITE_APP_MINIO_URL: string
|
||||
readonly VITE_APP_MINIO_BUCKET: string
|
||||
|
||||
// RSA公钥
|
||||
readonly VITE_APP_RSA_PUBLIC_KEY: string;
|
||||
|
||||
// 高德
|
||||
VITE_APP_GAODE_KEY: string
|
||||
VITE_APP_GAODE_VERSION: string
|
||||
VITE_APP_SECURITY_JS_CODE: string
|
||||
}
|
||||
|
||||
declare module '*.vue' {
|
||||
import { DefineComponent, readonly } from "vue"
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,82 +1,88 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true, // 标记为复合项目的一部分 [ty-reference](1)
|
||||
"target": "ES2020", // 设置目标 JavaScript 语言标准版本
|
||||
"useDefineForClassFields": true, // 为类字段使用 `defineProperty`,以支持装饰器
|
||||
"module": "ESNext", // 设置模块系统
|
||||
"lib": [ // 指定要包含的类型库
|
||||
"ES2020", // 包含 ES2020 的类型定义
|
||||
"DOM", // 包含 DOM 类型定义
|
||||
"DOM.Iterable" // 包含 DOM 可迭代类型定义
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"skipLibCheck": true, // 忽略类型库的类型检查
|
||||
"skipLibCheck": true,
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler", // 设置模块解析策略为 bundler 模式
|
||||
"allowImportingTsExtensions": true, // 允许导入 TypeScript 扩展名
|
||||
"isolatedModules": true, // 将每个文件视为一个模块
|
||||
"moduleDetection": "force", // 强制将所有模块视为 ESM
|
||||
"noEmit": false, // 允许发出文件
|
||||
"declaration": true, // 如果需要生成 .d.ts 文件
|
||||
"emitDeclarationOnly": true, // 只发出声明文件,而不生成 JS 文件
|
||||
"jsx": "preserve", // 保留 JSX 节点,不转换
|
||||
"jsxImportSource": "vue", // JSX 元素来自 Vue
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "vue",
|
||||
/* Linting */
|
||||
"strict": false, // 开启所有严格类型检查选项
|
||||
"noUnusedLocals": true, // 报告未使用的局部变量
|
||||
"noUnusedParameters": true, // 报告未使用的参数
|
||||
"noFallthroughCasesInSwitch": true, // 报告 switch 语句中的 fallthrough 错误
|
||||
"baseUrl": "./", // 设置基础模块解析目录
|
||||
"strict": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"baseUrl": "./",
|
||||
/* 配置别名 */
|
||||
"paths": { // 设置路径映射
|
||||
"@/*": [ // 将 @/ 映射到 src/ 目录
|
||||
"./src/*"
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"allowSyntheticDefaultImports": true // 允许默认导入
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": [ // 指定包含的文件
|
||||
"src/**/*.ts", // 包括 src 目录下的所有 TypeScript 文件
|
||||
"src/**/*.d.ts", // 包括 src 目录下的所有类型声明文件
|
||||
"src/**/*.tsx", // 包括 src 目录下的所有 JSX 文件
|
||||
"src/**/*.vue", // 包括 src 目录下的所有 Vue 文件
|
||||
"global.d.ts"
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue"
|
||||
]
|
||||
}
|
||||
// // 脚手架自带 配置:
|
||||
|
||||
|
||||
|
||||
|
||||
// {
|
||||
// "compilerOptions": {
|
||||
// "target": "ES2020",
|
||||
// "useDefineForClassFields": true,
|
||||
// "module": "ESNext",
|
||||
// "lib": [
|
||||
// "ES2020",
|
||||
// "DOM",
|
||||
// "DOM.Iterable"
|
||||
// "composite": true, // 标记为复合项目的一部分 [ty-reference](1)
|
||||
// "target": "ES2020", // 设置目标 JavaScript 语言标准版本
|
||||
// "useDefineForClassFields": true, // 为类字段使用 `defineProperty`,以支持装饰器
|
||||
// "module": "ESNext", // 设置模块系统
|
||||
// "lib": [ // 指定要包含的类型库
|
||||
// "ES2020", // 包含 ES2020 的类型定义
|
||||
// "DOM", // 包含 DOM 类型定义
|
||||
// "DOM.Iterable" // 包含 DOM 可迭代类型定义
|
||||
// ],
|
||||
// "skipLibCheck": true,
|
||||
// "skipLibCheck": true, // 忽略类型库的类型检查
|
||||
// /* Bundler mode */
|
||||
// "moduleResolution": "bundler",
|
||||
// "allowImportingTsExtensions": true,
|
||||
// "isolatedModules": true,
|
||||
// "moduleDetection": "force",
|
||||
// "noEmit": true,
|
||||
// "jsx": "preserve",
|
||||
// "moduleResolution": "bundler", // 设置模块解析策略为 bundler 模式
|
||||
// "allowImportingTsExtensions": true, // 允许导入 TypeScript 扩展名
|
||||
// "isolatedModules": true, // 将每个文件视为一个模块
|
||||
// "moduleDetection": "force", // 强制将所有模块视为 ESM
|
||||
// "noEmit": false, // 允许发出文件
|
||||
// "declaration": true, // 如果需要生成 .d.ts 文件
|
||||
// "emitDeclarationOnly": true, // 只发出声明文件,而不生成 JS 文件
|
||||
// "jsx": "preserve", // 保留 JSX 节点,不转换
|
||||
// "jsxImportSource": "vue", // JSX 元素来自 Vue
|
||||
// /* Linting */
|
||||
// "strict": true,
|
||||
// "noUnusedLocals": true,
|
||||
// "noUnusedParameters": true,
|
||||
// "noFallthroughCasesInSwitch": true,
|
||||
// "baseUrl": "/",
|
||||
// "strict": false, // 开启所有严格类型检查选项
|
||||
// "noUnusedLocals": true, // 报告未使用的局部变量
|
||||
// "noUnusedParameters": true, // 报告未使用的参数
|
||||
// "noFallthroughCasesInSwitch": true, // 报告 switch 语句中的 fallthrough 错误
|
||||
// "baseUrl": "./", // 设置基础模块解析目录
|
||||
// /* 配置别名 */
|
||||
// "paths": {
|
||||
// "@/*": [
|
||||
// "paths": { // 设置路径映射
|
||||
// "@/*": [ // 将 @/ 映射到 src/ 目录
|
||||
// "./src/*"
|
||||
// ]
|
||||
// },
|
||||
// "allowSyntheticDefaultImports": true // 允许默认导入
|
||||
// },
|
||||
// "include": [
|
||||
// "src/**/*.ts",
|
||||
// "src/**/*.tsx",
|
||||
// "src/**/*.vue"
|
||||
// "include": [ // 指定包含的文件
|
||||
// "src/**/*.ts", // 包括 src 目录下的所有 TypeScript 文件
|
||||
// "src/**/*.d.ts", // 包括 src 目录下的所有类型声明文件
|
||||
// "src/**/*.tsx", // 包括 src 目录下的所有 JSX 文件
|
||||
// "src/**/*.vue", // 包括 src 目录下的所有 Vue 文件
|
||||
// "global.d.ts"
|
||||
// ]
|
||||
// }
|
|
@ -1,40 +1,43 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "/", // 确保相对路径从根目录开始
|
||||
"paths": { // 设置路径映射
|
||||
"@/*": [ // 将 @/ 映射到 src/ 目录
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [], // 可以留空,表示不显式指定任何文件
|
||||
"references": [ // 引用其他 tsconfig 文件
|
||||
{
|
||||
"path": "./tsconfig.app.json" // 引用 tsconfig.app.json
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.node.json" // 引用 tsconfig.node.json
|
||||
}
|
||||
],
|
||||
"include": [ // 指定包含的文件
|
||||
"env.d.ts", // 包括环境类型的声明文件
|
||||
"src/vite-env.d.ts", // 包括 Vite 环境类型的声明文件
|
||||
"src/**/*.ts", // 包括 src 目录下的所有 TypeScript 文件
|
||||
"src/**/*.tsx", // 包括 src 目录下的所有 JSX 文件
|
||||
"src/**/*.vue", // 包括 src 目录下的所有 Vue 文件
|
||||
"global.d.ts", // 确保 global.d.ts 文件被包含
|
||||
"vite.config.ts" // Node 配置文件
|
||||
]
|
||||
}
|
||||
// // 脚手架自带 配置:
|
||||
// {
|
||||
// "files": [],
|
||||
// "references": [
|
||||
// {
|
||||
// "path": "./tsconfig.app.json"
|
||||
// },
|
||||
// {
|
||||
// "path": "./tsconfig.node.json"
|
||||
// }
|
||||
// "compilerOptions": {
|
||||
// "jsx": "react",
|
||||
// "baseUrl": "/", // 确保相对路径从根目录开始
|
||||
// "paths": { // 设置路径映射
|
||||
// "@/*": [ // 将 @/ 映射到 src/ 目录
|
||||
// "./src/*"
|
||||
// ]
|
||||
// }
|
||||
// },
|
||||
// "files": [], // 可以留空,表示不显式指定任何文件
|
||||
// "references": [ // 引用其他 tsconfig 文件
|
||||
// {
|
||||
// "path": "./tsconfig.app.json" // 引用 tsconfig.app.json
|
||||
// },
|
||||
// {
|
||||
// "path": "./tsconfig.node.json" // 引用 tsconfig.node.json
|
||||
// }
|
||||
// ],
|
||||
// "include": [ // 指定包含的文件
|
||||
// "env.d.ts", // 包括环境类型的声明文件
|
||||
// "src/vite-env.d.ts", // 包括 Vite 环境类型的声明文件
|
||||
// "src/**/*.ts", // 包括 src 目录下的所有 TypeScript 文件
|
||||
// "src/**/*.tsx", // 包括 src 目录下的所有 JSX 文件
|
||||
// "src/**/*.vue", // 包括 src 目录下的所有 Vue 文件
|
||||
// "global.d.ts", // 确保 global.d.ts 文件被包含
|
||||
// "vite.config.ts" // Node 配置文件
|
||||
// ]
|
||||
// }
|
||||
|
||||
|
||||
// 脚手架自带 配置:
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,47 +1,47 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"composite": true, // 标记为复合项目的一部分 [ty-reference](1)
|
||||
"target": "ES2022", // 设置目标 JavaScript 语言标准版本
|
||||
"lib": [ // 指定要包含的类型库
|
||||
"ES2023" // 包含 ES2023 的类型定义
|
||||
],
|
||||
"module": "ESNext", // 设置模块系统
|
||||
"skipLibCheck": true, // 忽略类型库的类型检查
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler", // 设置模块解析策略为 bundler 模式
|
||||
"allowImportingTsExtensions": true, // 允许导入 TypeScript 扩展名
|
||||
"isolatedModules": true, // 将每个文件视为一个模块
|
||||
"moduleDetection": "force", // 强制将所有模块视为 ESM
|
||||
"noEmit": false, // 允许发出文件
|
||||
"declaration": true, // 如果需要生成 .d.ts 文件
|
||||
"emitDeclarationOnly": true, // 只发出声明文件,而不生成 JS 文件
|
||||
"strict": true, // 开启所有严格类型检查选项
|
||||
"noUnusedLocals": true, // 报告未使用的局部变量
|
||||
"noUnusedParameters": true, // 报告未使用的参数
|
||||
"noFallthroughCasesInSwitch": true // 报告 switch 语句中的 fallthrough 错误
|
||||
},
|
||||
"include": [ // 指定包含的文件
|
||||
"vite.config.ts" // 包括 Vite 配置文件
|
||||
]
|
||||
}
|
||||
// 脚手架自带 配置:
|
||||
// {
|
||||
// "compilerOptions": {
|
||||
// "target": "ES2022",
|
||||
// "lib": ["ES2023"],
|
||||
// "module": "ESNext",
|
||||
// "skipLibCheck": true,
|
||||
// "composite": true, // 标记为复合项目的一部分 [ty-reference](1)
|
||||
// "target": "ES2022", // 设置目标 JavaScript 语言标准版本
|
||||
// "lib": [ // 指定要包含的类型库
|
||||
// "ES2023" // 包含 ES2023 的类型定义
|
||||
// ],
|
||||
// "module": "ESNext", // 设置模块系统
|
||||
// "skipLibCheck": true, // 忽略类型库的类型检查
|
||||
// /* Bundler mode */
|
||||
// "moduleResolution": "bundler",
|
||||
// "allowImportingTsExtensions": true,
|
||||
// "isolatedModules": true,
|
||||
// "moduleDetection": "force",
|
||||
// "noEmit": true,
|
||||
// /* Linting */
|
||||
// "strict": true,
|
||||
// "noUnusedLocals": true,
|
||||
// "noUnusedParameters": true,
|
||||
// "noFallthroughCasesInSwitch": true
|
||||
// "moduleResolution": "bundler", // 设置模块解析策略为 bundler 模式
|
||||
// "allowImportingTsExtensions": true, // 允许导入 TypeScript 扩展名
|
||||
// "isolatedModules": true, // 将每个文件视为一个模块
|
||||
// "moduleDetection": "force", // 强制将所有模块视为 ESM
|
||||
// "noEmit": false, // 允许发出文件
|
||||
// "declaration": true, // 如果需要生成 .d.ts 文件
|
||||
// "emitDeclarationOnly": true, // 只发出声明文件,而不生成 JS 文件
|
||||
// "strict": true, // 开启所有严格类型检查选项
|
||||
// "noUnusedLocals": true, // 报告未使用的局部变量
|
||||
// "noUnusedParameters": true, // 报告未使用的参数
|
||||
// "noFallthroughCasesInSwitch": true // 报告 switch 语句中的 fallthrough 错误
|
||||
// },
|
||||
// "include": ["vite.config.ts"]
|
||||
// "include": [ // 指定包含的文件
|
||||
// "vite.config.ts" // 包括 Vite 配置文件
|
||||
// ]
|
||||
// }
|
||||
// 脚手架自带 配置:
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
|
@ -14,7 +14,11 @@ export default defineConfig(({ mode }) => {
|
|||
define: {
|
||||
__APP_ENV: JSON.stringify(env)
|
||||
},
|
||||
base: '/',
|
||||
// base: './',
|
||||
base: '/policeManagement/',
|
||||
// base: '/',
|
||||
|
||||
|
||||
plugins: [
|
||||
vue(),
|
||||
vueJsx(),
|
||||
|
@ -45,7 +49,7 @@ export default defineConfig(({ mode }) => {
|
|||
}
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
outDir: 'policeManagement',
|
||||
target: 'modules',
|
||||
chunkSizeWarningLimit: 1500,
|
||||
minify: 'terser',
|
||||
|
|
|
@ -3,3 +3,4 @@ target
|
|||
logs
|
||||
temp
|
||||
HELP.md
|
||||
rebel.xml
|
|
@ -0,0 +1,56 @@
|
|||
pipeline {
|
||||
agent any
|
||||
tools {
|
||||
jdk "jdk-17.0.11"
|
||||
maven "apache-maven-3.8.8"
|
||||
}
|
||||
stages {
|
||||
stage('拉取代码') {
|
||||
steps {
|
||||
echo '开始拉取代码'
|
||||
checkout scmGit(branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[credentialsId: '3', url: 'http://175.6.124.250:3100/luozhun/policeSecurity.git']])
|
||||
echo '代码拉取成功'
|
||||
}
|
||||
}
|
||||
stage('构建后台服务') {
|
||||
steps{
|
||||
echo '开始构建后台服务'
|
||||
sh 'cd /var/jenkins_home/workspace/警保联动后端服务/policeSecurityServer && mvn clean -DskipTests=true package -P prod'
|
||||
echo '后台服务构建完成'
|
||||
}
|
||||
}
|
||||
stage('ssh远程推送代码'){
|
||||
steps{
|
||||
echo '开始推送构建产物'
|
||||
script{
|
||||
def remote = [:]
|
||||
remote.name = 'server-118.253.177.137'
|
||||
remote.host = '118.253.177.137'
|
||||
remote.port = 55555
|
||||
remote.allowAnyHosts = true
|
||||
withCredentials([usernamePassword(credentialsId: '4', passwordVariable: 'password', usernameVariable: 'username')]) {
|
||||
remote.user = "${username}"
|
||||
remote.password = "${password}"
|
||||
}
|
||||
sshCommand remote: remote, command: 'pwd=$(pwd) echo "ssh连接成功!当前工作目录:$(pwd)"'
|
||||
|
||||
sshCommand remote: remote, command: 'echo "停止后台服务..."'
|
||||
sshCommand remote: remote, command: '''docker stop policeSecurityServer'''
|
||||
sshCommand remote: remote, command: 'echo "后台服务已停止..."'
|
||||
|
||||
sshCommand remote: remote, command: 'echo "删除原来的server.jar..."'
|
||||
sshRemove remote: remote, path: '/home/javaProject/policeSecurity/policeSecurityServer.jar'
|
||||
sshCommand remote: remote, command: 'echo "server.jar删除成功!"'
|
||||
|
||||
sshCommand remote: remote, command: 'echo "将构建的server.jar发送到服务器..."'
|
||||
sshPut remote: remote, from: '/var/jenkins_home/workspace/警保联动后端服务/policeSecurityServer/target/policeSecurityServer.jar', into: '/home/javaProject/policeSecurity'
|
||||
sshCommand remote: remote, command: 'echo "server.jar发送成功!"'
|
||||
|
||||
sshCommand remote: remote, command: 'echo "启动后台服务..."'
|
||||
sshCommand remote: remote, command: '''docker start policeSecurityServer'''
|
||||
sshCommand remote: remote, command: 'echo "后台服务启动成功!"'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
<easyexcel.version>3.3.4</easyexcel.version>
|
||||
<mysql.driver.version>8.0.32</mysql.driver.version>
|
||||
<mybatis.plus.version>3.5.7</mybatis.plus.version>
|
||||
<geotools.version>25.2</geotools.version>
|
||||
<druid.version>1.2.20</druid.version>
|
||||
<minio.version>8.4.3</minio.version>
|
||||
<okhttp.version>4.8.1</okhttp.version>
|
||||
|
@ -190,6 +191,17 @@
|
|||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
<version>${mybatis.plus.version}</version>
|
||||
</dependency>
|
||||
<!-- 处理地理空间数据的读取、写入、转换、分析以及可视化 geotools-->
|
||||
<dependency>
|
||||
<groupId>org.geotools</groupId>
|
||||
<artifactId>gt-main</artifactId>
|
||||
<version>${geotools.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.geotools</groupId>
|
||||
<artifactId>gt-geojson</artifactId>
|
||||
<version>${geotools.version}</version>
|
||||
</dependency>
|
||||
<!-- minio对象存储 https://www.minio.org.cn/ -->
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
|
|