项目初始化

This commit is contained in:
BianLzhaoMin 2025-08-19 18:19:48 +08:00
commit d65b48ffe9
100 changed files with 16062 additions and 0 deletions

3
.env.development Normal file
View File

@ -0,0 +1,3 @@
# VITE_API_BASE_URL = http://112.29.103.165:1616
# VITE_API_BASE_URL = /api
VITE_API_BASE_URL = http://192.168.1.123:58080

1
.env.production Normal file
View File

@ -0,0 +1 @@
VITE_API_BASE_URL = http://192.168.1.175:58080

3
.eslintignore Normal file
View File

@ -0,0 +1,3 @@
# eslint检验排除的文件
/public
**/index.js

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
*.local
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

9
.hbuilderx/launch.json Normal file
View File

@ -0,0 +1,9 @@
{
"version" : "1.0",
"configurations" : [
{
"playground" : "standard",
"type" : "uni-app:app-android"
}
]
}

8
.prettierrc.json Normal file
View File

@ -0,0 +1,8 @@
{
"tabWidth": 4,
"singleQuote": true,
"semi": false,
"printWidth": 100,
"trailingComma": "all",
"endOfLine": "auto"
}

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# uni-app-temp
#### 介绍
h5、小程序、app多端兼容 vue3+uView-Plus组件库
#### 软件架构
软件架构说明
#### 安装教程
1. 切换 node 版本 18+
2. npm install
#### 使用说明
1. npm run dev
2. npm run build:h5 //h5打包

53
eslint.config.mjs Normal file
View File

@ -0,0 +1,53 @@
// import globals from "globals";
// import pluginJs from "@eslint/js";
// import pluginVue from "eslint-plugin-vue";
// /** @type {import('eslint').Linter.Config[]} */
// export default [
// {files: ["**/*.{js,mjs,cjs,vue}"]},
// {languageOptions: { globals: {...globals.browser, ...globals.node} }},
// pluginJs.configs.recommended,
// ...pluginVue.configs["flat/essential"],
// ];
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-prettier'],
// 小程序全局变量
globals: {
uni: true,
wx: true,
WechatMiniprogram: true,
getCurrentPages: true,
getApp: true,
UniApp: true,
UniHelper: true,
App: true,
Page: true,
Component: true,
AnyObject: true,
},
parserOptions: {
ecmaVersion: 'latest',
},
rules: {
'prettier/prettier': [
'warn',
{
tabWidth: 4,
singleQuote: true,
semi: false,
printWidth: 100,
trailingComma: 'all',
endOfLine: 'auto',
},
],
'vue/multi-word-component-names': ['off'],
'vue/no-setup-props-destructure': ['off'],
'vue/no-deprecated-html-element-is': ['off'],
'@typescript-eslint/no-unused-vars': ['off'],
},
}

23
index.html Normal file
View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

12820
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

82
package.json Normal file
View File

@ -0,0 +1,82 @@
{
"name": "uni-preset-vue",
"version": "0.0.0",
"scripts": {
"dev:custom": "uni -p",
"dev:h5": "uni",
"dev:h5:ssr": "uni --ssr",
"dev:mp-alipay": "uni -p mp-alipay",
"dev:mp-baidu": "uni -p mp-baidu",
"dev:mp-jd": "uni -p mp-jd",
"dev:mp-kuaishou": "uni -p mp-kuaishou",
"dev:mp-lark": "uni -p mp-lark",
"dev:mp-qq": "uni -p mp-qq",
"dev:mp-toutiao": "uni -p mp-toutiao",
"dev:mp-weixin": "uni -p mp-weixin",
"dev:mp-xhs": "uni -p mp-xhs",
"dev:quickapp-webview": "uni -p quickapp-webview",
"dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
"dev:quickapp-webview-union": "uni -p quickapp-webview-union",
"build:custom": "uni build -p",
"build:h5": "uni build",
"build:h5:ssr": "uni build --ssr",
"build:mp-alipay": "uni build -p mp-alipay",
"build:mp-baidu": "uni build -p mp-baidu",
"build:mp-jd": "uni build -p mp-jd",
"build:mp-kuaishou": "uni build -p mp-kuaishou",
"build:mp-lark": "uni build -p mp-lark",
"build:mp-qq": "uni build -p mp-qq",
"build:mp-toutiao": "uni build -p mp-toutiao",
"build:mp-weixin": "uni build -p mp-weixin",
"build:mp-xhs": "uni build -p mp-xhs",
"build:quickapp-webview": "uni build -p quickapp-webview",
"build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
"build:quickapp-webview-union": "uni build -p quickapp-webview-union"
},
"dependencies": {
"@dcloudio/uni-app": "3.0.0-4050720250324001",
"@dcloudio/uni-app-harmony": "3.0.0-4050720250324001",
"@dcloudio/uni-app-plus": "3.0.0-4050720250324001",
"@dcloudio/uni-components": "3.0.0-4050720250324001",
"@dcloudio/uni-h5": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-alipay": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-baidu": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-jd": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-kuaishou": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-lark": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-qq": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-toutiao": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-weixin": "3.0.0-4050720250324001",
"@dcloudio/uni-mp-xhs": "3.0.0-4050720250324001",
"@dcloudio/uni-quickapp-webview": "3.0.0-4050720250324001",
"clipboard": "^2.0.11",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.13",
"lodash-es": "^4.17.21",
"pinia": "^2.3.0",
"pinia-plugin-persistedstate": "^4.2.0",
"uview-plus": "^3.4.65",
"vue": "3.5.13",
"vue-i18n": "9.14.3"
},
"devDependencies": {
"@dcloudio/types": "3.4.14",
"@dcloudio/uni-automator": "3.0.0-4050720250324001",
"@dcloudio/uni-cli-shared": "3.0.0-4050720250324001",
"@dcloudio/uni-stacktracey": "3.0.0-4050720250324001",
"@dcloudio/vite-plugin-uni": "3.0.0-4050720250324001",
"@eslint/js": "^9.17.0",
"@vue/runtime-core": "3.5.13",
"eslint": "^9.17.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-vue": "^9.32.0",
"globals": "^15.14.0",
"prettier": "^3.4.2",
"sass": "^1.63.2",
"sass-loader": "^10.4.1",
"vite": "5.2.8",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-remove-console": "^2.2.0"
}
}

28
project.config.json Normal file
View File

@ -0,0 +1,28 @@
{
"appid": "wxac5c134e590200bf",
"compileType": "miniprogram",
"libVersion": "3.7.4",
"packOptions": {
"ignore": [],
"include": []
},
"setting": {
"coverView": true,
"es6": true,
"postcss": true,
"minified": true,
"enhance": true,
"showShadowRootInWxmlPanel": true,
"packNpmRelationList": [],
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
}
},
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
}
}

View File

@ -0,0 +1,7 @@
{
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "my-vue3-project",
"setting": {
"compileHotReLoad": true
}
}

10
shims-uni.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
/// <reference types='@dcloudio/types' />
import 'vue'
declare module '@vue/runtime-core' {
type Hooks = App.AppInstance & Page.PageInstance;
interface ComponentCustomOptions extends Hooks {
}
}

28
src/App.vue Normal file
View File

@ -0,0 +1,28 @@
<script>
export default {
onLaunch: function () {
console.log('App Launch')
},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
},
}
</script>
<style lang="scss">
/* 注意要写在第一行同时给style标签加入lang="scss"属性 */
@import 'uview-plus/index.scss';
page {
height: 100%;
width: 100%;
}
::v-deep .u-form-item__body__right__message {
margin-left: 0 !important;
}
</style>

View File

@ -0,0 +1,63 @@
<template>
<!-- 导航栏 -->
<up-navbar :title="navBarTitle">
<template #left>
<view class="u-nav-slot" @tap="onHandleBack">
<up-icon name="arrow-left" size="20" color="#2979ff" />
返回
</view>
</template>
<template #right v-if="showUploadRecord">
<text style="color: #2979ff" @tap="onHandleUploadRecord">上传记录</text>
</template>
</up-navbar>
</template>
<script setup>
const props = defineProps({
//
navBarTitle: {
type: String,
default: () => '个人中心',
},
//
showUploadRecord: {
type: Boolean,
default: () => false,
},
// url
uploadRecordUrl: {
type: String,
default: () => '',
},
})
//
const onHandleBack = () => {
uni.navigateBack({
delta: 1,
})
}
//
const onHandleUploadRecord = () => {
uni.navigateTo({
url: props.uploadRecordUrl,
})
}
</script>
<style scoped>
.u-nav-slot {
display: flex;
align-items: center;
color: #2979ff;
}
::v-deep .u-navbar__content__title {
font-weight: bold;
}
</style>

View File

@ -0,0 +1,44 @@
<template>
<!-- 表单头部提示文字 -->
<view class="title-tip">
<view></view>
<view>{{ TitleTip }}</view>
</view>
</template>
<script setup>
const props = defineProps({
TitleTip: {
type: String,
default: () => '',
},
})
//
const onHandleBack = () => {
uni.navigateBack({
delta: 1,
})
}
</script>
<style scoped lang="scss">
.title-tip {
padding: 16rpx 0;
display: flex;
align-items: center;
color: #585757;
font-weight: bold;
font-size: 14px;
letter-spacing: 2rpx;
background-color: #fff;
& view:first-child {
margin: 0 20rpx;
width: 10rpx;
height: 32rpx;
background-color: #2979ff;
border-radius: 2rpx;
}
}
</style>

1
src/hooks/useCommon.js Normal file
View File

@ -0,0 +1 @@

12
src/main.js Normal file
View File

@ -0,0 +1,12 @@
import { createSSRApp } from 'vue'
import App from './App.vue'
import pinia from './stores/index'
import uviewPlus from 'uview-plus'
export function createApp() {
const app = createSSRApp(App)
app.use(uviewPlus)
app.use(pinia)
return {
app,
}
}

153
src/manifest.json Normal file
View File

