mirror of
https://gitee.com/niucloud-team/niucloud-admin.git
synced 2026-08-19 11:19:02 +00:00
版本更新
This commit is contained in:
parent
02f2d8125c
commit
769ce650f2
2
.gitignore
vendored
2
.gitignore
vendored
@ -18,5 +18,5 @@ bin-release/
|
||||
# information for Eclipse / Flash Builder.
|
||||
|
||||
/.idea
|
||||
/upgrade
|
||||
niucloud/public/.htaccess
|
||||
admin/.env.development
|
||||
|
||||
8
.htaccess
Normal file
8
.htaccess
Normal 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
36
README.en.md
Normal 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/)
|
||||
35
README.md
35
README.md
@ -1,11 +1,11 @@
|
||||

|
||||

|
||||
|
||||
### niucloud-admin是什么?
|
||||
### niucloud-admin是什么?
|
||||
niucloud-admin是一款快速开发通用管理后台框架,前端采用最新的技术栈Vite+TypeScript+Vue3+ElementPlus最流行技术架构,后台结合PHP8、Java SDK、Python等主流后端语言搭建,内置集成用户权限、代码生成器、表单设计、云存储、短信发送、素材中心、微信及公众号、Api模块一系列开箱即用功能,是一款快速可以开发企业级应用的软件系统。
|
||||
|
||||
### niucloud-admin采用的技术亮点
|
||||
### niucloud-admin采用的技术亮点
|
||||
|
||||
- 后台php采用thinkphp8+php8+mysql,支持composer快速安装扩展,支持redis缓存以及消息队列,支持多语言设计开发,同时开发采用严格的restful的api设计开发。
|
||||
- 后台php采用thinkphp8+php8+mysql,支持composer快速安装扩展,支持redis缓存以及消息队列,支持多语言设计开发,同时开发采用严格的restful的api设计开发。
|
||||
|
||||
- 后台前后端分离采用element-plus、vue3.0、typescript、vite、pina等前端技术,同时使用i18n支持国际化多语言开发。
|
||||
|
||||
@ -32,25 +32,20 @@ niucloud-admin是一款快速开发通用管理后台框架,前端采用最新
|
||||
### 操作指南
|
||||
[官网地址](https://www.niucloud.com)
|
||||
| [服务市场](https://www.niucloud.com)
|
||||
| [使用手册](https://www.niucloud.com/doc)
|
||||
| [二开手册](https://www.niucloud.com/doc)
|
||||
| [开发视频](https://www.niucloud.com/doc)
|
||||
| [API接口手册](https://api.niucloud.com/apidoc.html?target_id=001)
|
||||
| [论坛地址](https://niucloud.com/bbs)
|
||||
| [使用手册](https://www.kancloud.cn/niucloud/niucloud-admin-develop/3153336)
|
||||
| [二开手册](https://www.kancloud.cn/niucloud/niucloud-admin-develop/3153336)
|
||||
| [API接口手册](https://www.niucloud.com/apidoc.html)
|
||||
| [论坛地址](https://www.niucloud.com/bbs)
|
||||
|
||||
### 演示地址
|
||||
- 管理后台演示网址:[<a href='https://v6.site.niucloud.com/admin' target="_blank"> 查看 </a>]
|
||||
<a href='https://v6.site.niucloud.com/admin' target="_blank">https://v6.site.niucloud.com/admin 账号: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
|
||||
|
||||
- 管理后台演示网址:[<a href='http://v6.site.niucloud.com' target="_blank"> 查看 </a>]
|
||||
<a href='http://v6.site.niucloud.com' target="_blank">http://v6.site.niucloud.com 账号:admin 密码:123456
|
||||
- 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
|
||||
|
||||
### 开源使用须知
|
||||
### 开源使用须知
|
||||
|
||||
1.允许用于个人学习、毕业设计、教学案例、公益事业、商业使用;
|
||||
1.允许用于个人学习、毕业设计、教学案例、公益事业、商业使用;
|
||||
|
||||
2.本框架应用源代码所有权和著作权归niucloud官方所有,基于niucloud-admin框架开发的应用,所有权和著作权归应用开发商所有。但必须明确声明是基于niucloud-admin框架开发,请自觉遵守,否则产生的一切任何后果责任由侵权者自负;
|
||||
|
||||
@ -62,12 +57,14 @@ niucloud-admin是一款快速开发通用管理后台框架,前端采用最新
|
||||
|
||||
6.一切事物有个人喜好的标准,本开源代码意在分享,不喜勿喷。
|
||||
|
||||
|
||||
|
||||
### 版权信息
|
||||
版权所有Copyright © 2015-2030 niucloud-admin 版权所有
|
||||
|
||||
All rights reserved。
|
||||
|
||||
|
||||
杭州数字云动科技有限公司
|
||||
杭州牛之云科技有限公司
|
||||
提供技术支持
|
||||
|
||||
提供技术支持
|
||||
34
admin/vite.config.ts.timestamp-1779333463627.mjs
Normal file
34
admin/vite.config.ts.timestamp-1779333463627.mjs
Normal 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
0
nginx.htaccess
Normal 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 =
|
||||
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
return [
|
||||
'version' => '1.6.2',
|
||||
'code' => '202606060001'
|
||||
'version' => '1.6.3',
|
||||
'code' => '202606270001'
|
||||
];
|
||||
5
niucloud/public/.gitignore
vendored
5
niucloud/public/.gitignore
vendored
@ -1,4 +1,7 @@
|
||||
/.htaccess
|
||||
upload
|
||||
nginx.htaccess
|
||||
.htaccess
|
||||
.htaccess
|
||||
admin
|
||||
wap
|
||||
web
|
||||
|
||||
@ -1,8 +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>
|
||||
<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>
|
||||
@ -5,7 +5,7 @@
|
||||
<link rel="icon" type="image" href="/admin/niucloud.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<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">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
location /{
|
||||
location / {
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^(.*)$ /index.php/$1 last; break;
|
||||
}
|
||||
|
||||
@ -870,9 +870,13 @@
|
||||
window.postMessage({ type: 'tianmap:select', data: payload }, '*');
|
||||
// alert('已选择坐标:' + selectedLongitude.toFixed(6) + ',' + selectedLatitude.toFixed(6));
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
setTimeout(onLoad, 100);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body onLoad="onLoad()">
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="map-wrap">
|
||||
<div id="mapDiv"></div>
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
<title></title>
|
||||
<!--preload-links-->
|
||||
<!--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">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@ -16,4 +16,4 @@ VITE_REQUEST_HEADER_TOKEN_KEY='token'
|
||||
VITE_REQUEST_HEADER_CHANNEL_KEY='channel'
|
||||
|
||||
# 应用版本
|
||||
VITE_APP_VERSION='1.0.1'
|
||||
VITE_APP_VERSION='1.0.1'
|
||||
|
||||
@ -123,7 +123,6 @@
|
||||
<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" />
|
||||
</template>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -85,6 +85,8 @@ import useSystemStore from '@/stores/system';
|
||||
import { useLocation } from '@/hooks/useLocation'
|
||||
|
||||
const systemStore = useSystemStore();
|
||||
const { refresh: refreshLocation } = useLocation(true);
|
||||
|
||||
const formData: any = ref({
|
||||
id: 0,
|
||||
name: '',
|
||||
@ -111,6 +113,7 @@ const isSelectMap = ref(2) // 值为1,该地址需要有经纬度,反之不
|
||||
const wxPrivacyPopupRef: any = ref(null)
|
||||
|
||||
onLoad((data: any) => {
|
||||
refreshLocation();
|
||||
isSelectMap.value = data.isSelectMap || '';
|
||||
const selectAddress = uni.getStorageSync('selectAddressCallback')
|
||||
if (data.id) {
|
||||
@ -260,8 +263,12 @@ const save = () => {
|
||||
|
||||
// 选择地址
|
||||
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
|
||||
uni.chooseLocation({
|
||||
@ -276,6 +283,12 @@ const chooseLocation = () => {
|
||||
if (res.latitude && res.longitude) {
|
||||
let latng = res.latitude + ',' + res.longitude;
|
||||
getAddress(latng);
|
||||
// 关键:选完地址后,存入仓库 + 本地缓存
|
||||
systemStore.setAddressInfo({
|
||||
latitude: res.latitude,
|
||||
longitude: res.longitude,
|
||||
address: res.address
|
||||
})
|
||||
}
|
||||
},
|
||||
fail: (res) => {
|
||||
@ -283,12 +296,15 @@ const chooseLocation = () => {
|
||||
if (res.errMsg && res.errno) {
|
||||
if (res.errno == 104) {
|
||||
let msg = '用户未授权隐私权限,选择位置失败';
|
||||
uni.showToast({ title: msg, icon: 'none' })
|
||||
// uni.showToast({ title: msg, icon: 'none' })
|
||||
console.log(msg)
|
||||
} else if (res.errno == 112) {
|
||||
let msg = '隐私协议中未声明,打开地图选择位置失败';
|
||||
uni.showToast({ title: msg, icon: 'none' })
|
||||
// uni.showToast({ title: msg, icon: 'none' })
|
||||
console.log(msg)
|
||||
} 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 = () =>{
|
||||
// 匹配市id(基于省id)
|
||||
formData.value.city_id = findIdByNameAndParentId(areaTree.value, res.cityName, formData.value.province_id);
|
||||
// 匹配区id(基于市id)
|
||||
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) {
|
||||
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
|
||||
uni.authorize({
|
||||
scope: 'scope.userLocation',
|
||||
@ -410,7 +433,7 @@ onMounted(()=>{
|
||||
success: (settingRes) => {
|
||||
if (settingRes.authSetting['scope.userLocation']) {
|
||||
const locationVal = useLocation(true);
|
||||
locationVal.init();
|
||||
locationVal.refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -205,15 +205,19 @@ const savePoster = () => {
|
||||
fail: (err) => {
|
||||
if (err.errno == 104) {
|
||||
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" ||
|
||||
err.errMsg == "saveImageToPhotosAlbum:fail:auth denied") {
|
||||
show.value = true;
|
||||
console.log(err.errMsg)
|
||||
} else if (err.errMsg == "saveImageToPhotosAlbum:fail cancel") {
|
||||
let msg = '用户取消将图片保存到相册';
|
||||
uni.showToast({ title: msg, icon: 'none' })
|
||||
// uni.showToast({ title: msg, icon: 'none' })
|
||||
console.log(msg)
|
||||
} else {
|
||||
uni.showToast({ title: err.errMsg, icon: 'none' })
|
||||
// uni.showToast({ title: err.errMsg, icon: 'none' })
|
||||
console.log(err.errMsg)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -4,6 +4,10 @@ import { getAddressByLatlng } from '@/app/api/system';
|
||||
import wechat from '@/utils/wechat'
|
||||
import useSystemStore from '@/stores/system';
|
||||
|
||||
// 单例定位服务
|
||||
// 使用全局 Promise 确保整个应用中只有一个定位请求在执行
|
||||
let locationPromise: Promise<void> | null = null;
|
||||
|
||||
export function useLocation(isOpenLocation: any) {
|
||||
const systemStore = useSystemStore();
|
||||
|
||||
@ -13,6 +17,80 @@ export function useLocation(isOpenLocation: any) {
|
||||
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 = '') => {
|
||||
onLoad((option: any) => {
|
||||
@ -25,76 +103,112 @@ export function useLocation(isOpenLocation: any) {
|
||||
});
|
||||
}
|
||||
|
||||
const init = () => {
|
||||
// 刷新页面时需要调用的
|
||||
const refreshLocation = () => {
|
||||
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')) {
|
||||
// #ifdef H5
|
||||
if (isWeixinBrowser() && systemStore.mapConfig.is_open && !uni.getStorageSync('location_address')) {
|
||||
if (isWeixinBrowser() && systemStore.mapConfig.is_open) {
|
||||
wechat.init(() => {
|
||||
wechat.getLocation(res => {
|
||||
let latlng = res.latitude + ',' + res.longitude; // 纬度(浮点数,范围为90 ~ -90),经度(浮点数,范围为180 ~ -180)
|
||||
getAddressByLatlngFn(latlng)
|
||||
})
|
||||
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')) {
|
||||
if (systemStore.mapConfig.is_open) {
|
||||
uni.getLocation({
|
||||
// #ifndef APP-PLUS
|
||||
type: 'gcj02',
|
||||
// #endif
|
||||
success: res => {
|
||||
let latlng = res.latitude + ',' + res.longitude; // 纬度(浮点数,范围为90 ~ -90),经度(浮点数,范围为180 ~ -180)
|
||||
locationPromise = null;
|
||||
let latlng = res.latitude + ',' + res.longitude;
|
||||
getAddressByLatlngFn(latlng);
|
||||
},
|
||||
fail: (res) => {
|
||||
uni.showToast({ title: res.errMsg, icon: 'none', duration: 15000 })
|
||||
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' })
|
||||
// uni.showToast({ title: msg, icon: 'none' });
|
||||
console.log(msg)
|
||||
} else if (res.errno == 112) {
|
||||
let msg = '隐私协议中未声明,获取位置失败';
|
||||
uni.showToast({ title: msg, icon: 'none' })
|
||||
// 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' })
|
||||
// uni.showToast({ title: msg, icon: 'none' });
|
||||
console.log(msg)
|
||||
} else {
|
||||
uni.showToast({ title: res.errMsg, icon: 'none' })
|
||||
// uni.showToast({ title: res.errMsg, icon: 'none' });
|
||||
console.log(res.errMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
locationPromise = null;
|
||||
}
|
||||
// #endif
|
||||
} else {
|
||||
locationPromise = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新页面时需要调用的
|
||||
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 {
|
||||
uni.removeStorageSync('location_address');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 定位信息过期后,重新获取定位
|
||||
if (!uni.getStorageSync('manually_select_location_from_map') && locationStorage() && locationStorage().is_expired) {
|
||||
init();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 通过经纬度获取地址信息
|
||||
const getAddressByLatlngFn = (latlng: any = '') => {
|
||||
@ -161,12 +275,15 @@ export function useLocation(isOpenLocation: any) {
|
||||
if (res.errMsg && res.errno) {
|
||||
if (res.errno == 104) {
|
||||
let msg = '用户未授权隐私权限,选择位置失败';
|
||||
uni.showToast({ title: msg, icon: 'none' })
|
||||
// uni.showToast({ title: msg, icon: 'none' })
|
||||
console.log(msg)
|
||||
} else if (res.errno == 112) {
|
||||
let msg = '隐私协议中未声明,打开地图选择位置失败';
|
||||
uni.showToast({ title: msg, icon: 'none' })
|
||||
// uni.showToast({ title: msg, icon: 'none' })
|
||||
console.log(msg)
|
||||
} else {
|
||||
uni.showToast({ title: res.errMsg, icon: 'none' })
|
||||
// uni.showToast({ title: res.errMsg, icon: 'none' })
|
||||
console.log(res.errMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,6 +210,7 @@
|
||||
],
|
||||
"subPackages": [
|
||||
// {{ PAGE_BEGAIN }}
|
||||
|
||||
// {{ PAGE_END }}
|
||||
{
|
||||
"root": "app/components",
|
||||
|
||||
@ -61,7 +61,7 @@ const useSystemStore = defineStore('system', {
|
||||
},
|
||||
shareCallback: null,
|
||||
defaultPositionAddress: '定位中',
|
||||
diyAddressInfo: null,
|
||||
diyAddressInfo: {},
|
||||
currTabbar: {
|
||||
path: '',
|
||||
query: {}
|
||||
|
||||
@ -576,12 +576,15 @@ export function copy(value: any, callback: any) {
|
||||
if (res.errMsg && res.errno) {
|
||||
if (res.errno == 104) {
|
||||
let msg = '用户未授权隐私权限,设置剪贴板数据失败';
|
||||
uni.showToast({ title: msg, icon: 'none' })
|
||||
// uni.showToast({ title: msg, icon: 'none' })
|
||||
console.log(msg)
|
||||
} else if (res.errno == 112) {
|
||||
let msg = '隐私协议中未声明,设置剪贴板数据失败';
|
||||
uni.showToast({ title: msg, icon: 'none' })
|
||||
// uni.showToast({ title: msg, icon: 'none' })
|
||||
console.log(msg)
|
||||
} 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
|
||||
// 注意:天地图的位置选择器API可能与腾讯地图不同,需要根据实际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;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user