diff --git a/.gitee/image/common/iot-feature.png b/.gitee/image/common/iot-feature.png
new file mode 100644
index 000000000..357781c53
Binary files /dev/null and b/.gitee/image/common/iot-feature.png differ
diff --git a/.gitee/image/common/iot-preview.png b/.gitee/image/common/iot-preview.png
new file mode 100644
index 000000000..58e8940eb
Binary files /dev/null and b/.gitee/image/common/iot-preview.png differ
diff --git a/.gitee/image/common/mes-feature.png b/.gitee/image/common/mes-feature.png
new file mode 100644
index 000000000..33196fd06
Binary files /dev/null and b/.gitee/image/common/mes-feature.png differ
diff --git a/.gitee/image/common/mes-preview.png b/.gitee/image/common/mes-preview.png
new file mode 100644
index 000000000..a140979e7
Binary files /dev/null and b/.gitee/image/common/mes-preview.png differ
diff --git a/.gitee/image/common/ruoyi-vue-pro-biz.png b/.gitee/image/common/ruoyi-vue-pro-biz.png
index 24a385abe..41e313711 100644
Binary files a/.gitee/image/common/ruoyi-vue-pro-biz.png and b/.gitee/image/common/ruoyi-vue-pro-biz.png differ
diff --git a/README.md b/README.md
index b0d294bc2..3e8f10586 100644
--- a/README.md
+++ b/README.md
@@ -82,9 +82,9 @@

-- 通用模块(必选):系统功能、基础设施
-- 通用模块(可选):工作流程、支付系统、数据报表、会员中心
-- 业务系统(按需):ERP 系统、CRM 系统、商城系统、微信公众号、AI 大模型
+* 通用模块(必选):系统功能、基础设施
+* 通用模块(可选):工作流程、支付系统、数据报表、会员中心
+* 业务系统(按需):ERP 系统、CRM 系统、MES 系统、商城系统、微信公众号、AI 大模型、IoT 物联网
### 系统功能
@@ -219,6 +219,16 @@

+### 会员中心
+
+| | 功能 | 描述 |
+|-----|------|----------------------------------|
+| 🚀 | 会员管理 | 会员是 C 端的消费者,该功能用于会员的搜索与管理 |
+| 🚀 | 会员标签 | 对会员的标签进行创建、查询、修改、删除等操作 |
+| 🚀 | 会员等级 | 对会员的等级、成长值进行管理,可用于订单折扣等会员权益 |
+| 🚀 | 会员分组 | 对会员进行分组,用于用户画像、内容推送等运营手段 |
+| 🚀 | 积分签到 | 回馈给签到、消费等行为的积分,会员可订单抵现、积分兑换等途径消耗 |
+
### ERP 系统
演示地址:
@@ -231,6 +241,14 @@

+### MES 系统
+
+演示地址:
+
+
+
+
+
### AI 大模型
演示地址:
@@ -238,3 +256,11 @@


+
+### IoT 物联网
+
+演示地址:
+
+
+
+
diff --git a/apps/web-antd/src/utils/index.ts b/apps/web-antd/src/utils/index.ts
index 5e797abcb..0a4c03ca5 100644
--- a/apps/web-antd/src/utils/index.ts
+++ b/apps/web-antd/src/utils/index.ts
@@ -3,6 +3,9 @@ import type { Recordable } from '@vben/types';
export * from './rangePickerProps';
export * from './routerHelper';
+// 从共享包导出 URL 工具函数
+export { isUrl } from '@vben/utils';
+
/**
* 查找数组对象的某个下标
* @param {Array} ary 查找的数组
@@ -27,14 +30,3 @@ export const findIndex = >(
});
return index;
};
-
-/**
- * URL 验证
- * @param path URL 路径
- */
-export const isUrl = (path: string): boolean => {
- // fix:修复hash路由无法跳转的问题
- const reg =
- /(((^https?:(?:\/\/)?)(?:[-:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%#/.\w-]*)?\??[-+=&%@.\w]*(?:#\w*)?)?)$/;
- return reg.test(path);
-};
diff --git a/apps/web-ele/src/components/cropper/cropper-modal.vue b/apps/web-ele/src/components/cropper/cropper-modal.vue
index cf80965ad..5355f67fd 100644
--- a/apps/web-ele/src/components/cropper/cropper-modal.vue
+++ b/apps/web-ele/src/components/cropper/cropper-modal.vue
@@ -41,8 +41,8 @@ const [Modal, modalApi] = useVbenModal({
onConfirm: handleOk,
onOpenChange(isOpen) {
if (isOpen) {
- // 打开时,进行 loading 加载。后续 CropperImage 组件加载完毕,会自动关闭 loading(通过 handleReady)
- modalLoading(true);
+ // 只有存在可加载图片时才显示 loading,避免空图或异常链接导致一直 loading
+ modalLoading(!!src.value);
} else {
// 关闭时,清空右侧预览
previewSource.value = '';
@@ -65,10 +65,14 @@ function handleBeforeUpload(file: File) {
reader.readAsDataURL(file);
src.value = '';
previewSource.value = '';
+ modalLoading(true);
reader.addEventListener('load', (e) => {
src.value = (e.target?.result as string) ?? '';
filename = file.name;
});
+ reader.addEventListener('error', () => {
+ modalLoading(false);
+ });
return false;
}
@@ -82,6 +86,10 @@ function handleReady(cropperInstance: CropperType) {
modalLoading(false);
}
+function handleCropperError() {
+ modalLoading(false);
+}
+
function handlerToolbar(event: string, arg?: number) {
if (event === 'scaleX') {
scaleX = arg = scaleX === -1 ? 1 : -1;
@@ -133,6 +141,7 @@ async function handleOk() {
:src="src"
height="300px"
@cropend="handleCropend"
+ @cropend-error="handleCropperError"
@ready="handleReady"
/>
diff --git a/apps/web-ele/src/components/cropper/cropper.vue b/apps/web-ele/src/components/cropper/cropper.vue
index d768fd87a..0db99c17b 100644
--- a/apps/web-ele/src/components/cropper/cropper.vue
+++ b/apps/web-ele/src/components/cropper/cropper.vue
@@ -144,6 +144,10 @@ function getRoundedCanvas() {
context.fill();
return canvas;
}
+
+function handleImageError() {
+ emit('cropendError');
+}
@@ -155,6 +159,7 @@ function getRoundedCanvas() {
:crossorigin="crossorigin"
:src="src"
:style="getImageStyle"
+ @error="handleImageError"
class="h-auto max-w-full"
/>
diff --git a/apps/web-ele/src/utils/index.ts b/apps/web-ele/src/utils/index.ts
index 9886b8d68..a63a885f4 100644
--- a/apps/web-ele/src/utils/index.ts
+++ b/apps/web-ele/src/utils/index.ts
@@ -3,6 +3,9 @@ import type { Recordable } from '@vben/types';
export * from './rangePickerProps';
export * from './routerHelper';
+// 从共享包导出 URL 工具函数
+export { isUrl } from '@vben/utils';
+
/**
* 查找数组对象的某个下标
* @param {Array} ary 查找的数组
@@ -28,14 +31,3 @@ export const findIndex = >(
});
return index;
};
-
-/**
- * URL 验证
- * @param path URL 路径
- */
-export const isUrl = (path: string): boolean => {
- // fix:修复hash路由无法跳转的问题
- const reg =
- /(((^https?:(?:\/\/)?)(?:[-:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%#/.\w-]*)?\??[-+=&%@.\w]*(?:#\w*)?)?)$/;
- return reg.test(path);
-};
diff --git a/packages/@core/base/shared/src/utils/index.ts b/packages/@core/base/shared/src/utils/index.ts
index ac506856d..00e3a983a 100644
--- a/packages/@core/base/shared/src/utils/index.ts
+++ b/packages/@core/base/shared/src/utils/index.ts
@@ -18,6 +18,7 @@ export * from './tree';
export * from './unique';
export * from './update-css-variables';
export * from './upload';
+export * from './url';
export * from './util';
export * from './uuid'; // add by 芋艿:从 vben2.0 复制
export * from './window';
diff --git a/packages/@core/base/shared/src/utils/url.ts b/packages/@core/base/shared/src/utils/url.ts
new file mode 100644
index 000000000..1bf744be2
--- /dev/null
+++ b/packages/@core/base/shared/src/utils/url.ts
@@ -0,0 +1,12 @@
+/**
+ * URL 验证
+ * @param path URL 路径
+ */
+export function isUrl(path: string): boolean {
+ try {
+ new URL(path);
+ return true;
+ } catch {
+ return false;
+ }
+}