@ -0,0 +1,153 @@
{
"name" : "AR水运",
"appid" : "__UNI__0A021AF",
"description" : "AR水运",
"versionName" : "1.0.0",
"versionCode" : 100,
"transformPx" : false,
/* 5+App */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"compatible" : {
"ignoreVersion" : true //trueHBuilderX1.9.0
},
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* */
"modules" : {
"Barcode" : {},
"Camera" : {}
},
/* */
"distribute" : {
/* android */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
"<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>",
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
"<uses-permission android:name=\"android.permission.INTERNET\"/>"
],
"minSdkVersion" : 24,
"abiFilters" : [ "armeabi-v7a" ]
},
"webview" : {
"allowFileAccess" : true,
"allowUniversalAccessFromFileURLs" : true
},
/* ios */
"ios" : {
"permissions" : {
"WRITE_EXTERNAL_STORAGE" : {
"description" : "允许应用保存文件到外部存储",
"permission" : "YES"
},
"READ_EXTERNAL_STORAGE" : {
"description" : "允许应用从外部存储读取文件",
"permission" : "YES"
}
},
"urlschemewhitelist" : [ "baidumap", "iosamap" ],
"dSYMs" : false,
"privacyDescription" : {
"NSAppleMusicUsageDescription" : "该应用需要访问您的媒体资料,以便为您编辑个人信息",
"NSPhotoLibraryUsageDescription" : "该应用需要读取您的相册,以便为您编辑个人信息,更新头像设置",
"NSPhotoLibraryAddUsageDescription" : "该应用需要读取您的相册,以便为您编辑个人信息,更新头像设置",
"NSCameraUsageDescription" : "该应用需要您的相机,以便您拍摄上传个人信息,更新头像设置,验证是否为本人",
"NSMicrophoneUsageDescription" : "",
"NSLocationWhenInUseUsageDescription" : "该应用需要您的位置信息,以便为您编辑个人信息",
"NSLocationAlwaysUsageDescription" : "该应用需要您的位置信息,以便为您编辑个人信息",
"NSLocationAlwaysAndWhenInUseUsageDescription" : "该应用需要您的位置信息,以便为您编辑个人信息",
"NSCalendarsUsageDescription" : "该应用需要您的日历,以便为您编辑个人信息",
"NSContactsUsageDescription" : "",
"NSLocalNetworkUsageDescription" : "该应用需要您的网络,以便为您编辑个人信息"
},
"idfa" : false
},
/* SDK */
"sdkConfigs" : {
"maps" : {}
},
"icons" : {
"android" : {
"hdpi" : "unpackage/res/icons/72x72.png",
"xhdpi" : "unpackage/res/icons/96x96.png",
"xxhdpi" : "unpackage/res/icons/144x144.png",
"xxxhdpi" : "unpackage/res/icons/192x192.png"
},
"ios" : {
"appstore" : "unpackage/res/icons/1024x1024.png",
"ipad" : {
"app" : "unpackage/res/icons/76x76.png",
"app@2x" : "unpackage/res/icons/152x152.png",
"notification" : "unpackage/res/icons/20x20.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"proapp@2x" : "unpackage/res/icons/167x167.png",
"settings" : "unpackage/res/icons/29x29.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"spotlight" : "unpackage/res/icons/40x40.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png"
},
"iphone" : {
"app@2x" : "unpackage/res/icons/120x120.png",
"app@3x" : "unpackage/res/icons/180x180.png",
"notification@2x" : "unpackage/res/icons/40x40.png",
"notification@3x" : "unpackage/res/icons/60x60.png",
"settings@2x" : "unpackage/res/icons/58x58.png",
"settings@3x" : "unpackage/res/icons/87x87.png",
"spotlight@2x" : "unpackage/res/icons/80x80.png",
"spotlight@3x" : "unpackage/res/icons/120x120.png"
}
}
}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true,
"mergeVirtualHostAttributes" : true
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true,
"mergeVirtualHostAttributes" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "3",
"h5" : {
"title" : ""
}
}

78
src/pages.json Normal file
View File

@ -0,0 +1,78 @@
{
"easycom": {
"autoscan": true,
// customhttps://ask.dcloud.net.cn/question/131175
"custom": {
"^u--(.*)": "uview-plus/components/u-$1/u-$1.vue",
"^up-(.*)": "uview-plus/components/u-$1/u-$1.vue",
"^u-([^-].*)": "uview-plus/components/u-$1/u-$1.vue"
}
},
"pages": [
// pageshttps://uniapp.dcloud.io/collocation/pages
//
{
"path": "pages/login/index",
"style": {
"navigationBarTitleText": "custom",
"navigationStyle": "custom"
}
},
//
{
"path": "pages/projectSelect/index",
"style": {
"navigationBarTitleText": "项目选择",
"navigationStyle": "custom" //
}
},
// Home
{
"path": "pages/workHome/index",
"style": {
"navigationBarTitleText": "custom",
"navigationStyle": "custom" //
}
},
//
{
"path": "pages/mapNav/index",
"style": {
"navigationBarTitleText": "custom",
"navigationStyle": "custom" //
}
},
// AR
{
"path": "pages/arCheck/index",
"style": {
"navigationBarTitleText": "custom",
"navigationStyle": "custom" //
}
},
//
{
"path": "pages/siteSurvey/index",
"style": {
"navigationBarTitleText": "custom",
"navigationStyle": "custom" //
}
},
//
{
"path": "pages/siteSurvey/addOrEditForm",
"style": {
"navigationBarTitleText": "custom",
"navigationStyle": "custom" //
}
}
],
"globalStyle": {
"navigationBarTextStyle": "#333",
"navigationBarTitleText": "AR水运",
"navigationBarBackgroundColor": "#F5F4F5",
"backgroundColor": "#F5F4F5"
}
}

139
src/pages/arCheck/index.vue Normal file
View File

@ -0,0 +1,139 @@
<template>
<!-- AR检查 -->
<view class="ar-check-container">
<!-- 底部操作栏 -->
<!-- <view class="handel-bar">
<view>
<up-image
:src="cameraIcon"
mode="aspectFit"
width="26"
height="26"
@click="takePhoto"
/>
</view>
<view>检查反馈</view>
<view>
<up-image
:src="videoIcon"
mode="aspectFit"
width="26"
height="26"
@click="startRecord"
/>
</view>
</view>
<view class="debug-btn" @click="debug">调试模型</view> -->
<view style="padding: 30px; color: aquamarine;">
返回的数据{{resultInfo}}
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { onLoad, onUnload } from '@dcloudio/uni-app'
import { getModelDetailApi } from '@/services/model'
import videoIcon from '@/static/image/video.png' //
import cameraIcon from '@/static/image/camera.png' //
const info = ref('')
const resultInfo = ref('这是测试回显的东西')
onLoad(async (options) => {
const modelId = options?.modelId
const res = await getModelDetailApi({ id: modelId })
if (res.code === 200) {
const ctx = uni.requireNativePlugin('bonus-textodule')
ctx.openNativePage(
{
modelInfoList: res.data,
},
(result) => {
resultInfo.value = JSON.stringify(result)
//
// uni.showToast({
// title: JSON.stringify(result),
// icon: 'none',
// duration: 10000,
// })
// setTimeout(() => {
// uni.navigateTo({
// url: '/pages/siteSurvey/addOrEditForm',
// })
// }, 500)
},
)
} else {
uni.$u.toast('模型数据获取失败!')
setTimeout(() => {
uni.navigateBack({
delta: 1,
})
}, 500)
}
})
</script>
<style lang="scss" scoped>
.ar-check-container {
width: 100%;
height: 100%;
// background: url('@/static/image/login_bg_new.png') no-repeat center center;
// background-size: cover;
// position: relative;
.stacking-modal {
position: absolute;
top: 20rpx;
right: 20rpx;
width: 100rpx;
height: 100rpx;
background: rgba(255, 255, 255, 0.9);
border-radius: 10rpx;
}
.handel-bar {
position: absolute;
bottom: 20rpx;
left: 0;
width: 100%;
display: flex;
justify-content: center;
view {
width: 68px;
height: 68px;
border-radius: 50%;
background-color: #165dff;
display: flex;
align-items: center;
justify-content: center;
}
& view:nth-child(2) {
margin: 0 12rpx;
font-size: 12px;
color: #fff;
}
}
.debug-btn {
position: absolute;
top: 20rpx;
right: 50%;
width: 100rpx;
height: 100rpx;
background: rgba(255, 255, 255, 0.9);
border-radius: 10rpx;
text-align: center;
line-height: 100rpx;
}
}
</style>

328
src/pages/login/index.vue Normal file
View File

@ -0,0 +1,328 @@
<template>
<!-- 登录页面 -->
<view class="login-container">
<!-- 表单 -->
<view class="login-form-container">
<view class="login-form-title"> 欢迎登录 </view>
<up-form
labelWidth="auto"
ref="loginModelRef"
:model="opinionModel"
:rules="opinionRules"
class="opinion-form"
>
<up-row>
<up-col span="12">
<up-form-item prop="username">
<up-input
clearable
prefixIcon="account"
placeholder="填输入用户名"
v-model="opinionModel.username"
/>
</up-form-item>
</up-col>
</up-row>
<up-row>
<up-col span="12">
<up-form-item prop="password">
<up-input
clearable
prefixIcon="lock"
placeholder="填输入密码"
:password="!showPassword"
v-model="opinionModel.password"
>
<template #suffix>
<u-icon
size="20"
@tap="showPassword = !showPassword"
:name="!showPassword ? 'eye-fill' : 'eye'"
/>
</template>
</up-input>
</up-form-item>
</up-col>
</up-row>
<up-row>
<up-col span="9">
<up-form-item prop="code">
<up-input
class="code-input-ref"
clearable
prefixIcon="email"
placeholder="填输入右侧验证码"
v-model="opinionModel.code"
/>
</up-form-item>
</up-col>
<up-col span="3">
<!-- <up-form-item prop="username">
</up-form-item> -->
<view class="code-img-ref">
<up-image
:src="codeUrl"
:show-loading="true"
:width="imgWidth + 'px'"
:height="imgHeight + 'px'"
@click="onHandleCodeImg"
mode="aspectFill"
/>
</view>
</up-col>
</up-row>
<up-form-item prop="remember">
<up-checkbox
usedAlone
name="agree"
label="记住密码"
v-model:checked="opinionModel.remember"
>
</up-checkbox>
</up-form-item>
<up-form-item>
<up-button type="primary" text="登录" @tap="onSubmitLogin" />
</up-form-item>
</up-form>
</view>
<up-loading-page
color="#333"
fontSize="16"
loadingColor="#2979ff"
:loading="sendLoading"
bg-color="rgba(0,0,0,0.5)"
loading-text="正在登录..."
/>
</view>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { debounce } from 'lodash-es' //
import { useMemberStore } from '@/stores'
import { loginApi, getUserInfoApi, getCodeImgApi } from '@/services/login.js'
import { onLoad } from '@dcloudio/uni-app'
const showPassword = ref(false) //
const sendLoading = ref(false) //
const memberStore = useMemberStore() //
const codeImgRef = ref(null)
const imgWidth = ref(0)
const imgHeight = ref(0)
const codeUrl = ref('')
const captchaEnabled = ref(false)
//
const opinionModel = ref({
username: '',
password: '',
code: '',
remember: false,
uuid: '',
// username: '!Admin',
// password: 'Bonus@admin123',
})
const opinionRules = ref({
username: [
{
type: 'string',
required: true,
message: '请填写用户名',
trigger: ['blur', 'change'],
},
// {
// pattern: /^(1\d{10}|!Admin)$/,
// //
// transform(value) {
// return String(value)
// },
// message: '',
// },
],
password: [
{
type: 'string',
required: true,
message: '请填写登录密码',
trigger: ['blur', 'change'],
},
],
})
//
const loginModelRef = ref(null)
//
const onHandleCodeImg = async () => {
const res = await getCodeImgApi()
captchaEnabled.value = res.captchaEnabled ? true : res.captchaEnabled
codeUrl.value = 'data:image/gif;base64,' + res.img
opinionModel.value.uuid = res.uuid
console.log('codeUrl.value', codeUrl.value)
}
//
const onSubmitLogin = debounce(() => {
//
sendLoading.value = true
loginModelRef.value
.validate()
.then(async (valid) => {
if (valid) {
try {
console.log(
'%c🔍 登录请求入参 %c',
'background: linear-gradient(90deg, #FF6B6B, #4ECDC4); color: white; padding: 5px 10px; border-radius: 5px; font-weight: bold;',
'',
opinionModel.value,
)
const res = await loginApi(opinionModel.value)
console.log(
'%c🔍 登录请求出参 %c',
'background: linear-gradient(90deg, #FF6B6B, #4ECDC4); color: white; padding: 5px 10px; border-radius: 5px; font-weight: bold;',
'',
res,
)
sendLoading.value = false
if (res.code === 200) {
memberStore.setToken(res.token)
console.log(opinionModel.value.remember, 'opinionModel.value.remember')
if (opinionModel.value.remember) {
const encryptedPwd = btoa(opinionModel.value.password)
uni.setStorageSync('userInfo', {
username: opinionModel.value.username,
password: encryptedPwd,
})
} else {
const userInfo = uni.getStorageSync('userInfo')
if (userInfo) {
uni.removeStorage('userInfo')
uni.removeStorageSync('userInfo')
}
}
// getUserInfo()
uni.$u.toast('登录成功')
setTimeout(() => {
// uni.switchTab({ url: '/pages/workbenches/index' })
uni.navigateTo({ url: '/pages/projectSelect/index' })
}, 500)
} else {
sendLoading.value = false
uni.$u.toast('登录失败' + res.message)
onHandleCodeImg()
}
} catch (error) {
sendLoading.value = false
}
}
})
.catch(() => {
//
sendLoading.value = false
})
// uni.$u.toast('')
// setTimeout(() => {
// uni.navigateTo({ url: '/pages/projectSelect/index' })
// }, 500)
}, 500)
//
const getUserInfo = () => {
getUserInfoApi().then((res) => {
if (res.code === 200) {
console.log(
'%c🔍 用户信息请求出参 %c',
'background: linear-gradient(90deg, #FF6B6B, #4ECDC4); color: white; padding: 5px 10px; border-radius: 5px; font-weight: bold;',
'',
res,
)
//
memberStore.setUserInfo(res.data)
uni.$u.toast('登录成功')
setTimeout(() => {
// uni.switchTab({ url: '/pages/workbenches/index' })
uni.navigateTo({ url: '/pages/projectSelect/index' })
}, 500)
}
})
}
onLoad(() => {
const userInfo = uni.getStorageSync('userInfo')
if (userInfo) {
opinionModel.value.username = userInfo.username
opinionModel.value.password = atob(userInfo.password)
opinionModel.value.remember = true
}
})
onHandleCodeImg()
onMounted(() => {
uni.createSelectorQuery()
.select('.code-img-ref') // 使
.boundingClientRect((rect) => {
if (rect) {
console.log('宽度:', rect.width)
imgWidth.value = rect.width
}
})
.exec()
uni.createSelectorQuery()
.select('.code-input-ref') // 使
.boundingClientRect((rect) => {
if (rect) {
console.log('高度:', rect.height)
imgHeight.value = rect.height
}
})
.exec()
})
</script>
<style lang="scss" scoped>
.login-container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: url('@/static/image/login_bg_new.png') no-repeat center center;
background-size: cover;
.login-form-container {
width: 40%;
background: rgba(255, 255, 255, 0.7);
border-radius: 10rpx;
padding: 20rpx;
}
.login-form-title {
font-size: 20px;
font-weight: bold;
margin-bottom: 6rpx;
letter-spacing: 2rpx;
}
}
.uni-input-placeholder {
color: #393a3a;
}
.u-border,
.up-border {
border-color: #777d8e !important;
}
</style>

View File

@ -0,0 +1,20 @@
<!-- 在你的 Vue 组件中 -->
<template>
<view class="container">
<web-view ref="baiduMap" :src="webViewUrl"></web-view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
const baiduMap = ref(null)
const webViewUrl = ref('')
onLoad((options) => {
console.log(options)
const projectInfo = JSON.parse(options?.projectInfo)
webViewUrl.value = `/static/map.html?lat=${projectInfo.latitude}&lng=${projectInfo.longitude}&proName=${projectInfo.proName}&chargePerson=${projectInfo.chargePerson}&location=${projectInfo.location}`
})
</script>

View File

