Pre Merge pull request !339 from 芋道源码/dev
commit
a5d6d1d543
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 163 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 46 KiB |
32
README.md
32
README.md
|
|
@ -82,9 +82,9 @@
|
||||||
|
|
||||||

|

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

|

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

|

|
||||||
|
|
||||||
|
### MES 系统
|
||||||
|
|
||||||
|
演示地址:<https://doc.iocoder.cn/mes-preview/>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### AI 大模型
|
### AI 大模型
|
||||||
|
|
||||||
演示地址:<https://doc.iocoder.cn/ai-preview/>
|
演示地址:<https://doc.iocoder.cn/ai-preview/>
|
||||||
|
|
@ -238,3 +256,11 @@
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
### IoT 物联网
|
||||||
|
|
||||||
|
演示地址:<https://doc.iocoder.cn/iot/build>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ import type { Recordable } from '@vben/types';
|
||||||
export * from './rangePickerProps';
|
export * from './rangePickerProps';
|
||||||
export * from './routerHelper';
|
export * from './routerHelper';
|
||||||
|
|
||||||
|
// 从共享包导出 URL 工具函数
|
||||||
|
export { isUrl } from '@vben/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找数组对象的某个下标
|
* 查找数组对象的某个下标
|
||||||
* @param {Array} ary 查找的数组
|
* @param {Array} ary 查找的数组
|
||||||
|
|
@ -27,14 +30,3 @@ export const findIndex = <T = Recordable<any>>(
|
||||||
});
|
});
|
||||||
return index;
|
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);
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ const [Modal, modalApi] = useVbenModal({
|
||||||
onConfirm: handleOk,
|
onConfirm: handleOk,
|
||||||
onOpenChange(isOpen) {
|
onOpenChange(isOpen) {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
// 打开时,进行 loading 加载。后续 CropperImage 组件加载完毕,会自动关闭 loading(通过 handleReady)
|
// 只有存在可加载图片时才显示 loading,避免空图或异常链接导致一直 loading
|
||||||
modalLoading(true);
|
modalLoading(!!src.value);
|
||||||
} else {
|
} else {
|
||||||
// 关闭时,清空右侧预览
|
// 关闭时,清空右侧预览
|
||||||
previewSource.value = '';
|
previewSource.value = '';
|
||||||
|
|
@ -65,10 +65,14 @@ function handleBeforeUpload(file: File) {
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
src.value = '';
|
src.value = '';
|
||||||
previewSource.value = '';
|
previewSource.value = '';
|
||||||
|
modalLoading(true);
|
||||||
reader.addEventListener('load', (e) => {
|
reader.addEventListener('load', (e) => {
|
||||||
src.value = (e.target?.result as string) ?? '';
|
src.value = (e.target?.result as string) ?? '';
|
||||||
filename = file.name;
|
filename = file.name;
|
||||||
});
|
});
|
||||||
|
reader.addEventListener('error', () => {
|
||||||
|
modalLoading(false);
|
||||||
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,6 +86,10 @@ function handleReady(cropperInstance: CropperType) {
|
||||||
modalLoading(false);
|
modalLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCropperError() {
|
||||||
|
modalLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
function handlerToolbar(event: string, arg?: number) {
|
function handlerToolbar(event: string, arg?: number) {
|
||||||
if (event === 'scaleX') {
|
if (event === 'scaleX') {
|
||||||
scaleX = arg = scaleX === -1 ? 1 : -1;
|
scaleX = arg = scaleX === -1 ? 1 : -1;
|
||||||
|
|
@ -133,6 +141,7 @@ async function handleOk() {
|
||||||
:src="src"
|
:src="src"
|
||||||
height="300px"
|
height="300px"
|
||||||
@cropend="handleCropend"
|
@cropend="handleCropend"
|
||||||
|
@cropend-error="handleCropperError"
|
||||||
@ready="handleReady"
|
@ready="handleReady"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,10 @@ function getRoundedCanvas() {
|
||||||
context.fill();
|
context.fill();
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleImageError() {
|
||||||
|
emit('cropendError');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -155,6 +159,7 @@ function getRoundedCanvas() {
|
||||||
:crossorigin="crossorigin"
|
:crossorigin="crossorigin"
|
||||||
:src="src"
|
:src="src"
|
||||||
:style="getImageStyle"
|
:style="getImageStyle"
|
||||||
|
@error="handleImageError"
|
||||||
class="h-auto max-w-full"
|
class="h-auto max-w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ import type { Recordable } from '@vben/types';
|
||||||
export * from './rangePickerProps';
|
export * from './rangePickerProps';
|
||||||
export * from './routerHelper';
|
export * from './routerHelper';
|
||||||
|
|
||||||
|
// 从共享包导出 URL 工具函数
|
||||||
|
export { isUrl } from '@vben/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找数组对象的某个下标
|
* 查找数组对象的某个下标
|
||||||
* @param {Array} ary 查找的数组
|
* @param {Array} ary 查找的数组
|
||||||
|
|
@ -28,14 +31,3 @@ export const findIndex = <T = Recordable<any>>(
|
||||||
});
|
});
|
||||||
return index;
|
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);
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ export * from './tree';
|
||||||
export * from './unique';
|
export * from './unique';
|
||||||
export * from './update-css-variables';
|
export * from './update-css-variables';
|
||||||
export * from './upload';
|
export * from './upload';
|
||||||
|
export * from './url';
|
||||||
export * from './util';
|
export * from './util';
|
||||||
export * from './uuid'; // add by 芋艿:从 vben2.0 复制
|
export * from './uuid'; // add by 芋艿:从 vben2.0 复制
|
||||||
export * from './window';
|
export * from './window';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* URL 验证
|
||||||
|
* @param path URL 路径
|
||||||
|
*/
|
||||||
|
export function isUrl(path: string): boolean {
|
||||||
|
try {
|
||||||
|
new URL(path);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue