From 8bf30fc174568eb3101e08847927965a16c0c3c0 Mon Sep 17 00:00:00 2001 From: "Mr.April" Date: Tue, 5 Aug 2025 13:38:51 +0800 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20=E4=B8=8A=E4=BC=A0=E5=9B=9E=E6=98=BE?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=B7=AF=E5=BE=84=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/.env.production | 19 ++--- web/src/api/dev/terminal/index.ts | 5 +- web/src/api/request.ts | 25 +++++- web/src/components/form/components/avatar.vue | 80 ++++++++++++++----- web/src/utils/tool.ts | 64 ++++++++++----- 5 files changed, 131 insertions(+), 62 deletions(-) diff --git a/web/.env.production b/web/.env.production index 0ed97cd..fe9e941 100644 --- a/web/.env.production +++ b/web/.env.production @@ -1,10 +1,9 @@ VITE_BASE=/ -# 接口地址 -# VITE_GLOB_API_URL=/api -#后端模式 -VITE_GLOB_API_URL=/ +# 接口地址 +VITE_GLOB_API_URL=/api +# VITE_GLOB_API_URL=useCurrentDomain #useCurrentDomain 为自动获取当前域名为base地址 # 是否开启压缩,可以设置为 none, brotli, gzip VITE_COMPRESS=none @@ -25,16 +24,8 @@ VITE_GLOB_CLIENT_KEY= X-Client-ID VITE_GLOB_ENABLE_WSS=true # wss接口地址 -# VITE_GLOB_WSS_URL=/ws - -#后端模式写全路径 -VITE_GLOB_WSS_URL=ws://127.0.0.1:3898 +VITE_GLOB_WSS_URL=/ws +# VITE_GLOB_WSS_URL=ws://127.0.0.1:3898 #useCurrentDomain 模式使用绝对url # WSS KEY VITE_GLOB_WSS_APPKEY = 60756ede2a9737a05384aad849e220f8 - - -# 线上环境接口地址 -VITE_AXIOS_BASE_URL = fetchCurrentDomain - -# VITE_AXIOS_BASE_URL = 'https://api.admin.madong.tech' \ No newline at end of file diff --git a/web/src/api/dev/terminal/index.ts b/web/src/api/dev/terminal/index.ts index 96219bd..52c66f8 100644 --- a/web/src/api/dev/terminal/index.ts +++ b/web/src/api/dev/terminal/index.ts @@ -1,6 +1,7 @@ +import { getApiBaseUrl } from './../../request'; import { requestClient } from "#/api/request"; import { useAccessStore } from "#/components/common/stores"; -import { getUrl } from "#/utils" + @@ -27,7 +28,7 @@ export class TerminalApi { const accessStore = useAccessStore(); const token = this.formatToken(accessStore.accessToken); return ( - getUrl() + this.baseUrl + '?command=' + commandKey + '&uuid=' + uuid + '&extend=' + extend + '&token=' + token + '&server=crmd' + getApiBaseUrl() + this.baseUrl + '?command=' + commandKey + '&uuid=' + uuid + '&extend=' + extend + '&token=' + token + '&server=crmd' ) } diff --git a/web/src/api/request.ts b/web/src/api/request.ts index 57c4a66..5885fb8 100644 --- a/web/src/api/request.ts +++ b/web/src/api/request.ts @@ -15,10 +15,10 @@ import { message } from 'ant-design-vue'; import { refreshTokenApi } from './core'; -const apiURL = import.meta.env.VITE_GLOB_API_URL; const clientKey = import.meta.env.VITE_GLOB_CLIENT_KEY; + function createRequestClient(baseURL: string, options?: RequestClientOptions) { const client = new RequestClient({ ...options, @@ -135,9 +135,28 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) { return client; } -export const requestClient = createRequestClient(apiURL, { + +export const getApiBaseUrl = (customValue?: string | null): string => { + if (customValue) { + return customValue === 'useCurrentDomain' + ? window.location.protocol + '//' + window.location.host + : customValue; + } + + const envValue = import.meta.env.VITE_GLOB_API_URL; + if (envValue) { + return envValue === 'useCurrentDomain' + ? window.location.protocol + '//' + window.location.host + : envValue; + } + return window.location.protocol + '//' + window.location.host; +} + + +export const requestClient = createRequestClient(getApiBaseUrl(null), { responseReturn: 'data', }); -export const baseRequestClient = new RequestClient({ baseURL: apiURL }); + +export const baseRequestClient = new RequestClient({ baseURL: getApiBaseUrl(null) }); diff --git a/web/src/components/form/components/avatar.vue b/web/src/components/form/components/avatar.vue index c05f558..c5e58a8 100644 --- a/web/src/components/form/components/avatar.vue +++ b/web/src/components/form/components/avatar.vue @@ -1,59 +1,89 @@ + + diff --git a/web/src/utils/tool.ts b/web/src/utils/tool.ts index 8b63f7b..84bf962 100644 --- a/web/src/utils/tool.ts +++ b/web/src/utils/tool.ts @@ -1,4 +1,5 @@ +import { getApiBaseUrl } from '#/api/request'; import { useSiteConfigStore } from '#/store/modules/site-config'; import type { App, Component } from 'vue'; @@ -116,24 +117,6 @@ const padStart = (str: string, maxLength: number, fillString = ' ') => { return fillString.slice(0, fillLength) + str } -/** - * 根据环境获取基础URL - * @returns - */ -export const getUrl = (): string => { - const value: string = import.meta.env.VITE_AXIOS_BASE_URL as string - return value == 'fetchCurrentDomain' ? window.location.protocol + '//' + window.location.host : value -} - - -/** - * 根据环境获取基础请求URL的端口 - */ -export const getPort = (): string => { - const url = getUrl() - return new URL(url).port -} - /** @@ -144,10 +127,9 @@ export const getPort = (): string => { */ export const fullUrl = (relativeUrl: string, domain: string = ''): string => { const siteConfig = useSiteConfigStore(); - // 1. 处理空路径直接返回域名 - if (!relativeUrl) return domain || getUrl(); + if (!relativeUrl) return domain || getApiBaseUrl(null); @@ -157,7 +139,7 @@ export const fullUrl = (relativeUrl: string, domain: string = ''): string => { if (isAbsoluteUrl || isDataUrl) return relativeUrl; // 3. 确定最终使用的域名 - const finalDomain = domain || siteConfig.state.cdn_url || getUrl(); + const finalDomain = domain || siteConfig.state.cdn_url || getApiBaseUrl(); if (!finalDomain) return relativeUrl; // 保底返回原路径 // 4. 拼接URL @@ -176,6 +158,46 @@ export const fullUrl = (relativeUrl: string, domain: string = ''): string => { }; +/** + * 移除URL中的公共路径前缀 + * @param url 待处理的URL + * @param domain 可选指定要移除的特定域名(默认自动检测) + * @returns 移除前缀后的相对路径 + */ +export const stripBaseUrl = (url: string, domain: string = ''): string => { + const siteConfig = useSiteConfigStore(); + + // 1. 处理空值 + if (!url) return ''; + + // 2. 检测不需要处理的URL类型 + const isDataUrl = /^data:image\//i.test(url); + if (isDataUrl) return url; + + // 3. 确定要移除的域名(优先级:参数指定 > CDN域名 > API域名) + const baseDomain = domain || siteConfig.state.cdn_url || getApiBaseUrl(); + if (!baseDomain) return url; + + // 4. 标准化待移除的域名(移除尾部斜杠) + const normalizedDomain = baseDomain.replace(/\/+$/, ''); + + // 5. 移除域名部分(包括协议头可选匹配) + let result = url + .replace(new RegExp(`^https?:\\/\\/${normalizedDomain}\\/?`), '') + .replace(new RegExp(`^${normalizedDomain}\\/?`), ''); + + // 6. 移除可能的CDN参数(如果来自同一CDN) + if (normalizedDomain === siteConfig.state.cdn_url && siteConfig.state.cdn_url_params) { + const paramStr = `[?&]${siteConfig.state.cdn_url_params.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`; + result = result.replace(new RegExp(`${paramStr}(?:&|$)`), ''); + } + + // 7. 确保不会返回空路径(至少保留原文件名) + return result || url.split('/').pop() || ''; +}; + + + /** * 获取一组资源的完整地址(支持字符串或数组输入) * @param relativeUrls 相对路径(支持逗号分隔字符串或数组) -- Gitee From 215c163111a0d54fca62967795fb3acbc9504395 Mon Sep 17 00:00:00 2001 From: "Mr.April" Date: Tue, 5 Aug 2025 14:03:29 +0800 Subject: [PATCH 2/5] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=9B=AA=E8=8A=B1?= =?UTF-8?q?ID=E9=87=8D=E5=A4=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/composer.lock | 10 +-- server/config/core/utils/app.php | 15 ++++ server/config/core/uuid/app.php | 15 ++++ server/config/core/uuid/snowflake.php | 20 +++++ server/core/abstract/BaseModel.php | 44 +--------- server/core/db/DataImporterService.php | 37 +-------- server/core/uuid/Snowflake.php | 106 +++++++++++++++++++++++++ 7 files changed, 169 insertions(+), 78 deletions(-) create mode 100644 server/config/core/utils/app.php create mode 100644 server/config/core/uuid/app.php create mode 100644 server/config/core/uuid/snowflake.php create mode 100644 server/core/uuid/Snowflake.php diff --git a/server/composer.lock b/server/composer.lock index 2cebef3..7f41469 100644 --- a/server/composer.lock +++ b/server/composer.lock @@ -2873,11 +2873,11 @@ }, { "name": "madong/helper", - "version": "v1.1.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://gitcode.com/motion-code/helper.git", - "reference": "d13e1d7715b02d87342419643094b53b2218adaf" + "reference": "7d6029c0e8d3e09414e5db7bae0aa8b398267276" }, "require": { "illuminate/collections": "*", @@ -2904,7 +2904,7 @@ } ], "description": "The ingen Helper Package", - "time": "2025-07-04T01:40:03+00:00" + "time": "2025-08-05T03:16:37+00:00" }, { "name": "maennchen/zipstream-php", @@ -8177,7 +8177,7 @@ "packages-dev": [], "aliases": [], "minimum-stability": "dev", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { @@ -8186,6 +8186,6 @@ "ext-pdo": "*", "ext-gd": "*" }, - "platform-dev": [], + "platform-dev": {}, "plugin-api-version": "2.6.0" } diff --git a/server/config/core/utils/app.php b/server/config/core/utils/app.php new file mode 100644 index 0000000..c9afe2b --- /dev/null +++ b/server/config/core/utils/app.php @@ -0,0 +1,15 @@ + true, +]; diff --git a/server/config/core/uuid/app.php b/server/config/core/uuid/app.php new file mode 100644 index 0000000..c9afe2b --- /dev/null +++ b/server/config/core/uuid/app.php @@ -0,0 +1,15 @@ + true, +]; diff --git a/server/config/core/uuid/snowflake.php b/server/config/core/uuid/snowflake.php new file mode 100644 index 0000000..c4c1f62 --- /dev/null +++ b/server/config/core/uuid/snowflake.php @@ -0,0 +1,20 @@ + true, + 'node_id' => 1, + 'worker_id' => null,//使用线程id + 'node_id_bits' => 3, + 'worker_id_bits' => 7, + 'sequence_bits' => 12, +]; diff --git a/server/core/abstract/BaseModel.php b/server/core/abstract/BaseModel.php index 81add97..bf988fd 100644 --- a/server/core/abstract/BaseModel.php +++ b/server/core/abstract/BaseModel.php @@ -12,24 +12,19 @@ namespace core\abstract; -use app\common\model\platform\Tenant; + use app\common\model\system\SysRecycleBin; use app\common\scopes\global\AccessScope; -use app\common\scopes\global\TenantScope; -use app\common\scopes\global\TenantSharedTableScope; use app\common\services\system\SysRecycleBinService; use Carbon\Carbon; use core\exception\handler\AdminException; +use core\uuid\Snowflake; use Illuminate\Database\Eloquent\SoftDeletes; -use core\context\TenantContext; -use madong\helper\Snowflake; use support\Container; use support\Model; class BaseModel extends Model { - private const WORKER_ID = 1; - private const DATA_CENTER_ID = 1; /** * 指明模型的ID是否自动递增。 @@ -66,12 +61,6 @@ class BaseModel extends Model */ public $timestamps = true; - /** - * 雪花算法实例 - * - * @var Snowflake|null - */ - protected static ?Snowflake $snowflake = null; public function __construct(array $data = []) { @@ -81,7 +70,7 @@ class BaseModel extends Model protected static function booted() { // 1. 默认添加 AccessScope - static::addGlobalScope(new AccessScope); +// static::addGlobalScope(new AccessScope); } protected static function boot() @@ -90,7 +79,7 @@ class BaseModel extends Model //注册创建事件 static::creating(function ($model) { if (!isset($model->{$model->getKeyName()})) { - $model->{$model->getKeyName()} = self::generateSnowflakeID(); // 生成雪花 ID + $model->{$model->getKeyName()} = Snowflake::generate() ; // 生成雪花 ID } self::setCreatedBy($model); }); @@ -278,31 +267,6 @@ class BaseModel extends Model } } - /** - * 实例化雪花算法 - * - * @return Snowflake - */ - private static function createSnowflake(): Snowflake - { - if (self::$snowflake == null) { - self::$snowflake = new Snowflake(self::WORKER_ID, self::DATA_CENTER_ID); - } - return self::$snowflake; - } - - /** - * 生成雪花ID - * - * @return int - * @throws \Exception - */ - private static function generateSnowflakeID(): int - { - $snowflake = self::createSnowflake(); - return $snowflake->nextId(); - } - private static function prepareRecycleBinData($tableData, $table, $prefix): array { return [ diff --git a/server/core/db/DataImporterService.php b/server/core/db/DataImporterService.php index 01b5e71..5617cba 100644 --- a/server/core/db/DataImporterService.php +++ b/server/core/db/DataImporterService.php @@ -12,7 +12,7 @@ namespace core\db; -use madong\helper\Snowflake; +use core\uuid\Snowflake; use PDO; /** @@ -24,35 +24,6 @@ use PDO; class DataImporterService { - private const WORKER_ID = 1; - private const DATA_CENTER_ID = 1; - - /** - * 雪花算法实例 - * - * @var Snowflake|null - */ - protected ?Snowflake $snowflake = null; - - - public function __construct() - { - $this->snowflake = new Snowflake(self::WORKER_ID, self::DATA_CENTER_ID); - } - - /** - * 生成雪花ID - * - * @return int - * @throws \Exception - */ - public function generateSnowflakeId(): int - { - $snowflake = $this->snowflake; - return $snowflake->nextId(); - } - - /** * 获取 PDO 连接的方法 * @@ -115,7 +86,7 @@ class DataImporterService if ($options['useSnowflakeId']) { $fields[] = $options['idKey']; if (empty($row[$options['idKey']])) { - $row[$options['idKey']] = $this->generateSnowflakeId(); + $row[$options['idKey']] = Snowflake::generate(); } } elseif ($options['useAutoIncrement']) { unset($row[$options['idKey']]); @@ -195,7 +166,7 @@ class DataImporterService foreach ($data as $key => $item) { // 如果需要使用雪花ID if ($options['useSnowflakeId']) { - $item[$options['idKey']] = $this->generateSnowflakeId(); // 生成雪花ID + $item[$options['idKey']] = Snowflake::generate(); // 生成雪花ID } elseif ($options['useAutoIncrement']) { unset($item[$options['idKey']]); // 自增ID由数据库处理 } @@ -244,7 +215,7 @@ class DataImporterService foreach ($data as $item) { // 如果需要使用雪花ID if ($options['useSnowflakeId']) { - $item[$options['idKey']] = $this->generateSnowflakeId(); // 生成雪花ID + $item[$options['idKey']] = Snowflake::generate(); // 生成雪花ID } elseif ($options['useAutoIncrement']) { unset($item[$options['idKey']]); // 自增ID由数据库处理 } diff --git a/server/core/uuid/Snowflake.php b/server/core/uuid/Snowflake.php new file mode 100644 index 0000000..133dab6 --- /dev/null +++ b/server/core/uuid/Snowflake.php @@ -0,0 +1,106 @@ +id ?: 0) : 0; + self::$instance = new SnowflakeGenerator( + $nodeId, + $workerId, + array_merge([ + 'node_id_bits' => 3, + 'worker_id_bits' => 7, + 'sequence_bits' => 12, + ], config('core.uuid.snowflake', [])) + + ); + } + + return self::$instance; + } + + /** + * 静态代理调用:将所有静态方法调用转发到真正的 Snowflake 实例上 + * + * @param string $method 方法名,比如 "generate" + * @param array $args 参数列表 + * + * @return mixed + * @throws \core\exception\handler\AdminException + */ + public static function __callStatic(string $method, array $args) + { + $instance = self::instance(); + + if (!method_exists($instance, $method)) { + throw new AdminException(sprintf( + 'Call to undefined method %s::%s()', + static::class, + $method + )); + } + + return $instance->{$method}(...$args); + } +} + -- Gitee From ea40b8290be26bc68b7d93da1ba38e7d2d1c150d Mon Sep 17 00:00:00 2001 From: "Mr.April" Date: Tue, 5 Aug 2025 14:03:56 +0800 Subject: [PATCH 3/5] =?UTF-8?q?chore:=20=E6=9B=B4=E6=94=B9=E8=8F=9C?= =?UTF-8?q?=E5=8D=95app=20=E5=AD=97=E6=AE=B5=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/scripts/sql/install.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/scripts/sql/install.sql b/server/scripts/sql/install.sql index 0023e3d..82957f2 100644 --- a/server/scripts/sql/install.sql +++ b/server/scripts/sql/install.sql @@ -320,7 +320,7 @@ CREATE TABLE `ma_sys_menu` ( `id` bigint(20) NOT NULL COMMENT '菜单ID', `pid` bigint(20) NOT NULL DEFAULT 0 COMMENT '父ID', - `app` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用编码', + `app` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'admin' COMMENT '应用编码', `title` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单名称', `code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '唯一编码', `level` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '父ID集合', -- Gitee From d489b35433ea957e2f94fa9a27e27fa9cb5d77ff Mon Sep 17 00:00:00 2001 From: "Mr.April" Date: Tue, 5 Aug 2025 14:28:27 +0800 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=9B=9E=E6=98=BE=E8=AF=86=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/.env.production | 8 ++++---- web/src/views/core/profile/components/update-avatar.vue | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/web/.env.production b/web/.env.production index fe9e941..b512175 100644 --- a/web/.env.production +++ b/web/.env.production @@ -2,8 +2,8 @@ VITE_BASE=/ # 接口地址 -VITE_GLOB_API_URL=/api -# VITE_GLOB_API_URL=useCurrentDomain #useCurrentDomain 为自动获取当前域名为base地址 +# VITE_GLOB_API_URL=/api +VITE_GLOB_API_URL=useCurrentDomain #useCurrentDomain 为自动获取当前域名为base地址 # 是否开启压缩,可以设置为 none, brotli, gzip VITE_COMPRESS=none @@ -24,8 +24,8 @@ VITE_GLOB_CLIENT_KEY= X-Client-ID VITE_GLOB_ENABLE_WSS=true # wss接口地址 -VITE_GLOB_WSS_URL=/ws -# VITE_GLOB_WSS_URL=ws://127.0.0.1:3898 #useCurrentDomain 模式使用绝对url +# VITE_GLOB_WSS_URL=/ws +VITE_GLOB_WSS_URL=ws://127.0.0.1:3898 #useCurrentDomain 模式使用绝对url # WSS KEY VITE_GLOB_WSS_APPKEY = 60756ede2a9737a05384aad849e220f8 diff --git a/web/src/views/core/profile/components/update-avatar.vue b/web/src/views/core/profile/components/update-avatar.vue index bbf660c..f1819ca 100644 --- a/web/src/views/core/profile/components/update-avatar.vue +++ b/web/src/views/core/profile/components/update-avatar.vue @@ -13,6 +13,7 @@ import { import { Icon } from '#/components/icon'; import { SystemProfileApi } from '#/api/system/profile'; import { joinUrls } from '#/utils'; +import { getApiBaseUrl } from '#/api/request'; const api= new SystemProfileApi(); @@ -31,7 +32,7 @@ const authStore = useAuthStore(); const getAction = computed(() => { //@ts-ignore - return joinUrls(import.meta.env.VITE_GLOB_API_URL, 'system/files/upload-image') + return joinUrls(getApiBaseUrl(null), 'system/files/upload-image') }); const headers = { -- Gitee From 8defec0f4beb2a9ed9d108deced9339305121c2f Mon Sep 17 00:00:00 2001 From: "Mr.April" Date: Tue, 5 Aug 2025 14:29:16 +0800 Subject: [PATCH 5/5] chore: v4.0.5 --- server/config/core/app.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/config/core/app.php b/server/config/core/app.php index 77b2a13..ade2795 100644 --- a/server/config/core/app.php +++ b/server/config/core/app.php @@ -12,5 +12,5 @@ return [ 'enable' => true, - 'version' => '4.0.4', + 'version' => '4.0.5', ]; -- Gitee