@ -0,0 +1,202 @@
<template>
<!-- 项目选择 -->
<up-navbar
title="项目选择"
:leftIconSize="0"
:titleStyle="{ color: '#333', fontWeight: 'bold' }"
/>
<!-- 查询 -->
<view class="project-select-container" :style="{ paddingTop: safeAreaInsets?.top + 44 + 'px' }">
<up-row :gutter="10" class="project-select-row">
<up-col span="3">
<up-input placeholder="项目名称" border="surround" v-model="queryParams.proName" />
</up-col>
<!-- <up-col span="3">
<up-input placeholder="项目类型" border="surround" v-model="queryParams.proType" />
</up-col>
<up-col span="3">
<up-input
border="surround"
placeholder="项目经理"
v-model="queryParams.proManager"
/>
</up-col> -->
<up-col span="3">
<view class="project-select-button-box">
<up-button type="primary" text="查询" @click="onHandleSearch" />
<up-button
type="primary"
:plain="true"
:hairline="true"
text="重置"
@click="onHandleReset"
/>
</view>
</up-col>
</up-row>
<!-- 表格 -->
<view class="project-select-table-box">
<!-- 表头 -->
<up-row class="table-th">
<up-col class="table-td" span="1"> 序号 </up-col>
<up-col class="table-td" span="2.5"> 项目名称 </up-col>
<up-col class="table-td" span="2.5"> 项目层级 </up-col>
<up-col class="table-td" span="2.5"> 项目经理 </up-col>
<up-col class="table-td" span="4.5"> 项目所在地 </up-col>
</up-row>
<!-- 表格内容 -->
<up-row
:key="index"
class="table-tbody"
v-for="(item, index) in projectList"
@tap="onHandleSelectProject(item)"
:style="{
borderBottom: index !== projectList.length - 1 ? '1px solid #f7f8fa' : 'none',
}"
>
<up-col class="table-td" span="1"> {{ index + 1 }} </up-col>
<up-col class="table-td" span="2.5"> {{ item.proName }} </up-col>
<up-col class="table-td" span="2.5"> {{ item.level }} </up-col>
<up-col class="table-td" span="2.5"> {{ item.manager }} </up-col>
<up-col class="table-td" span="4.5"> {{ item.location }} </up-col>
</up-row>
</view>
<!-- 分页 -->
<view class="pagination-box">
<u-pagination
:total="total"
:current-page="queryParams.pageNum"
layout="prev, pager, next"
:page-size="queryParams.pageSize"
@current-change="onHandleCurrentChange"
/>
</view>
</view>
</template>
<script setup>
import { ref, onMounted, reactive } from 'vue'
import { getProjectListApi } from '@/services/projectSelect'
import js from '@eslint/js'
const { safeAreaInsets } = uni.getSystemInfoSync()
const projectList = ref([
// { proId: 1, proName: '1', level: '', manager: '', location: '' },
// { proId: 2, proName: '2', level: '', manager: '', location: '' },
// { proId: 3, proName: '3', level: '', manager: '', location: '广' },
// { proId: 4, proName: '4', level: '', manager: '', location: '' },
// { proId: 5, proName: '5', level: '', manager: '', location: '' },
// { proId: 6, proName: '6', level: '', manager: '', location: '' },
// { proId: 7, proName: '7', level: '', manager: '', location: '西' },
])
const total = ref(100)
//
const queryParams = ref({
proName: '', //
// proType: '', //
// proManager: '', //
pageNum: 1, //
pageSize: 10, //
})
//
const getProjectList = async () => {
const res = await getProjectListApi(queryParams.value)
projectList.value = res?.rows
total.value = res?.total
}
//
const onHandleSearch = () => {
getProjectList()
}
//
const onHandleReset = () => {
queryParams.value = {
proName: '',
// proType: '',
// proManager: '',
pageNum: 1,
pageSize: 10,
}
getProjectList()
}
//
const onHandleCurrentChange = (page) => {
// console.log(page,'')
queryParams.value.pageNum = page
getProjectList()
}
//
const onHandleSelectProject = (item) => {
// console.log('', item)
// const { id, projectName } = item
// uni.navigateTo({
// url: `/pages/projectSelect/projectSelectDetail?id=${id}&projectName=${projectName}`,
// })
const projectInfo = JSON.stringify(item)
uni.navigateTo({
url: `/pages/workHome/index?proId=${item.proId}&projectName=${item.proName}&projectInfo=${projectInfo}`,
})
}
onMounted(() => {
getProjectList()
})
</script>
<style lang="scss" scoped>
.project-select-container {
height: 100%;
background-color: #f7f8fa;
box-sizing: border-box;
padding-bottom: 20rpx;
.project-select-row,
.project-select-table-box {
background-color: #fff;
margin-top: 20rpx;
padding: 20rpx;
}
.project-select-button-box {
display: flex;
align-items: center;
gap: 10rpx;
}
.table-td {
text-align: center !important;
}
.table-th {
padding: 20rpx 0;
background-color: #f7f8fa;
}
.table-tbody {
padding: 20rpx 0;
}
.table-tbody:hover {
background-color: #f7f8fa;
}
.pagination-box {
margin-top: 20rpx;
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@ -0,0 +1,454 @@
<template>
<!-- 现场勘察 填报 -->
<view class="site-survey-container">
<!-- 项目名称 -->
<up-navbar :title="projectName" bgColor="#fff" @leftClick="onHandleLeftClick"> </up-navbar>
<!-- 查询 -->
<view
class="site-survey-container"
:style="{ paddingTop: safeAreaInsets?.top + 44 + 'px' }"
>
<up-form
labelWidth="auto"
ref="addOrEditFormModelRef"
:model="addOrEditFormModel"
:rules="addOrEditFormRules"
labelPosition="top"
>
<up-row justify="space-between" gutter="10">
<up-col span="5.5">
<up-form-item prop="projectName" label="项目名称">
<up-input
clearable
disabled
placeholder="填输入勘察项目名称"
v-model="addOrEditFormModel.projectName"
/>
</up-form-item>
</up-col>
<up-col span="5.5">
<up-form-item prop="surveyUser" label="勘察人">
<up-input
clearable
placeholder="填输入勘察人"
v-model="addOrEditFormModel.surveyUser"
/>
</up-form-item>
</up-col>
</up-row>
<up-row justify="space-between" gutter="10">
<up-col span="5.5">
<up-form-item name="surveyTime" label="勘察时间" required>
<!-- <up-input
clearable
placeholder="填输入勘察项目名称"
v-model="addOrEditFormModel.proName"
/> -->
<up-datetime-picker
hasInput
placeholder="请选择日期"
mode="date"
:inputProps="{
border: 'surround',
shape: 'square',
inputAlign: 'center',
suffixIcon: 'calendar',
}"
v-model="addOrEditFormModel.date"
>
</up-datetime-picker>
</up-form-item>
</up-col>
<up-col span="5.5">
<up-form-item prop="surveyContent" label="勘察内容" required>
<up-input
clearable
placeholder="填输入勘察人"
v-model="addOrEditFormModel.surveyContent"
/>
</up-form-item>
</up-col>
</up-row>
<up-row justify="space-between" gutter="10">
<up-col span="5.5">
<up-form-item prop="modelId" label="模型">
<!-- <up-input
clearable
placeholder="填输入勘察项目名称"
v-model="addOrEditFormModel.modelId"
/> -->
<up-picker
:hasInput="true"
title="请选择模型"
:show="showPickerSelectModel"
:columns="modelColumns"
@confirm="onConfirmSelectModel"
@cancel="showPickerSelectModel = false"
keyName="nodeName"
valueName="id"
:inputProps="{
shape: 'square',
inputAlign: 'center',
suffixIcon: 'arrow-down',
value: addOrEditFormModel.modelName,
placeholder: '请选择模型',
}"
v-model="addOrEditFormModel.modelId"
style="width: 100%"
></up-picker>
</up-form-item>
</up-col>
</up-row>
<up-row justify="space-between" gutter="10">
<up-col span="5.5">
<up-form-item prop="surveyResult" label="勘察结果" required>
<up-textarea
v-model="addOrEditFormModel.surveyResult"
placeholder="请输勘察结果"
autoHeight
/>
</up-form-item>
</up-col>
</up-row>
<up-row justify="space-between" gutter="10">
<up-col span="5.5">
<up-form-item prop="fileList" label="勘察附件" required>
<!-- <up-input
clearable
placeholder="填输入勘察项目名称"
v-model="addOrEditFormModel.proName"
/> -->
<!-- <up-button type="primary" text="上传附件" size="small" /> -->
<view
:key="index"
class="file-list-show"
v-for="(item, index) in addOrEditFormModel.fileList"
>
附件 {{ index + 1 }}
<!-- 右上角删除按钮 -->
<up-icon
size="22"
color="#333"
class="delete-icon"
name="close-circle-fill"
@click="onHandleDelete(index)"
/>
</view>
<view
class="upload-box"
@click="onHandleUpload"
v-if="addOrEditFormModel.fileList.length < 6"
>
<up-icon name="camera-fill" size="26" color="#d3d4d6" />
</view>
</up-form-item>
</up-col>
</up-row>
<up-row justify="flex-end" gutter="10">
<up-col span="1">
<up-form-item>
<up-button text="取消" size="small" />
</up-form-item>
</up-col>
<up-col span="1">
<up-form-item>
<up-button
type="primary"
text="确认"
size="small"
@click="onHandleSubmit"
/>
</up-form-item>
</up-col>
</up-row>
</up-form>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { addSurveyDataApi, getSurveyDataDetailApi, editSurveyDataApi } from '@/services/survey.js'
import { getModelListApi } from '@/services/model.js'
import dayjs from 'dayjs'
const { safeAreaInsets } = uni.getSystemInfoSync()
const projectName = ref('')
const addOrEditFormModelRef = ref(null)
const showPickerSelectModel = ref(false)
const modelColumns = ref([])
const addOrEditFormModel = ref({
projectName: '', //
proId: '', // ID
surveyUser: '', //
date: Date.now(), //
surveyTime: '', //
surveyContent: '', //
modelId: [], // id
surveyResult: '', //
surveyAttach: '', //
modelName: '', //
fileList: [],
})
const addOrEditFormRules = ref({
date: [
{ type: 'string', required: true, message: '请选择勘察日期', trigger: ['blur', 'change'] },
],
surveyContent: [
{ type: 'string', required: true, message: '请输入勘察内容', trigger: ['blur', 'change'] },
],
surveyResult: [
{ type: 'string', required: true, message: '请输入勘察结果', trigger: ['blur', 'change'] },
],
// fileList: [
// { type: 'string', required: true, message: '', trigger: ['blur', 'change'] },
// ],
})
//
const onHandleLeftClick = () => {
uni.navigateBack({
delta: 1,
})
}
//
const onHandleUpload = () => {
// #ifdef H5
uni.chooseFile({
count: 6, //
// type: 'all', // 'all''image''video''file'H5
extension: ['.doc', '.docx', '.pdf', '.xls', '.xlsx'], // H5App
success: (res) => {
const tempFilePaths = res.tempFiles[0].path //
uni.uploadFile({
url: '/common/uploadFile',
filePath: tempFilePaths,
name: 'file',
formData: {
file: 'file',
},
success: (res) => {
const result = JSON.parse(res.data)
if (result.code === 200) {
addOrEditFormModel.value.fileList.push(result.data)
}
},
fail: (err) => {
console.error('上传失败', err)
},
})
},
fail: (err) => {
console.error('选择文件失败', err)
},
})
// #endif
// #ifdef APP-PLUS
plus.io.chooseFile(
{
title: '选择附件',
// 使MIME
mime: [
'image/*',
'video/*',
'application/msword', // doc
'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // docx
'application/pdf', // pdf
'application/vnd.ms-excel', // xls
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // xlsx
],
maximum: 6, // 6
multiple: false, //
},
(res) => {
const tempFilePaths = res.files[0] //
uni.uploadFile({
url: '/common/uploadFile',
filePath: tempFilePaths,
name: 'file',
formData: {
file: 'file',
},
success: (res) => {
const result = JSON.parse(res.data)
if (result.code === 200) {
addOrEditFormModel.value.fileList.push(result.data)
}
},
fail: (err) => {
console.error('上传失败', err)
},
})
},
(err) => {
console.error('选择文件失败:', err)
plus.nativeUI.alert('选择文件失败: ' + err.message)
},
)
// #endif
}
//
const onHandleDelete = (index) => {
addOrEditFormModel.value.fileList.splice(index, 1)
}
//
const onHandleSubmit = () => {
addOrEditFormModelRef.value.validate().then(async (valid) => {
if (valid) {
if (addOrEditFormModel.value.fileList.length === 0) {
uni.$u.toast('请上传勘察附件')
return
}
const {
projectName, //
proId, // ID
surveyUser, //
surveyContent, //
modelId, // id
modelName,
surveyResult, //
date,
fileList,
} = addOrEditFormModel.value
const params = {
projectName, //
proId, // ID
surveyUser, //
surveyTime: dayjs(date).format('YYYY-MM-DD'), //
surveyContent, //
modelId, // id
modelName,
surveyResult, //
surveyAttach: fileList.map((item) => item.url).join(','), //
}
const API = addOrEditFormModel.value.id ? editSurveyDataApi : addSurveyDataApi
if (addOrEditFormModel.value.id) {
params.id = addOrEditFormModel.value.id
}
console.log('params新增时入参', params)
const res = await API(params)
if (res.code === 200) {
uni.$u.toast(addOrEditFormModel.value.id ? '修改成功' : '新增成功')
//
setTimeout(() => {
uni.navigateBack({
delta: 1,
success: () => {
//
uni.$emit('onHandleSearch')
},
})
}, 500)
}
}
})
}
//
const getSurveyDataDetail = async () => {
const res = await getSurveyDataDetailApi(addOrEditFormModel.value.id)
const {
surveyUser,
surveyTime,
surveyContent,
modelId,
surveyResult,
surveyAttach,
modelName,
} = res.data
addOrEditFormModel.value.surveyUser = surveyUser
addOrEditFormModel.value.date = dayjs(surveyTime).valueOf() //
addOrEditFormModel.value.surveyContent = surveyContent
addOrEditFormModel.value.modelId = [modelId]
addOrEditFormModel.value.modelName = modelName
addOrEditFormModel.value.surveyResult = surveyResult
addOrEditFormModel.value.fileList = surveyAttach?.split(',')
}
//
const getModelList = async () => {
const { rows: res } = await getModelListApi({
page: 1,
pageSize: 999,
projectId: addOrEditFormModel.value.proId,
})
const modelList = res.filter((item) => item.nodelevel == item.nodeCount)
modelColumns.value.push(modelList)
}
const onConfirmSelectModel = (e) => {
const currentIndex = e.indexs
const selectModel = modelColumns.value[0][currentIndex]
addOrEditFormModel.value.modelName = selectModel.nodeName
addOrEditFormModel.value.modelId = selectModel.id
showPickerSelectModel.value = false
}
onLoad((options) => {
getModelList()
//
if (options?.isType === 'add') {
addOrEditFormModel.value.id = null
} else {
addOrEditFormModel.value.id = options?.id
getSurveyDataDetail()
}
projectName.value =
options?.projectName + '--勘察' + (options?.isType === 'add' ? '填报' : '修改')
addOrEditFormModel.value.proId = options?.proId
addOrEditFormModel.value.projectName = options?.projectName
})
</script>
<style lang="scss" scoped>
.site-survey-container {
height: 100%;
background-color: #f7f8fa;
box-sizing: border-box;
padding: 20rpx;
}
.upload-box,
.file-list-show {
width: 88px;
height: 88px;
display: flex;
justify-content: center;
align-items: center;
background-color: #f4f5f7;
border-radius: 10rpx;
margin-top: 20rpx;
margin-bottom: 20rpx;
}
.file-list-show {
margin-right: 6px;
position: relative;
.delete-icon {
position: absolute;
right: 0;
top: 0;
z-index: 10;
}
}
</style>

