Compare commits

..

1 Commits

Author SHA1 Message Date
phm1551
769ce650f2 版本更新 2026-06-27 18:30:14 +08:00
22 changed files with 318 additions and 89 deletions

2
.gitignore vendored
View File

@ -18,5 +18,5 @@ bin-release/
# information for Eclipse / Flash Builder. # information for Eclipse / Flash Builder.
/.idea /.idea
/upgrade
niucloud/public/.htaccess niucloud/public/.htaccess
admin/.env.development

8
.htaccess Normal file
View File

@ -0,0 +1,8 @@
<ifModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
RewriteEngine on RewriteCond % !^$
</ifModule>

36
README.en.md Normal file
View File

@ -0,0 +1,36 @@
# niucloud-admin
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

View File

@ -1,4 +1,4 @@
![输入图片说明](https://media.niucloud.com/1712133019020249f332e83457a01a6799472e0495_aliyun.png) ![输入图片说明](https://www.niucloud.com/img/readme/%E9%A1%B6%E9%83%A8%E5%B9%BF%E5%91%8A1.jpg)
### niucloud-admin是什么 ### niucloud-admin是什么
niucloud-admin是一款快速开发通用管理后台框架前端采用最新的技术栈Vite+TypeScript+Vue3+ElementPlus最流行技术架构后台结合PHP8、Java SDK、Python等主流后端语言搭建内置集成用户权限、代码生成器、表单设计、云存储、短信发送、素材中心、微信及公众号、Api模块一系列开箱即用功能是一款快速可以开发企业级应用的软件系统。 niucloud-admin是一款快速开发通用管理后台框架前端采用最新的技术栈Vite+TypeScript+Vue3+ElementPlus最流行技术架构后台结合PHP8、Java SDK、Python等主流后端语言搭建内置集成用户权限、代码生成器、表单设计、云存储、短信发送、素材中心、微信及公众号、Api模块一系列开箱即用功能是一款快速可以开发企业级应用的软件系统。
@ -32,19 +32,14 @@ niucloud-admin是一款快速开发通用管理后台框架前端采用最新
### 操作指南 ### 操作指南
[官网地址](https://www.niucloud.com) [官网地址](https://www.niucloud.com)
| [服务市场](https://www.niucloud.com) | [服务市场](https://www.niucloud.com)
| [使用手册](https://www.niucloud.com/doc) | [使用手册](https://www.kancloud.cn/niucloud/niucloud-admin-develop/3153336)
| [二开手册](https://www.niucloud.com/doc) | [二开手册](https://www.kancloud.cn/niucloud/niucloud-admin-develop/3153336)
| [开发视频](https://www.niucloud.com/doc) | [API接口手册](https://www.niucloud.com/apidoc.html)
| [API接口手册](https://api.niucloud.com/apidoc.html?target_id=001) | [论坛地址](https://www.niucloud.com/bbs)
| [论坛地址](https://niucloud.com/bbs)
### 演示地址 ### 演示地址
- 管理后台演示网址:[<a href='https://v6.site.niucloud.com/admin' target="_blank"> 查看 </a>] - 管理后台演示网址:[<a href='http://v6.site.niucloud.com' target="_blank"> 查看 </a>]
<a href='https://v6.site.niucloud.com/admin' target="_blank">https://v6.site.niucloud.com/admin 账号admin 密码123456 <a href='http://v6.site.niucloud.com' target="_blank">http://v6.site.niucloud.com 账号admin 密码123456
- web端演示网址[<a href='https://v6.site.niucloud.com' target="_blank"> 查看 </a>]
<a href='https://v6.site.niucloud.com' target="_blank">https://v6.site.niucloud.com 账号admin 密码123456
- H5前端演示网址[<a href='https://v6.site.niucloud.com/wap/' target="_blank"> 查看 </a>] - H5前端演示网址[<a href='https://v6.site.niucloud.com/wap/' target="_blank"> 查看 </a>]
<a href='https://v6.site.niucloud.com/wap/' target="_blank">https://v6.site.niucloud.com/wap/ 账号admin 密码123456 <a href='https://v6.site.niucloud.com/wap/' target="_blank">https://v6.site.niucloud.com/wap/ 账号admin 密码123456
@ -62,12 +57,14 @@ niucloud-admin是一款快速开发通用管理后台框架前端采用最新
6.一切事物有个人喜好的标准,本开源代码意在分享,不喜勿喷。 6.一切事物有个人喜好的标准,本开源代码意在分享,不喜勿喷。
### 版权信息 ### 版权信息
版权所有Copyright © 2015-2030 niucloud-admin 版权所有 版权所有Copyright © 2015-2030 niucloud-admin 版权所有
All rights reserved。 All rights reserved。
杭州数字云动科技有限公司 杭州数字云动科技有限公司
杭州牛之云科技有限公司 杭州牛之云科技有限公司
提供技术支持 提供技术支持

View File

@ -0,0 +1,34 @@
// vite.config.ts
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "file:///G:/www/niucloud-admin-niushop-v6/admin/node_modules/vite/dist/node/index.js";
import vue from "file:///G:/www/niucloud-admin-niushop-v6/admin/node_modules/@vitejs/plugin-vue/dist/index.mjs";
import AutoImport from "file:///G:/www/niucloud-admin-niushop-v6/admin/node_modules/unplugin-auto-import/dist/vite.js";
import Components from "file:///G:/www/niucloud-admin-niushop-v6/admin/node_modules/unplugin-vue-components/dist/vite.mjs";
import { ElementPlusResolver } from "file:///G:/www/niucloud-admin-niushop-v6/admin/node_modules/unplugin-vue-components/dist/resolvers.mjs";
var __vite_injected_original_import_meta_url = "file:///G:/www/niucloud-admin-niushop-v6/admin/vite.config.ts";
var vite_config_default = defineConfig({
base: "",
server: {
host: "0.0.0.0"
},
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()]
}),
Components({
resolvers: [ElementPlusResolver()]
})
],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", __vite_injected_original_import_meta_url)),
"assets": fileURLToPath(new URL("./src/assets", __vite_injected_original_import_meta_url)),
"vue-i18n": "vue-i18n/dist/vue-i18n.cjs.js"
}
}
});
export {
vite_config_default as default
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJHOlxcXFx3d3dcXFxcbml1Y2xvdWQtYWRtaW4tbml1c2hvcC12NlxcXFxhZG1pblwiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiRzpcXFxcd3d3XFxcXG5pdWNsb3VkLWFkbWluLW5pdXNob3AtdjZcXFxcYWRtaW5cXFxcdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL0c6L3d3dy9uaXVjbG91ZC1hZG1pbi1uaXVzaG9wLXY2L2FkbWluL3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZmlsZVVSTFRvUGF0aCwgVVJMIH0gZnJvbSBcIm5vZGU6dXJsXCJcclxuaW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHZ1ZSBmcm9tICdAdml0ZWpzL3BsdWdpbi12dWUnXHJcbmltcG9ydCBBdXRvSW1wb3J0IGZyb20gJ3VucGx1Z2luLWF1dG8taW1wb3J0L3ZpdGUnXHJcbmltcG9ydCBDb21wb25lbnRzIGZyb20gJ3VucGx1Z2luLXZ1ZS1jb21wb25lbnRzL3ZpdGUnXHJcbmltcG9ydCB7IEVsZW1lbnRQbHVzUmVzb2x2ZXIgfSBmcm9tICd1bnBsdWdpbi12dWUtY29tcG9uZW50cy9yZXNvbHZlcnMnXHJcblxyXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xyXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xyXG4gICAgYmFzZTogJycsXHJcbiAgICBzZXJ2ZXI6IHtcclxuICAgICAgICBob3N0OiAnMC4wLjAuMCdcclxuICAgIH0sXHJcbiAgICBwbHVnaW5zOiBbXHJcbiAgICAgICAgdnVlKCksXHJcbiAgICAgICAgQXV0b0ltcG9ydCh7XHJcbiAgICAgICAgICAgIHJlc29sdmVyczogW0VsZW1lbnRQbHVzUmVzb2x2ZXIoKV1cclxuICAgICAgICB9KSxcclxuICAgICAgICBDb21wb25lbnRzKHtcclxuICAgICAgICAgICAgcmVzb2x2ZXJzOiBbRWxlbWVudFBsdXNSZXNvbHZlcigpXVxyXG4gICAgICAgIH0pXHJcbiAgICBdLFxyXG4gICAgcmVzb2x2ZToge1xyXG4gICAgICAgIGFsaWFzOiB7XHJcbiAgICAgICAgICAgICdAJzogZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuL3NyYycsIGltcG9ydC5tZXRhLnVybCkpLFxyXG4gICAgICAgICAgICAnYXNzZXRzJzogZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuL3NyYy9hc3NldHMnLCBpbXBvcnQubWV0YS51cmwpKSxcclxuICAgICAgICAgICAgJ3Z1ZS1pMThuJzogJ3Z1ZS1pMThuL2Rpc3QvdnVlLWkxOG4uY2pzLmpzJ1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufSlcclxuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUE0UyxTQUFTLGVBQWUsV0FBVztBQUMvVSxTQUFTLG9CQUFvQjtBQUM3QixPQUFPLFNBQVM7QUFDaEIsT0FBTyxnQkFBZ0I7QUFDdkIsT0FBTyxnQkFBZ0I7QUFDdkIsU0FBUywyQkFBMkI7QUFMdUosSUFBTSwyQ0FBMkM7QUFRNU8sSUFBTyxzQkFBUSxhQUFhO0FBQUEsRUFDeEIsTUFBTTtBQUFBLEVBQ04sUUFBUTtBQUFBLElBQ0osTUFBTTtBQUFBLEVBQ1Y7QUFBQSxFQUNBLFNBQVM7QUFBQSxJQUNMLElBQUk7QUFBQSxJQUNKLFdBQVc7QUFBQSxNQUNQLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQztBQUFBLElBQ3JDLENBQUM7QUFBQSxJQUNELFdBQVc7QUFBQSxNQUNQLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQztBQUFBLElBQ3JDLENBQUM7QUFBQSxFQUNMO0FBQUEsRUFDQSxTQUFTO0FBQUEsSUFDTCxPQUFPO0FBQUEsTUFDSCxLQUFLLGNBQWMsSUFBSSxJQUFJLFNBQVMsd0NBQWUsQ0FBQztBQUFBLE1BQ3BELFVBQVUsY0FBYyxJQUFJLElBQUksZ0JBQWdCLHdDQUFlLENBQUM7QUFBQSxNQUNoRSxZQUFZO0FBQUEsSUFDaEI7QUFBQSxFQUNKO0FBQ0osQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K

0
nginx.htaccess Normal file
View File

View File

@ -1 +1 @@
APP_DEBUG = true [APP] DEFAULT_TIMEZONE = Asia/Shanghai AUTH_KEY = {auth_key} PRODUCT_KEY = {product_key} [DATABASE] TYPE = mysql HOSTNAME = {dbhost} DATABASE = {dbname} USERNAME = {dbuser} PASSWORD = {dbpwd} HOSTPORT = {dbport} PREFIX = {dbprefix} CHARSET = utf8mb4 DEBUG = false [REDIS] REDIS_HOSTNAME = 127.0.0.1 PORT = 6379 REDIS_PASSWORD = SELECT = 0 [QUEUE] state = false [LANG] default_lang = zh-cn [SYSTEM] ADMIN_TOKEN_NAME = token API_TOKEN_NAME = token ADMIN_TOKEN_EXPIRE_TIME = 604800 API_TOKEN_EXPIRE_TIME = 2592000 LANG_NAME = lang CHANNEL_NAME = channel ADMIN_DOMAIN = WAP_DOMAIN = WEB_DOMAIN = [NIUCLOUD] code = secret = APP_DEBUG = false [APP] DEFAULT_TIMEZONE = Asia/Shanghai AUTH_KEY = {auth_key} PRODUCT_KEY = {product_key} [DATABASE] TYPE = mysql HOSTNAME = {dbhost} DATABASE = {dbname} USERNAME = {dbuser} PASSWORD = {dbpwd} HOSTPORT = {dbport} PREFIX = {dbprefix} CHARSET = utf8mb4 DEBUG = false [REDIS] REDIS_HOSTNAME = 127.0.0.1 PORT = 6379 REDIS_PASSWORD = SELECT = 0 [QUEUE] state = false [LANG] default_lang = zh-cn [SYSTEM] ADMIN_TOKEN_NAME = token API_TOKEN_NAME = token ADMIN_TOKEN_EXPIRE_TIME = 604800 API_TOKEN_EXPIRE_TIME = 2592000 LANG_NAME = lang CHANNEL_NAME = channel ADMIN_DOMAIN = WAP_DOMAIN = WEB_DOMAIN = [NIUCLOUD] code = secret =

View File

@ -1,5 +1,5 @@
<?php <?php
return [ return [
'version' => '1.6.2', 'version' => '1.6.3',
'code' => '202606060001' 'code' => '202606270001'
]; ];

View File

@ -2,3 +2,6 @@
upload upload
nginx.htaccess nginx.htaccess
.htaccess .htaccess
admin
wap
web

View File

@ -1,8 +1,8 @@
<IfModule mod_rewrite.c> <ifModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews Options +FollowSymlinks -Multiviews
RewriteEngine On RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L] RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
RewriteEngine on RewriteCond % !^$ RewriteEngine on RewriteCond % !^$
</IfModule> </ifModule>

View File

@ -5,7 +5,7 @@
<link rel="icon" type="image" href="/admin/niucloud.ico" /> <link rel="icon" type="image" href="/admin/niucloud.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title> <title></title>
<script type="module" crossorigin src="/admin/assets/index-22b96767.js"></script> <script type="module" crossorigin src="/admin/assets/index-60b5b21e.js"></script>
<link rel="stylesheet" href="/admin/assets/index-6e9046b8.css"> <link rel="stylesheet" href="/admin/assets/index-6e9046b8.css">
</head> </head>
<body> <body>

View File

@ -1,4 +1,4 @@
location /{ location / {
if (!-e $request_filename) { if (!-e $request_filename) {
rewrite ^(.*)$ /index.php/$1 last; break; rewrite ^(.*)$ /index.php/$1 last; break;
} }

View File

@ -870,9 +870,13 @@
window.postMessage({ type: 'tianmap:select', data: payload }, '*'); window.postMessage({ type: 'tianmap:select', data: payload }, '*');
// alert('已选择坐标:' + selectedLongitude.toFixed(6) + ',' + selectedLatitude.toFixed(6)); // alert('已选择坐标:' + selectedLongitude.toFixed(6) + ',' + selectedLatitude.toFixed(6));
} }
document.addEventListener('DOMContentLoaded', function() {
setTimeout(onLoad, 100);
});
</script> </script>
</head> </head>
<body onLoad="onLoad()"> <body>
<div class="page"> <div class="page">
<div class="map-wrap"> <div class="map-wrap">
<div id="mapDiv"></div> <div id="mapDiv"></div>

View File

@ -14,7 +14,7 @@
<title></title> <title></title>
<!--preload-links--> <!--preload-links-->
<!--app-context--> <!--app-context-->
<script type="module" crossorigin src="/wap/assets/index-a4393c74.js"></script> <script type="module" crossorigin src="/wap/assets/index-1e2462dd.js"></script>
<link rel="stylesheet" href="/wap/assets/index-5143bf90.css"> <link rel="stylesheet" href="/wap/assets/index-5143bf90.css">
</head> </head>
<body> <body>

View File

@ -123,7 +123,6 @@
<template v-if="component.componentName == 'Text'"> <template v-if="component.componentName == 'Text'">
<diy-text ref="diyTextRef" :component="component" :global="data.global" :index="index" :scrollBool="diyGroup.componentsScrollBool.Text" @update:componentIsShow="component.componentIsShow = $event" /> <diy-text ref="diyTextRef" :component="component" :global="data.global" :index="index" :scrollBool="diyGroup.componentsScrollBool.Text" @update:componentIsShow="component.componentIsShow = $event" />
</template> </template>
</view> </view>
</view> </view>
</template> </template>

View File

@ -85,6 +85,8 @@ import useSystemStore from '@/stores/system';
import { useLocation } from '@/hooks/useLocation' import { useLocation } from '@/hooks/useLocation'
const systemStore = useSystemStore(); const systemStore = useSystemStore();
const { refresh: refreshLocation } = useLocation(true);
const formData: any = ref({ const formData: any = ref({
id: 0, id: 0,
name: '', name: '',
@ -111,6 +113,7 @@ const isSelectMap = ref(2) // 值为1该地址需要有经纬度反之不
const wxPrivacyPopupRef: any = ref(null) const wxPrivacyPopupRef: any = ref(null)
onLoad((data: any) => { onLoad((data: any) => {
refreshLocation();
isSelectMap.value = data.isSelectMap || ''; isSelectMap.value = data.isSelectMap || '';
const selectAddress = uni.getStorageSync('selectAddressCallback') const selectAddress = uni.getStorageSync('selectAddressCallback')
if (data.id) { if (data.id) {
@ -260,8 +263,12 @@ const save = () => {
// //
const chooseLocation = () => { const chooseLocation = () => {
let latitude = systemStore.diyAddressInfo ? systemStore.diyAddressInfo.latitude : ''; //
let longitude = systemStore.diyAddressInfo ? systemStore.diyAddressInfo.longitude : ''; const latitude = systemStore.diyAddressInfo?.latitude ?? ''
const longitude = systemStore.diyAddressInfo?.longitude ?? ''
// let latitude = systemStore.diyAddressInfo ? systemStore.diyAddressInfo.latitude : '';
// let longitude = systemStore.diyAddressInfo ? systemStore.diyAddressInfo.longitude : '';
// #ifndef H5 // #ifndef H5
uni.chooseLocation({ uni.chooseLocation({
@ -276,6 +283,12 @@ const chooseLocation = () => {
if (res.latitude && res.longitude) { if (res.latitude && res.longitude) {
let latng = res.latitude + ',' + res.longitude; let latng = res.latitude + ',' + res.longitude;
getAddress(latng); getAddress(latng);
// +
systemStore.setAddressInfo({
latitude: res.latitude,
longitude: res.longitude,
address: res.address
})
} }
}, },
fail: (res) => { fail: (res) => {
@ -283,12 +296,15 @@ const chooseLocation = () => {
if (res.errMsg && res.errno) { if (res.errMsg && res.errno) {
if (res.errno == 104) { if (res.errno == 104) {
let msg = '用户未授权隐私权限,选择位置失败'; let msg = '用户未授权隐私权限,选择位置失败';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' })
console.log(msg)
} else if (res.errno == 112) { } else if (res.errno == 112) {
let msg = '隐私协议中未声明,打开地图选择位置失败'; let msg = '隐私协议中未声明,打开地图选择位置失败';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' })
console.log(msg)
} else { } else {
uni.showToast({ title: res.errMsg, icon: 'none' }) // uni.showToast({ title: res.errMsg, icon: 'none' })
console.log(res.errMsg)
} }
} }
} }
@ -385,7 +401,7 @@ const choosegAddress = () =>{
// idid // idid
formData.value.city_id = findIdByNameAndParentId(areaTree.value, res.cityName, formData.value.province_id); formData.value.city_id = findIdByNameAndParentId(areaTree.value, res.cityName, formData.value.province_id);
// idid // idid
formData.value.district_id = findIdByNameAndParentId(areaTree.value, res.countyName, formData.value.cityId); formData.value.district_id = findIdByNameAndParentId(areaTree.value, res.countyName, formData.value.city_id);
}, },
fail(err) { fail(err) {
loadingchoosegAddress.value = false loadingchoosegAddress.value = false
@ -393,7 +409,14 @@ const choosegAddress = () =>{
}); });
} }
onMounted(()=>{ onMounted(async ()=>{
//
const cacheLocation = uni.getStorageSync('location_address')
if(cacheLocation && Object.keys(cacheLocation).length) {
//
systemStore.setAddressInfo(cacheLocation)
}
// #ifdef MP // #ifdef MP
uni.authorize({ uni.authorize({
scope: 'scope.userLocation', scope: 'scope.userLocation',
@ -410,7 +433,7 @@ onMounted(()=>{
success: (settingRes) => { success: (settingRes) => {
if (settingRes.authSetting['scope.userLocation']) { if (settingRes.authSetting['scope.userLocation']) {
const locationVal = useLocation(true); const locationVal = useLocation(true);
locationVal.init(); locationVal.refresh();
} }
} }
}); });

View File

@ -205,15 +205,19 @@ const savePoster = () => {
fail: (err) => { fail: (err) => {
if (err.errno == 104) { if (err.errno == 104) {
let msg = '用户未授权隐私权限,将图像保存到相册失败'; let msg = '用户未授权隐私权限,将图像保存到相册失败';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' })
console.log(msg)
} else if (err.errMsg == "saveImageToPhotosAlbum:fail auth deny" || } else if (err.errMsg == "saveImageToPhotosAlbum:fail auth deny" ||
err.errMsg == "saveImageToPhotosAlbum:fail:auth denied") { err.errMsg == "saveImageToPhotosAlbum:fail:auth denied") {
show.value = true; show.value = true;
console.log(err.errMsg)
} else if (err.errMsg == "saveImageToPhotosAlbum:fail cancel") { } else if (err.errMsg == "saveImageToPhotosAlbum:fail cancel") {
let msg = '用户取消将图片保存到相册'; let msg = '用户取消将图片保存到相册';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' })
console.log(msg)
} else { } else {
uni.showToast({ title: err.errMsg, icon: 'none' }) // uni.showToast({ title: err.errMsg, icon: 'none' })
console.log(err.errMsg)
} }
} }
}); });

View File

@ -4,6 +4,10 @@ import { getAddressByLatlng } from '@/app/api/system';
import wechat from '@/utils/wechat' import wechat from '@/utils/wechat'
import useSystemStore from '@/stores/system'; import useSystemStore from '@/stores/system';
// 单例定位服务
// 使用全局 Promise 确保整个应用中只有一个定位请求在执行
let locationPromise: Promise<void> | null = null;
export function useLocation(isOpenLocation: any) { export function useLocation(isOpenLocation: any) {
const systemStore = useSystemStore(); const systemStore = useSystemStore();
@ -13,6 +17,80 @@ export function useLocation(isOpenLocation: any) {
isOpen = false; isOpen = false;
} }
const init = () => {
if (!isOpen) return false;
// 使用 locationPromise 作为唯一的锁源
if (locationPromise) {
return;
}
// 立即设置空 Promise 作为锁
locationPromise = new Promise<void>(() => {});
// 排除手动地图选择位置的情况
if (!uni.getStorageSync('manually_select_location_from_map')) {
// #ifdef H5
if (isWeixinBrowser() && systemStore.mapConfig.is_open && !uni.getStorageSync('location_address')) {
wechat.init(() => {
wechat.getLocation(res => {
locationPromise = null;
let latlng = res.latitude + ',' + res.longitude;
getAddressByLatlngFn(latlng);
});
});
} else {
locationPromise = null;
}
// #endif
// #ifndef H5
if (systemStore.mapConfig.is_open && !uni.getStorageSync('location_address')) {
uni.getLocation({
// #ifndef APP-PLUS
type: 'gcj02',
// #endif
success: res => {
locationPromise = null;
let latlng = res.latitude + ',' + res.longitude;
getAddressByLatlngFn(latlng);
},
fail: (res) => {
locationPromise = null;
// uni.showToast({ title: res.errMsg, icon: 'none', duration: 15000 });
systemStore.defaultPositionAddress = '定位失败';
if (res.errno) {
if (res.errno == 104) {
let msg = '用户未授权隐私权限,获取位置失败';
// uni.showToast({ title: msg, icon: 'none' });
console.log(msg)
} else if (res.errno == 112) {
let msg = '隐私协议中未声明,获取位置失败';
// uni.showToast({ title: msg, icon: 'none' });
console.log(msg)
}
}
if (res.errMsg) {
if (res.errMsg.indexOf('getLocation:fail') != -1 || res.errMsg.indexOf('deny') != -1 || res.errMsg.indexOf('denied') != -1) {
let msg = '用户未授权获取位置权限,将无法提供服务';
// uni.showToast({ title: msg, icon: 'none' });
console.log(msg)
} else {
// uni.showToast({ title: res.errMsg, icon: 'none' });
console.log(res.errMsg)
}
}
}
});
} else {
locationPromise = null;
}
// #endif
} else {
locationPromise = null;
}
};
// 监听页面加载 // 监听页面加载
const onLoadLifeCycle = (callback: any = '') => { const onLoadLifeCycle = (callback: any = '') => {
onLoad((option: any) => { onLoad((option: any) => {
@ -25,76 +103,112 @@ export function useLocation(isOpenLocation: any) {
}); });
} }
const init = () => { // 刷新页面时需要调用的
const refreshLocation = () => {
if (!isOpen) return false; if (!isOpen) return false;
// 使用 locationPromise 作为唯一的锁源
// 如果已经有定位在进行,直接返回
if (locationPromise) {
return;
}
// 立即设置空 Promise 作为锁(这是关键!必须在任何检查之前设置)
// 第二个调用者会在上面的检查中看到 locationPromise 已存在,直接返回
locationPromise = new Promise<void>(() => {});
// 只读取一次本地缓存,减少重复存储调用
const locationCache = uni.getStorageSync('location_address');
const manualSelect = uni.getStorageSync('manually_select_location_from_map');
// 存在手动选点标记,直接终止逻辑
if (manualSelect) {
locationPromise = null;
return;
}
// 有定位缓存
if (locationCache) {
const cacheInfo = locationStorage();
// 缓存未过期,恢复定位信息
if (!cacheInfo.is_expired) {
// 检查经纬度是否有效非空且非0
const hasValidLatLng = locationCache.latitude && locationCache.longitude &&
locationCache.latitude !== 0 && locationCache.longitude !== 0;
if (hasValidLatLng) {
systemStore.setAddressInfo(locationCache);
locationPromise = null;
return; // 有有效缓存,直接返回,不触发定位
}
// 经纬度无效,继续往下走重新定位
}
// 缓存过期或经纬度无效,删除缓存
uni.removeStorageSync('location_address');
}
// 无缓存或缓存无效/过期,直接执行定位
// 排除手动地图选择位置的情况 // 排除手动地图选择位置的情况
if (!uni.getStorageSync('manually_select_location_from_map')) { if (!uni.getStorageSync('manually_select_location_from_map')) {
// #ifdef H5 // #ifdef H5
if (isWeixinBrowser() && systemStore.mapConfig.is_open && !uni.getStorageSync('location_address')) { if (isWeixinBrowser() && systemStore.mapConfig.is_open) {
wechat.init(() => { wechat.init(() => {
wechat.getLocation(res => { wechat.getLocation(res => {
let latlng = res.latitude + ',' + res.longitude; // 纬度浮点数范围为90 ~ -90经度浮点数范围为180 ~ -180 locationPromise = null;
getAddressByLatlngFn(latlng) let latlng = res.latitude + ',' + res.longitude;
}) getAddressByLatlngFn(latlng);
}); });
});
} else {
locationPromise = null;
} }
// #endif // #endif
// #ifndef H5 // #ifndef H5
if (systemStore.mapConfig.is_open && !uni.getStorageSync('location_address')) { if (systemStore.mapConfig.is_open) {
uni.getLocation({ uni.getLocation({
// #ifndef APP-PLUS // #ifndef APP-PLUS
type: 'gcj02', type: 'gcj02',
// #endif // #endif
success: res => { success: res => {
let latlng = res.latitude + ',' + res.longitude; // 纬度浮点数范围为90 ~ -90经度浮点数范围为180 ~ -180 locationPromise = null;
let latlng = res.latitude + ',' + res.longitude;
getAddressByLatlngFn(latlng); getAddressByLatlngFn(latlng);
}, },
fail: (res) => { fail: (res) => {
uni.showToast({ title: res.errMsg, icon: 'none', duration: 15000 }) locationPromise = null;
// uni.showToast({ title: res.errMsg, icon: 'none', duration: 15000 });
systemStore.defaultPositionAddress = '定位失败'; systemStore.defaultPositionAddress = '定位失败';
if (res.errno) { if (res.errno) {
if (res.errno == 104) { if (res.errno == 104) {
let msg = '用户未授权隐私权限,获取位置失败'; let msg = '用户未授权隐私权限,获取位置失败';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' });
console.log(msg)
} else if (res.errno == 112) { } else if (res.errno == 112) {
let msg = '隐私协议中未声明,获取位置失败'; let msg = '隐私协议中未声明,获取位置失败';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' });
console.log(msg)
} }
} }
if (res.errMsg) { if (res.errMsg) {
if (res.errMsg.indexOf('getLocation:fail') != -1 || res.errMsg.indexOf('deny') != -1 || res.errMsg.indexOf('denied') != -1) { if (res.errMsg.indexOf('getLocation:fail') != -1 || res.errMsg.indexOf('deny') != -1 || res.errMsg.indexOf('denied') != -1) {
let msg = '用户未授权获取位置权限,将无法提供服务'; let msg = '用户未授权获取位置权限,将无法提供服务';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' });
console.log(msg)
} else { } else {
uni.showToast({ title: res.errMsg, icon: 'none' }) // uni.showToast({ title: res.errMsg, icon: 'none' });
console.log(res.errMsg)
} }
} }
} }
}); });
} else {
locationPromise = null;
} }
// #endif // #endif
}
}
// 刷新页面时需要调用的
const refreshLocation = () => {
if (!isOpen) return false;
if (!uni.getStorageSync('manually_select_location_from_map') && uni.getStorageSync('location_address')) {
if (locationStorage() && !locationStorage().is_expired) {
systemStore.setAddressInfo(uni.getStorageSync('location_address'))
} else { } else {
uni.removeStorageSync('location_address'); locationPromise = null;
}
}
// 定位信息过期后,重新获取定位
if (!uni.getStorageSync('manually_select_location_from_map') && locationStorage() && locationStorage().is_expired) {
init();
}
} }
};
// 通过经纬度获取地址信息 // 通过经纬度获取地址信息
const getAddressByLatlngFn = (latlng: any = '') => { const getAddressByLatlngFn = (latlng: any = '') => {
@ -161,12 +275,15 @@ export function useLocation(isOpenLocation: any) {
if (res.errMsg && res.errno) { if (res.errMsg && res.errno) {
if (res.errno == 104) { if (res.errno == 104) {
let msg = '用户未授权隐私权限,选择位置失败'; let msg = '用户未授权隐私权限,选择位置失败';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' })
console.log(msg)
} else if (res.errno == 112) { } else if (res.errno == 112) {
let msg = '隐私协议中未声明,打开地图选择位置失败'; let msg = '隐私协议中未声明,打开地图选择位置失败';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' })
console.log(msg)
} else { } else {
uni.showToast({ title: res.errMsg, icon: 'none' }) // uni.showToast({ title: res.errMsg, icon: 'none' })
console.log(res.errMsg)
} }
} }
} }

View File

@ -210,6 +210,7 @@
], ],
"subPackages": [ "subPackages": [
// {{ PAGE_BEGAIN }} // {{ PAGE_BEGAIN }}
// {{ PAGE_END }} // {{ PAGE_END }}
{ {
"root": "app/components", "root": "app/components",

View File

@ -61,7 +61,7 @@ const useSystemStore = defineStore('system', {
}, },
shareCallback: null, shareCallback: null,
defaultPositionAddress: '定位中', defaultPositionAddress: '定位中',
diyAddressInfo: null, diyAddressInfo: {},
currTabbar: { currTabbar: {
path: '', path: '',
query: {} query: {}

View File

@ -576,12 +576,15 @@ export function copy(value: any, callback: any) {
if (res.errMsg && res.errno) { if (res.errMsg && res.errno) {
if (res.errno == 104) { if (res.errno == 104) {
let msg = '用户未授权隐私权限,设置剪贴板数据失败'; let msg = '用户未授权隐私权限,设置剪贴板数据失败';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' })
console.log(msg)
} else if (res.errno == 112) { } else if (res.errno == 112) {
let msg = '隐私协议中未声明,设置剪贴板数据失败'; let msg = '隐私协议中未声明,设置剪贴板数据失败';
uni.showToast({ title: msg, icon: 'none' }) // uni.showToast({ title: msg, icon: 'none' })
console.log(msg)
} else { } else {
uni.showToast({ title: res.errMsg, icon: 'none' }) // uni.showToast({ title: res.errMsg, icon: 'none' })
console.log(res.errMsg)
} }
} }
} }
@ -845,7 +848,7 @@ export function openMapSelector(backurl: string, params = '') {
// 天地图的位置选择器URL // 天地图的位置选择器URL
// 注意天地图的位置选择器API可能与腾讯地图不同需要根据实际API文档调整 // 注意天地图的位置选择器API可能与腾讯地图不同需要根据实际API文档调整
const baseUrl = (import.meta.env.VITE_APP_BASE_URL || `${ location.origin }`).replace(/\/api\/$/, '') const baseUrl = (import.meta.env.VITE_APP_BASE_URL || `${ location.origin }`).replace(/\/api\/$/, '')
const url = baseUrl + `/tianmap/index.html?search=1&type=0&backurl=${ encodeURIComponent(backurl) }&key=${ tiandituKey }` + (params ? '&' + params : '') const url = baseUrl + `/tianmap/index.html?search=1&type=0&backurl=${ encodeURIComponent(backurl) }&key=${ tiandituKey }&t=${Date.now()}` + (params ? '&' + params : '')
window.location.href = url; window.location.href = url;
} }
} }