View File

@ -0,0 +1,268 @@
<template>
<!-- 现场勘察 -->
<view class="site-survey-container">
<!-- 项目名称 -->
<up-navbar :title="projectName" bgColor="#fff" @leftClick="onHandleLeftClick"> </up-navbar>
<!-- 查询 -->
<view
class="site-survey-container"
:style="{ paddingTop: safeAreaInsets?.top + 44 + 'px' }"
>
<up-row :gutter="10" class="project-select-row">
<up-col span="3">
<up-datetime-picker
hasInput
placeholder="请选择日期"
mode="date"
:inputProps="{
border: 'surround',
shape: 'square',
inputAlign: 'center',
suffixIcon: 'calendar',
}"
v-model="queryDate"
>
</up-datetime-picker>
</up-col>
<up-col span="3">
<view class="project-select-button-box">
<up-button type="primary" text="查询" @click="onHandleSearch" />
<up-button
type="primary"
:plain="true"
:hairline="true"
text="新建"
@click="onHandleAdd"
/>
</view>
</up-col>
</up-row>
<!-- 表格 -->
<view class="project-select-table-box">
<!-- 表头 -->
<up-row class="table-th">
<up-col class="table-td" span="0.5"> 序号 </up-col>
<up-col class="table-td" span="2.5"> 项目名称 </up-col>
<up-col class="table-td" span="1"> 勘察人 </up-col>
<up-col class="table-td" span="1.5"> 勘察日期 </up-col>
<up-col class="table-td" span="1"> 勘察内容 </up-col>
<up-col class="table-td" span="1"> 勘察模型 </up-col>
<!-- <up-col class="table-td" span="1"> 模型设计人员 </up-col> -->
<up-col class="table-td" span="1"> 勘察附件 </up-col>
<up-col class="table-td" span="2"> 勘察结果 </up-col>
<up-col class="table-td" span="1.5"> 操作 </up-col>
</up-row>
<!-- 表格内容 -->
<up-row
:key="index"
class="table-tbody"
v-for="(item, index) in projectList"
@tap="onHandleSelectProject(item)"
:style="{
borderBottom:
index !== projectList.length - 1 ? '1px solid #f7f8fa' : 'none',
}"
>
<up-col class="table-td" span="0.5"> {{ index + 1 }} </up-col>
<up-col class="table-td" span="2.5"> {{ item.proName }} </up-col>
<up-col class="table-td" span="1"> {{ item.surveyUser }} </up-col>
<up-col class="table-td" span="1.5"> {{ item.surveyTime }} </up-col>
<up-col class="table-td" span="1"> {{ item.surveyContent }} </up-col>
<up-col class="table-td" span="1"> {{ item.modelName }} </up-col>
<!-- <up-col class="table-td" span="1"> {{ item.projectName }} </up-col> -->
<up-col class="table-td" span="1" style="color: #007aff">
{{ item.surveyAttach?.split(',').length || 0 }}
</up-col>
<up-col class="table-td" span="2"> {{ item.surveyResult }} </up-col>
<up-col class="table-td" span="1.5">
<view style="display: flex; justify-content: space-between">
<up-button
type="primary"
text="编辑"
size="small"
style="width: 45%"
@click="onHandleEdit(item)"
/>
<up-button
type="error"
text="删除"
size="small"
style="width: 45%"
@click="onHandleDelete(item)"
/>
</view>
</up-col>
</up-row>
</view>
<!-- 分页 -->
<view class="pagination-box">
<u-pagination
:total="total"
:current-page="queryParams.pageNum"
layout="prev, pager, next"
:page-size="queryParams.pageSize"
@current-change="onHandleCurrentChange"
/>
</view>
</view>
<up-modal
title="温馨提示"
:show="showModalDelete"
:showCancelButton="true"
@cancel="onCancelDelete"
@confirm="onConfirmDelete"
content="是否确认永久删除该数据?"
/>
</view>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getSurveyDataListApi, deleteSurveyDataApi } from '@/services/survey.js'
import dayjs from 'dayjs'
const { safeAreaInsets } = uni.getSystemInfoSync()
const projectName = ref('') //
const proId = ref('') // id
const projectList = ref([]) //
const total = ref(0) //
const showModalDelete = ref(false) //
const deleteId = ref('') // id
const queryDate = ref(Date.now()) //
//
const queryParams = ref({
pageNum: 1,
pageSize: 10,
surveyTime: '',
})
//
const onHandleLeftClick = () => {
uni.navigateBack({
delta: 1,
})
}
//
const onHandleSearch = () => {
getSurveyDataList()
}
//
const onHandleCurrentChange = (page) => {
queryParams.value.pageNum = page
getSurveyDataList()
}
//
const onHandleAdd = () => {
uni.navigateTo({
url: `/pages/siteSurvey/addOrEditForm?projectName=${projectName.value}&proId=${proId.value}&isType=add`,
})
}
//
const getSurveyDataList = async () => {
queryParams.value.surveyTime = dayjs(queryDate.value).format('YYYY-MM-DD')
const res = await getSurveyDataListApi(queryParams.value)
projectList.value = res?.rows
total.value = res?.total
}
//
const onHandleEdit = (item) => {
uni.navigateTo({
url: `/pages/siteSurvey/addOrEditForm?projectName=${projectName.value}&proId=${proId.value}&id=${item.id}&isType=edit`,
})
}
//
const onHandleDelete = (item) => {
showModalDelete.value = true
deleteId.value = item.id
}
//
const onCancelDelete = () => {
showModalDelete.value = false
}
//
const onConfirmDelete = async () => {
// showModalDelete.value = false
const res = await deleteSurveyDataApi(deleteId.value)
if (res.code === 200) {
uni.$u.toast('删除成功')
getSurveyDataList()
} else {
uni.$u.toast('删除失败')
}
showModalDelete.value = false
}
onLoad((options) => {
projectName.value = options?.projectName
proId.value = options?.proId
uni.$on('onHandleSearch', getSurveyDataList)
getSurveyDataList()
})
//
onUnmounted(() => {
uni.$off('onHandleSearch', getSurveyDataList)
})
</script>
<style lang="scss" scoped>
.site-survey-container {
height: 100%;
background-color: #f7f8fa;
box-sizing: border-box;
padding-bottom: 20rpx;
.project-select-row,
.project-select-table-box {
background-color: #fff;
margin-top: 20rpx;
padding: 20rpx;
}
.project-select-button-box {
display: flex;
align-items: center;
gap: 10rpx;
}
.table-td {
text-align: center !important;
}
.table-th {
padding: 20rpx 0;
background-color: #f7f8fa;
}
.table-tbody {
padding: 20rpx 0;
}
.table-tbody:hover {
background-color: #f7f8fa;
}
.pagination-box {
margin-top: 20rpx;
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@ -0,0 +1,232 @@
<template>
<!-- 工作台页面 -->
<up-navbar :title="projectName" bgColor="#fff" @leftClick="onHandleLeftClick"> </up-navbar>
<view class="work-home-container">
<view class="work-home-content">
<view
:key="index"
@click="onHandleJump(item)"
class="work-home-content-item"
v-for="(item, index) in imgNavList"
>
<up-image :src="item.img" mode="aspectFit" :width="imgWidth" height="160" />
<text class="work-home-content-item-title"> {{ item.title }} </text>
</view>
</view>
</view>
<!-- 打开弹框选择模型 -->
<!-- <up-popup :show="projectPopupShow" mode="center">
<view class="project-popup-content">
<view class="project-popup-content-title">选择模型</view>
<up-select
v-model:current="projectId"
:label="selectProjectLabel"
:options="projectList"
@select="onSelectProject"
/>
<view class="project-popup-content-btn">
<up-button type="primary" @click="onCloseProjectPopup(true)">确定</up-button>
<up-button
plain
type="primary"
style="margin-left: 20rpx"
@click="onCloseProjectPopup(false)"
>取消
</up-button>
</view>
</view>
</up-popup> -->
<up-picker
title="请选择模型"
:show="showPickerSelectModel"
:columns="modelColumns"
@confirm="onConfirmSelectModel"
@cancel="showPickerSelectModel = false"
keyName="nodeName"
valueName="id"
></up-picker>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getModelListApi } from '@/services/model.js'
import workHomeImg_1 from '@/static/image/work_home_1.png'
import workHomeImg_2 from '@/static/image/work_home_2.png'
import workHomeImg_3 from '@/static/image/work_home_3.png'
const projectName = ref('')
const imgWidth = ref(0)
const projectPopupShow = ref(false)
const projectId = ref('')
const proId = ref('')
const selectProjectLabel = ref('请选择模型')
const projectInfo = ref({})
const showPickerSelectModel = ref(false)
const modelColumns = ref([])
const imgNavList = ref([
{
img: workHomeImg_1,
title: '地图导航',
jumpUrl: '/pages/mapNav/index',
},
{
img: workHomeImg_2,
title: 'AR检查',
jumpUrl: '/pages/arCheck/index',
},
{
img: workHomeImg_3,
title: '现场勘察',
jumpUrl: '/pages/siteSurvey/index',
},
])
//
const onHandleJump = (item) => {
// uni.navigateTo({
// url,
// })
if (item.title === 'AR检查') {
showPickerSelectModel.value = true
} else if (item.title === '地图导航') {
uni.navigateTo({
url: item.jumpUrl + `?projectInfo=${JSON.stringify(projectInfo.value)}`,
})
} else {
uni.navigateTo({
url: item.jumpUrl + `?projectName=${projectName.value}&proId=${proId.value}`,
})
}
}
const onSelectProject = (e) => {
projectId.value = e.id
selectProjectLabel.value = e.name
console.log(projectId.value, 'projectId')
}
const onCloseProjectPopup = (type) => {
if (type && !projectId.value) {
uni.showToast({
title: '请选择模型',
icon: 'none',
})
return
}
uni.navigateTo({
url: '/pages/arCheck/index',
})
projectPopupShow.value = false
}
//
const getModelList = async () => {
const { rows: res } = await getModelListApi({
page: 1,
pageSize: 999,
projectId: proId.value,
})
const modelList = res.filter((item) => item.nodelevel == item.nodeCount)
modelColumns.value.push(modelList)
}
//
const onConfirmSelectModel = (e) => {
// console.log(e, 'e')
const currentIndex = e.indexs
const selectModel = modelColumns.value[0][currentIndex]
uni.navigateTo({
url: '/pages/arCheck/index?modelId=' + selectModel.id,
})
showPickerSelectModel.value = false
}
//
const onHandleLeftClick = () => {
uni.navigateBack({
delta: 1,
})
}
onLoad((options) => {
projectName.value = options?.projectName
const proInfo = JSON.parse(options?.projectInfo)
projectInfo.value = proInfo
proId.value = options?.proId
getModelList()
})
onMounted(() => {
uni.createSelectorQuery()
.select('.work-home-content-item') // 使
.boundingClientRect((rect) => {
if (rect) {
imgWidth.value = rect.width
}
})
.exec()
})
</script>
<style lang="scss" scoped>
.work-home-container {
width: 100%;
height: 100%;
background-color: #f7f8fa;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
.work-home-content {
width: 100%;
display: flex;
justify-content: space-around;
.work-home-content-item {
width: calc((100% - 20rpx) / 3.3);
padding: 60rpx 10rpx;
display: flex;
flex-direction: column;
align-items: center;
background-color: #fff;
box-sizing: border-box;
border-radius: 12px;
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
}
.work-home-content-item-title {
margin-top: 40rpx;
}
}
}
.project-popup-content {
width: 80vw;
padding: 30rpx 16rpx;
}
.project-popup-content-title {
font-size: 26rpx;
margin-bottom: 20rpx;
}
.project-popup-content-btn {
width: 50%;
margin-top: 20rpx;
display: flex;
transform: translateX(100%);
}
</style>

39
src/services/login.js Normal file
View File

@ -0,0 +1,39 @@
import { http } from '@/utils/http'
import { encrypt, decrypt } from '@/utils/encrypt' // 引入加解密方法
// 登录接口
export const loginApi = (data) => {
return http({
method: 'POST',
url: '/login',
data,
})
}
// 获取图形验证码
export const getCodeImgApi = () => {
return http({
method: 'GET',
url: '/captchaImage',
})
}
// 登录接口
// export const loginApi = (data) => {
// return http({
// method: 'POST',
// url: '/imgTool/login',
// isEncrypt: true,
// isPassWord: false,
// data,
// header: {
// 'Content-Type': 'application/x-www-form-urlencoded',
// },
// })
// }
// 获取用户信息
export const getUserInfoApi = () => {
return http({
method: 'GET',
url: '/imgTool/users/current',
})
}

18
src/services/model.js Normal file
View File

@ -0,0 +1,18 @@
import { http } from '@/utils/http'
// 获取模型列表
export const getModelListApi = (data) => {
return http({
method: 'GET',
url: '/model/list',
data,
})
}
// 获取模型详情
export const getModelDetailApi = (data) => {
return http({
method: 'POST',
url: '/model/openView',
data,
})
}

View File

@ -0,0 +1,10 @@
import { http } from '@/utils/http'
// 获取项目列表
export const getProjectListApi = (data) => {
return http({
method: 'GET',
url: '/project/list',
data,
})
}

48
src/services/survey.js Normal file
View File

@ -0,0 +1,48 @@
import { http } from '@/utils/http'
// 新增现场勘察填报数据
export const addSurveyDataApi = (data) => {
return http({
method: 'POST',
url: '/survey',
data,
})
}
// 修改现场勘察填报数据
export const editSurveyDataApi = (data) => {
return http({
method: 'PUT',
url: '/survey',
data,
})
}
// 获取现场勘察填报数据列表
export const getSurveyDataListApi = (data) => {
return http({
method: 'GET',
url: '/survey/list',
data,
})
}
// 删除现场勘察填报数据
export const deleteSurveyDataApi = (id) => {
return http({
method: 'DELETE',
url: `/survey/${id}`,
})
}
// 查询现场勘察填报数据详情
export const getSurveyDataDetailApi = (id) => {
return http({
method: 'GET',
url: `/survey/${id}`,
})
}
// 上传附件
export const uploadFileApi = (data) => {
return http({
method: 'POST',
url: '/survey/uploadFile',
data,
})
}

6
src/shime-uni.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
export {};
declare module "vue" {
type Hooks = App.AppInstance & Page.PageInstance;
interface ComponentCustomOptions extends Hooks {}
}

BIN
src/static/image/camera.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

BIN
src/static/image/video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
src/static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

127
src/static/map.html Normal file
View File

@ -0,0 +1,127 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
<script type="text/javascript"
src="https://api.map.baidu.com/api?v=3.0&&type=webgl&ak=cClgLBaLgGUdQDilX9dGvieL"></script>
<title>百度地图</title>
<style>
#map-container {
width: 100vw;
height: 100vh;
}
/** 去除百度地图的水印和logo */
.BMap_cpyCtrl,
.anchorBL {
display: none;
}
</style>
</head>
<body>
<div id="map-container"></div>
</body>
<script type="text/javascript">
document.addEventListener('UniAppJSBridgeReady', function () {
// // 1. 初始化地图
// const map = new BMapGL.Map('map-container') // 创建地图实例
// let point = new BMapGL.Point(117.13805, 31.8734) // 创建点坐标
// map.centerAndZoom(point, 12) // 初始化地图,设置中心点坐标和地图级别
// map.enableScrollWheelZoom(true) // 启用滚轮放大缩小
function getUrlParams() {
const params = new URLSearchParams(window.location.search);
return {
lat: parseFloat(params.get('lat')) || 31.8734, // 默认值
lng: parseFloat(params.get('lng')) || 117.13805, // 默认值
proName: decodeURIComponent(params.get('proName')) || '-', // 默认值
chargePerson: decodeURIComponent(params.get('chargePerson')) || '-', // 默认值
location: decodeURIComponent(params.get('location')) || '-' // 默认值
};
}
const { lat, lng, proName, chargePerson, location } = getUrlParams()
const proInfo = {
lat,
lng,
proName,
chargePerson,
location
}
initMap(proInfo)
function initMap(proInfo) {
const map = new BMapGL.Map('map-container') // 创建地图实例
let point = new BMapGL.Point(proInfo.lng, proInfo.lat) // 创建点坐标
map.centerAndZoom(point, 12) // 初始化地图,设置中心点坐标和地图级别
map.enableScrollWheelZoom(true) // 启用滚轮放大缩小
handleProjectInfoOnMap(map, proInfo)
}
function handleProjectInfoOnMap(map, projectInfo) {
// 示例1: 如果项目信息包含经纬度,移动地图到该位置
if (projectInfo.lng && projectInfo.lat) {
const projectPoint = new BMapGL.Point(projectInfo.lng, projectInfo.lat);
map.centerAndZoom(projectPoint, 15); // 移动并放大到项目位置
const icon = new BMapGL.Icon('./image/location.png', new BMapGL.Size(36, 36), {
anchor: new BMapGL.Size(12, 24), // 图标锚点,使图标底部中心点与坐标点重合
})
// 创建marker并应用自定义图标
const marker = new BMapGL.Marker(projectPoint, {
icon: icon,
})
map.addOverlay(marker)
const infoWindow = new BMapGL.InfoWindow(`
<h3 style="color: #002db6; margin: 0 0 10px 0; font-size: 18px;">${projectInfo.proName}</h3>
<p>负责人: ${projectInfo.chargePerson}</p>
<p>所在地: ${projectInfo.location}</p>
`);
const label = new BMapGL.Label(projectInfo.proName, {
position: projectPoint,
offset: new BMapGL.Size(0, 0), // 调整偏移量使文字在marker正下方
})
// 设置label样式
label.setStyle({
color: '#002db6',
backgroundColor: 'transparent',
border: 'none',
textAlign: 'center',
padding: '5px',
whiteSpace: 'nowrap',
fontSize: '18px',
fontWeight: 'bold',
transform: 'translateX(-45%)' // 关键让Label向左移动自身宽度的一半
});
map.addOverlay(label)
marker.addEventListener('click', function () {
map.openInfoWindow(infoWindow, projectPoint);
});
}
}
})
</script>
</html>

13
src/stores/index.js Normal file
View File

@ -0,0 +1,13 @@
import { createPinia } from 'pinia'
import persist from 'pinia-plugin-persistedstate'
// 创建 pinia 实例
const pinia = createPinia()
// 使用持久化存储插件
pinia.use(persist)
// 默认导出,给 main.js 使用
export default pinia
// 模块统一导出
export * from './modules/member'

View File

@ -0,0 +1,77 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useMemberStore = defineStore(
'member',
() => {
// 定义用户信息
const userInfo = ref({})
const token = ref('')
const userType = ref(1)
const companyList = ref([])
const userCompanyName = ref()
// 存储用户信息
const setUserInfo = (val) => {
userInfo.value = val
}
// 清除用户信息
const clearUserInfo = () => {
userInfo.value = undefined
token.value = ''
userType.value = 1
companyList.value = []
userCompanyName.value = ''
}
// 存储 token
const setToken = (val) => {
token.value = val
}
// 清除 token
const clearToken = (val) => {
token.value = undefined
}
// 切换用户角色
const editUserType = (val) => {
userType.value = val
}
// 存储公司列表
const setCompanyList = (list) => {
companyList.value = list
}
// 存储公司名称
const setCompanyName = (name) => {
userCompanyName.value = name
}
// 把数据和方法 return 出去
return {
userInfo,
token,
userType,
companyList,
userCompanyName,
setToken,
clearToken,
setUserInfo,
editUserType,
setCompanyName,
clearUserInfo,
setCompanyList,
}
},
// 用户信息持久化处理
{
persist: {
storage: {
getItem(key) {
return uni.getStorageSync(key)
},
setItem(key, value) {
uni.setStorageSync(key, value)
},
},
},
},
)

79
src/uni.scss Normal file
View File

@ -0,0 +1,79 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量同时无需 import 这个文件
*/
/* 颜色变量 */
/* uni.scss */
@import 'uview-plus/theme.scss';
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color: #333; // 基本色
$uni-text-color-inverse: #fff; // 反色
$uni-text-color-grey: #999; // 辅助灰色如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable: #c0c0c0;
/* 背景颜色 */
$uni-bg-color: #fff;
$uni-bg-color-grey: #f8f8f8;
$uni-bg-color-hover: #f1f1f1; // 点击状态颜色
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色
/* 边框颜色 */
$uni-border-color: #c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm: 12px;
$uni-font-size-base: 14px;
$uni-font-size-lg: 16;
/* 图片尺寸 */
$uni-img-size-sm: 20px;
$uni-img-size-base: 26px;
$uni-img-size-lg: 40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2c405a; // 文章标题颜色
$uni-font-size-title: 20px;
$uni-color-subtitle: #555; // 二级标题颜色
$uni-font-size-subtitle: 18px;
$uni-color-paragraph: #3f536e; // 文章段落颜色
$uni-font-size-paragraph: 15px;

28
src/utils/encrypt.js Normal file
View File

@ -0,0 +1,28 @@
// 加解密方法
import CryptoJS from 'crypto-js'
// const key = 'zhst@bonus@zhst@bonus@1234567890' // 加密密钥
const key = 'zhst@bonus@zhst@' // 加密密钥
const utf8Key = CryptoJS.enc.Utf8.parse(key)
// AES 加密UTF-8 处理)
export const encrypt = (message) => {
const utf8Message = CryptoJS.enc.Utf8.parse(message)
const cbc_iv = CryptoJS.enc.Utf8.parse('1234567812345678')
const encrypted = CryptoJS.AES.encrypt(utf8Message, utf8Key, {
iv: cbc_iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
})
return encrypted.toString()
}
// AES 解密
export const decrypt = (encryptedBase64) => {
const decrypted = CryptoJS.AES.decrypt(encryptedBase64, utf8Key, {
iv: cbc_iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
})
return CryptoJS.enc.Utf8.stringify(decrypted)
}

109
src/utils/http.js Normal file
View File

@ -0,0 +1,109 @@
import { useMemberStore } from '@/stores'
import { encrypt, decrypt } from './encrypt' // 引入加解密方法
import { cloneDeep } from 'lodash-es' // 引入深拷贝函数
/**
* 添加拦截器
* 拦截 request 请求
* baseURL 设置请求ip地址和端口
*/
// const ENV = process.env.NODE_ENV
// const baseURL = ENV === 'development' ? '/api' : 'http://192.168.0.133:11997'
const baseURL = import.meta.env.VITE_API_BASE_URL
/**
* httpInterceptor 分别拦截 request uploadFile 请求
*/
// 添加请求拦截
const httpInterceptor = {
invoke(options) {
// 1. 先判断请求 url 是否为完整的 http 请求路径 如果不是则拼接 baseURL
if (!options.url.startsWith('http')) {
options.url = baseURL + options.url
}
// 2. 设置请求超时时间默认为60s设置为 10s
options.timeout = 10000
// 3. 增加小程序端请求头标识
options.header = {
// 'source-client': 'mini',
...options.header,
}
// 4. 增加 token 请求头标识
const memberStore = useMemberStore()
const token = memberStore.token
if (token) {
options.header.Authorization = token
options.header.Token = token
}
},
}
uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)
// 设置http请求
export const http = (options) => {
return new Promise((resolve, reject) => {
uni.request({
...options,
success(res) {
console.log(res, 'res--')
// 1. 判断是否请求成功
if (res.statusCode >= 200 && res.statusCode < 300) {
if (res.data.code >= 200 && res.data.code < 300) {
resolve(res.data)
} else if (res.data.code === 401) {
// 2. 401 表示token过期 去往登录页重新登录
uni.showToast({
icon: 'none',
title: `${res.data.msg}`,
})
const memberStore = useMemberStore()
memberStore.clearUserInfo()
memberStore.clearToken()
uni.navigateTo({
url: '/pages/login/index',
})
reject(res)
} else if (res.data.code === 500) {
uni.showToast({
icon: 'none',
title: res?.data?.msg,
})
reject(res)
}
} else if (res.statusCode === 401) {
// 2. 401 表示token过期 去往登录页重新登录
// const memberStore = useMemberStore()
// memberStore.clearUserInfo()
// memberStore.clearToken()
// uni.navigateTo({
// url: '/pages/login/index',
// })
uni.$u.toast(res.data.message)
reject(res)
} else {
// 3. 其他错误
uni.showToast({
icon: 'none',
title: res?.data?.message || '请求失败,请切换网络后尝试',
})
reject(res)
}
// console.log(res)
},
fail(err) {
uni.showToast({
icon: 'none',
title: err?.message || '请求失败,请切换网络后尝试',
})
console.log(err, '请求失败')
reject(err)
},
})
})
}

15
src/utils/index.js Normal file
View File

@ -0,0 +1,15 @@
export function formatCustomNumber(num) {
const str = num.toString()
const len = str.length
if (len <= 2) return str // 不足2位直接返回
// 最后2位单独处理
const lastTwo = str.slice(-2)
const rest = str.slice(0, -2)
// 每3位加逗号
const formattedRest = rest.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
return `${formattedRest},${lastTwo}`
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>View</title>
<link rel="icon" href="data:,">
<link rel="stylesheet" href="app.css" />
<script>var __uniConfig = {"globalStyle":{},"darkmode":false}</script>
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
</head>
<body>
<div id="app"></div>
<script src="uni-app-view.umd.js"></script>
<script src="app-wxs.js"></script>
</body>
</html>

View File

@ -0,0 +1,11 @@
;(function(){
let u=void 0,isReady=false,onReadyCallbacks=[],isServiceReady=false,onServiceReadyCallbacks=[];
const __uniConfig = {"pages":[],"globalStyle":{"backgroundColor":"#F5F4F5","navigationBar":{"backgroundColor":"#F5F4F5","titleText":"AR水运","type":"default","titleColor":"#333"},"isNVue":false},"nvue":{"compiler":"uni-app","styleCompiler":"uni-app","flex-direction":"column"},"renderer":"auto","appname":"AR水运","splashscreen":{"alwaysShowBeforeRender":true,"autoclose":true},"compilerVersion":"4.57","entryPagePath":"pages/login/index","entryPageQuery":"","realEntryPagePath":"","networkTimeout":{"request":60000,"connectSocket":60000,"uploadFile":60000,"downloadFile":60000},"locales":{},"darkmode":false,"themeConfig":{}};
const __uniRoutes = [{"path":"pages/login/index","meta":{"isQuit":true,"isEntry":true,"navigationBar":{"titleText":"custom","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/projectSelect/index","meta":{"navigationBar":{"titleText":"项目选择","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/workHome/index","meta":{"navigationBar":{"titleText":"custom","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/mapNav/index","meta":{"navigationBar":{"titleText":"custom","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/arCheck/index","meta":{"navigationBar":{"titleText":"custom","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/siteSurvey/index","meta":{"navigationBar":{"titleText":"custom","style":"custom","type":"default"},"isNVue":false}},{"path":"pages/siteSurvey/addOrEditForm","meta":{"navigationBar":{"titleText":"custom","style":"custom","type":"default"},"isNVue":false}}].map(uniRoute=>(uniRoute.meta.route=uniRoute.path,__uniConfig.pages.push(uniRoute.path),uniRoute.path='/'+uniRoute.path,uniRoute));
__uniConfig.styles=[];//styles
__uniConfig.onReady=function(callback){if(__uniConfig.ready){callback()}else{onReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"ready",{get:function(){return isReady},set:function(val){isReady=val;if(!isReady){return}const callbacks=onReadyCallbacks.slice(0);onReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});
__uniConfig.onServiceReady=function(callback){if(__uniConfig.serviceReady){callback()}else{onServiceReadyCallbacks.push(callback)}};Object.defineProperty(__uniConfig,"serviceReady",{get:function(){return isServiceReady},set:function(val){isServiceReady=val;if(!isServiceReady){return}const callbacks=onServiceReadyCallbacks.slice(0);onServiceReadyCallbacks.length=0;callbacks.forEach(function(callback){callback()})}});
service.register("uni-app-config",{create(a,b,c){if(!__uniConfig.viewport){var d=b.weex.config.env.scale,e=b.weex.config.env.deviceWidth,f=Math.ceil(e/d);Object.assign(__uniConfig,{viewport:f,defaultFontSize:16})}return{instance:{__uniConfig:__uniConfig,__uniRoutes:__uniRoutes,global:u,window:u,document:u,frames:u,self:u,location:u,navigator:u,localStorage:u,history:u,Caches:u,screen:u,alert:u,confirm:u,prompt:u,fetch:u,XMLHttpRequest:u,WebSocket:u,webkit:u,print:u}}}});
})();

View File

@ -0,0 +1 @@
(function(){})();

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,6 @@
var __wxsModules={};
__wxsModules["5126814f"]=(()=>{var v=(r,t)=>()=>(t||r((t={exports:{}}).exports,t),t.exports);var p=v((f,c)=>{function W(r,t){var l=r.detail,a=l.scrollWidth,o=l.scrollLeft,i=r.currentTarget.dataset,e=i.scrollWidth||i.scrollwidth||0,s=i.indicatorWidth||i.indicatorwidth||0,n=i.barWidth||i.barwidth||0,h=o/(a-e)*(s-n);d(t,h)}function _(r,t){t.callMethod("scrollEvent","right");var l=r.currentTarget.dataset,a=l.indicatorWidth||l.indicatorwidth||0,o=l.barWidth||l.barwidth||0;d(t,a-o)}function u(r,t){t.callMethod("scrollEvent","left"),d(t,0)}function d(r,t){r.selectComponent(".u-scroll-list__indicator__line__bar")&&r.selectComponent(".u-scroll-list__indicator__line__bar").setStyle({transform:"translateX("+t+"px)"})}c.exports={scroll:W,scrolltolower:_,scrolltoupper:u}});return p();})();
__wxsModules["973234d6"]=(()=>{var c=(t,r)=>()=>(r||t((r={exports:{}}).exports,r),r.exports);var M=c((A,v)=>{function b(t,r){var s=t.instance,a=s.getState();if(!a.disabled){var e=t.touches;e&&e.length>1||(a.moving=!0,a.startX=e[0].pageX,a.startY=e[0].pageY,r.callMethod("closeOther"))}}function m(t,r){var s=t.instance,a=s.getState();if(!(a.disabled||!a.moving)){var e=t.touches,i=e[0].pageX,n=e[0].pageY,o=i-a.startX,u=n-a.startY,f=a.buttonsWidth;(Math.abs(o)>Math.abs(u)||Math.abs(o)>a.threshold)&&(t.preventDefault&&t.preventDefault(),t.stopPropagation&&t.stopPropagation()),!(Math.abs(o)<Math.abs(u))&&(a.status==="open"?(o<0&&(o=0),o>f&&(o=f),g(-f+o,s,r)):(o>0&&(o=0),Math.abs(o)>f&&(o=-f),g(o,s,r)))}}function S(t,r){var s=t.instance,a=s.getState();if(!(!a.moving||a.disabled)){var e=t.changedTouches?t.changedTouches[0]:{},i=e.pageX,n=e.pageY,o=i-a.startX;if(a.status==="open"){if(o<0)return;if(o===0)return h(s,r);Math.abs(o)<a.threshold?l(s,r):h(s,r)}else{if(o>0)return;Math.abs(o)<a.threshold?h(s,r):l(s,r)}}}function p(t){return t.toString().indexOf("s")>=0?t:t>30?t+"ms":t+"s"}function g(t,r,s){var a=r.getState(),e=s.selectAllComponents(".u-swipe-action-item__right__button");r.requestAnimationFrame(function(){r.setStyle({transition:"none",transform:"translateX("+t+"px)","-webkit-transform":"translateX("+t+"px)"})})}function l(t,r){var s=t.getState(),a=r.selectAllComponents(".u-swipe-action-item__right__button"),e=p(s.duration),i=-s.buttonsWidth;t.requestAnimationFrame(function(){t.setStyle({transition:"transform "+e,transform:"translateX("+i+"px)","-webkit-transform":"translateX("+i+"px)"})}),d("open",t,r)}function d(t,r,s){var a=r.getState();a.status=t,s.callMethod("setState",t)}function h(t,r){var s=t.getState(),a=r.selectAllComponents(".u-swipe-action-item__right__button"),e=a.length,i=p(s.duration);t.requestAnimationFrame(function(){t.setStyle({transition:"transform "+i,transform:"translateX(0px)","-webkit-transform":"translateX(0px)"});for(var n=e-1;n>=0;n--)a[n].setStyle({transition:"transform "+i,transform:"translateX(0px)","-webkit-transform":"translateX(0px)"})}),d("close",t,r)}function X(t,r,s,a){var e=a.getState();e.disabled||(t==="close"&&e.status==="open"?h(a,s):t==="open"&&e.status==="close"&&l(a,s))}function _(t,r,s,a){var e=a.getState();if(!(!e||!t)){if(e.disabled=t.disabled,e.duration=t.duration,e.show=t.show,e.threshold=t.threshold,e.buttons=t.buttons,e.buttons)for(var i=e.buttons.length,n=0,o=t.buttons,u=0;u<i;u++)n+=o[u].width;e.buttonsWidth=n,e.show&&l(a,s)}}v.exports={touchstart:b,touchmove:m,touchend:S,sizeChange:_,statusChange:X}});return M();})();
__wxsModules["5e7f39f7"]=(()=>{var u=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports);var i=u((l,t)=>{var n={abbr:!0,b:!0,big:!0,code:!0,del:!0,em:!0,i:!0,ins:!0,label:!0,q:!0,small:!0,span:!0,strong:!0,sub:!0,sup:!0};t.exports={isInline:function(r,e){return n[r]||(e||"").indexOf("display:inline")!==-1}}});return i();})();

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"@platforms":["android","iPhone","iPad"],"id":"__UNI__0A021AF","name":"AR水运","version":{"name":"1.0.0","code":100},"description":"AR水运","developer":{"name":"","email":"","url":""},"permissions":{"Barcode":{},"Camera":{},"UniNView":{"description":"UniNView原生渲染"}},"plus":{"useragent":{"value":"uni-app","concatenate":true},"splashscreen":{"target":"id:1","autoclose":true,"waiting":true,"delay":0},"popGesture":"close","launchwebview":{"render":"always","id":"1","kernel":"WKWebview"},"usingComponents":true,"nvueStyleCompiler":"uni-app","compilerVersion":3,"compatible":{"ignoreVersion":true},"statusbar":{"immersed":"supportedDevice","style":"dark","background":"#F5F4F5"},"uniStatistics":{"enable":false},"allowsInlineMediaPlayback":true,"uni-app":{"control":"uni-v3","vueVersion":"3","compilerVersion":"4.57","nvueCompiler":"uni-app","renderer":"auto","nvue":{"flex-direction":"column"},"nvueLaunchMode":"normal","webView":{"minUserAgentVersion":"49.0"}}},"app-harmony":{"useragent":{"value":"uni-app","concatenate":true},"uniStatistics":{"enable":false}},"launch_path":"__uniappview.html"}

View File

@ -0,0 +1 @@
.ar-check-container[data-v-225f2b20]{width:100%;height:100%}.ar-check-container .stacking-modal[data-v-225f2b20]{position:absolute;top:.625rem;right:.625rem;width:3.125rem;height:3.125rem;background:rgba(255,255,255,.9);border-radius:.3125rem}.ar-check-container .handel-bar[data-v-225f2b20]{position:absolute;bottom:.625rem;left:0;width:100%;display:flex;justify-content:center}.ar-check-container .handel-bar uni-view[data-v-225f2b20]{width:68px;height:68px;border-radius:50%;background-color:#165dff;display:flex;align-items:center;justify-content:center}.ar-check-container .handel-bar uni-view[data-v-225f2b20]:nth-child(2){margin:0 .375rem;font-size:12px;color:#fff}.ar-check-container .debug-btn[data-v-225f2b20]{position:absolute;top:.625rem;right:50%;width:3.125rem;height:3.125rem;background:rgba(255,255,255,.9);border-radius:.3125rem;text-align:center;line-height:3.125rem}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,127 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
<script type="text/javascript"
src="https://api.map.baidu.com/api?v=3.0&&type=webgl&ak=cClgLBaLgGUdQDilX9dGvieL"></script>
<title>百度地图</title>
<style>
#map-container {
width: 100vw;
height: 100vh;
}
/** 去除百度地图的水印和logo */
.BMap_cpyCtrl,
.anchorBL {
display: none;
}
</style>
</head>
<body>
<div id="map-container"></div>
</body>
<script type="text/javascript">
document.addEventListener('UniAppJSBridgeReady', function () {
// // 1. 初始化地图
// const map = new BMapGL.Map('map-container') // 创建地图实例
// let point = new BMapGL.Point(117.13805, 31.8734) // 创建点坐标
// map.centerAndZoom(point, 12) // 初始化地图,设置中心点坐标和地图级别
// map.enableScrollWheelZoom(true) // 启用滚轮放大缩小
function getUrlParams() {
const params = new URLSearchParams(window.location.search);
return {
lat: parseFloat(params.get('lat')) || 31.8734, // 默认值
lng: parseFloat(params.get('lng')) || 117.13805, // 默认值
proName: decodeURIComponent(params.get('proName')) || '-', // 默认值
chargePerson: decodeURIComponent(params.get('chargePerson')) || '-', // 默认值
location: decodeURIComponent(params.get('location')) || '-' // 默认值
};
}
const { lat, lng, proName, chargePerson, location } = getUrlParams()
const proInfo = {
lat,
lng,
proName,
chargePerson,
location
}
initMap(proInfo)
function initMap(proInfo) {
const map = new BMapGL.Map('map-container') // 创建地图实例
let point = new BMapGL.Point(proInfo.lng, proInfo.lat) // 创建点坐标
map.centerAndZoom(point, 12) // 初始化地图,设置中心点坐标和地图级别
map.enableScrollWheelZoom(true) // 启用滚轮放大缩小
handleProjectInfoOnMap(map, proInfo)
}
function handleProjectInfoOnMap(map, projectInfo) {
// 示例1: 如果项目信息包含经纬度,移动地图到该位置
if (projectInfo.lng && projectInfo.lat) {
const projectPoint = new BMapGL.Point(projectInfo.lng, projectInfo.lat);
map.centerAndZoom(projectPoint, 15); // 移动并放大到项目位置
const icon = new BMapGL.Icon('./image/location.png', new BMapGL.Size(36, 36), {
anchor: new BMapGL.Size(12, 24), // 图标锚点,使图标底部中心点与坐标点重合
})
// 创建marker并应用自定义图标
const marker = new BMapGL.Marker(projectPoint, {
icon: icon,
})
map.addOverlay(marker)
const infoWindow = new BMapGL.InfoWindow(`
<h3 style="color: #002db6; margin: 0 0 10px 0; font-size: 18px;">${projectInfo.proName}</h3>
<p>负责人: ${projectInfo.chargePerson}</p>
<p>所在地: ${projectInfo.location}</p>
`);
const label = new BMapGL.Label(projectInfo.proName, {
position: projectPoint,
offset: new BMapGL.Size(0, 0), // 调整偏移量使文字在marker正下方
})
// 设置label样式
label.setStyle({
color: '#002db6',
backgroundColor: 'transparent',
border: 'none',
textAlign: 'center',
padding: '5px',
whiteSpace: 'nowrap',
fontSize: '18px',
fontWeight: 'bold',
transform: 'translateX(-45%)' // 关键让Label向左移动自身宽度的一半
});
map.addOverlay(label)
marker.addEventListener('click', function () {
map.openInfoWindow(infoWindow, projectPoint);
});
}
}
})
</script>
</html>

File diff suppressed because one or more lines are too long

20
vite.config.js Normal file
View File

@ -0,0 +1,20 @@
import { defineConfig } from 'vite'
import removeConsole from 'vite-plugin-remove-console'
import uni from '@dcloudio/vite-plugin-uni'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [uni(), removeConsole()],
server: {
proxy: {
// 在此处编写代理规则
'/api': {
// target: 'http://112.29.103.165:1616', // 测试环境
target: 'http://192.168.0.133:58080', // 梁超
changeOrigin: true,
rewrite: (path) => {
return path.replace(/\/api/, '')
},
},
},
},
})