小程序初始提交

This commit is contained in:
jdc
2025-11-13 10:36:23 +08:00
parent f26b4f9a2f
commit 5db3b180eb
447 changed files with 83351 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
import { parse } from "@/cool";
import type { ClCascaderOption, ClListViewItem, ClTreeItem } from "../types";
export function useListView(data: UTSJSONObject[]) {
return data.map((e) => {
return parse<ClListViewItem>({
...e,
value: e
})!;
});
}
export function useCascader(data: UTSJSONObject[]) {
return data.map((e) => parse<ClCascaderOption>(e)!);
}
export function useTree(data: UTSJSONObject[]) {
return data.map((e) => {
return parse<ClTreeItem>({
...e,
value: e
})!;
});
}

View File

@@ -0,0 +1,142 @@
import { computed, ref, type ComputedRef } from "vue";
import type { ClFormRule, ClFormValidateError } from "../types";
import { useParent } from "@/cool";
export class Form {
public formRef = ref<ClFormComponentPublicInstance | null>(null);
public disabled: ComputedRef<boolean>;
constructor() {
// 获取 cl-form 实例
if (this.formRef.value == null) {
const ClForm = useParent<ClFormComponentPublicInstance>("cl-form");
if (ClForm != null) {
this.formRef.value = ClForm;
}
}
// 监听表单是否禁用
this.disabled = computed<boolean>(() => {
if (this.formRef.value == null) {
return false;
}
return this.formRef.value.disabled;
});
}
// 注册表单字段
addField = (prop: string, rules: ClFormRule[]): void => {
this.formRef.value!.addField(prop, rules);
};
// 注销表单字段
removeField = (prop: string): void => {
this.formRef.value!.removeField(prop);
};
// 获取字段值
getValue = (prop: string): any | null => {
return this.formRef.value!.getValue(prop);
};
// 设置字段错误信息
setError = (prop: string, error: string): void => {
this.formRef.value!.setError(prop, error);
};
// 获取字段错误信息
getError = (prop: string): string => {
return this.formRef.value!.getError(prop);
};
// 获取所有错误信息
getErrors = async (): Promise<ClFormValidateError[]> => {
return this.formRef.value!.getErrors();
};
// 移除字段错误信息
removeError = (prop: string): void => {
this.formRef.value!.removeError(prop);
};
// 清除所有错误信息
clearErrors = (): void => {
this.formRef.value!.clearErrors();
};
// 获取字段规则
getRule = (prop: string): ClFormRule[] => {
return this.formRef.value!.getRule(prop);
};
// 设置字段规则
setRule = (prop: string, rules: ClFormRule[]): void => {
this.formRef.value!.setRule(prop, rules);
};
// 移除字段规则
removeRule = (prop: string): void => {
this.formRef.value!.removeRule(prop);
};
// 验证单个规则
validateRule = (value: any | null, rule: ClFormRule): string | null => {
return this.formRef.value!.validateRule(value, rule);
};
// 清除所有验证
clearValidate = (): void => {
this.formRef.value!.clearValidate();
};
// 验证单个字段
validateField = (prop: string): string | null => {
return this.formRef.value!.validateField(prop);
};
// 验证整个表单
validate = (callback: (valid: boolean, errors: ClFormValidateError[]) => void): void => {
this.formRef.value!.validate(callback);
};
// 检查字段是否存在错误
isError = (prop: string): boolean => {
return this.formRef.value!.getError(prop) != "";
};
}
class FormItem {
public formItemRef = ref<ClFormItemComponentPublicInstance | null>(null);
public isError: ComputedRef<boolean>;
constructor() {
const { isError } = new Form();
if (this.formItemRef.value == null) {
const ClFormItem = useParent<ClFormItemComponentPublicInstance>("cl-form-item");
if (ClFormItem != null) {
this.formItemRef.value = ClFormItem;
}
}
// 监听表单字段是否验证错误
this.isError = computed<boolean>(() => {
if (this.formItemRef.value == null) {
return false;
}
return isError(this.formItemRef.value.prop);
});
}
}
export const useForm = (): Form => {
return new Form();
};
export const useFormItem = (): FormItem => {
return new FormItem();
};

View File

@@ -0,0 +1,5 @@
export * from "./component";
export * from "./form";
export * from "./page";
export * from "./size";
export * from "./ui";

View File

@@ -0,0 +1,60 @@
import { router, scroller, useParent } from "@/cool";
class Page {
pageRef: ClPageComponentPublicInstance | null = null;
constructor() {
this.pageRef = useParent<ClPageComponentPublicInstance>("cl-page");
}
/**
* 获取页面路径
* @returns 页面路径
*/
path = () => {
return router.path();
};
/**
* 获取滚动位置
* @returns 滚动位置
*/
getScrollTop = (): number => {
return this.pageRef!.scrollTop as number;
};
/**
* 滚动到指定位置
* @param top 滚动位置
*/
scrollTo = (top: number) => {
this.pageRef!.scrollTo(top);
};
/**
* 回到顶部
*/
scrollToTop = () => {
this.pageRef!.scrollToTop();
};
/**
* 监听页面滚动
* @param callback 回调函数
*/
onScroll = (callback: (top: number) => void) => {
scroller.on(callback);
};
/**
* 取消监听页面滚动
* @param callback 回调函数
*/
offScroll = (callback: (top: number) => void) => {
scroller.off(callback);
};
}
export function usePage(): Page {
return new Page();
}

View File

@@ -0,0 +1,159 @@
import { computed, type ComputedRef } from "vue";
import { config } from "../config";
import { rpx2px } from "@/cool";
/**
* 字号管理类
* 用于处理文本大小的缩放和样式
*/
class Size {
// 预设的字号类名
public names = [
"text-xs",
"text-sm",
"text-md",
"text-lg",
"text-xl",
"text-2xl",
"text-3xl",
"text-4xl",
"text-5xl",
"text-6xl",
"text-7xl",
"text-8xl",
"text-9xl"
];
// 对应的字号大小
public sizes = [20, 24, 28, 32, 36, 44, 52, 60, 72, 84, 96, 120, 152];
// 对应的行高
public lineHeights = [28, 36, 44, 52, 52, 1, 1, 1, 1, 1, 1, 1, 1];
// 原始类名
public className: ComputedRef<string> = computed(() => "");
// 计算后的类名
public ptClassName: ComputedRef<string>;
constructor(cb: (() => string) | null) {
this.className = computed(cb ?? (() => ""));
// 根据全局字号配置动态计算类名
this.ptClassName = computed(() => {
if (config.fontSize == null) {
return this.className.value;
}
const name = this.names[this.getIndex()];
return this.className.value.replace(`-important-${name}`, "").replace(name, "");
});
}
/**
* 获取全局字号缩放比例
*/
getScale = () => {
return config.fontSize ?? 1;
};
/**
* 根据缩放比例计算rpx值
* @param val - 需要转换的值
*/
getRpx = (val: number | string) => {
const scale = this.getScale();
if (typeof val == "number") {
return val * scale + "rpx";
} else {
const num = parseFloat(val);
const unit = val.replace(`${num}`, "");
return num * scale + unit;
}
};
/**
* 获取px值
* @param val - 需要转换的值 10、10rpx、10px
* @returns 转换后的px值
*/
getPxValue = (val: number | string) => {
const scale = this.getScale();
if (typeof val == "string") {
const num = parseFloat(val);
const unit = val.replace(`${num}`, "");
if (unit == "px") {
return num * scale;
} else {
return rpx2px(num * scale);
}
} else {
return rpx2px(val * scale);
}
};
/**
* 获取px值
*/
getPx = (val: number | string) => {
return this.getPxValue(val) + "px";
};
/**
* 获取当前字号在预设中的索引
*/
getIndex = () => {
let index = this.names.findIndex((name) => {
if (this.className.value.includes(name)) {
return true;
}
return false;
});
// 默认使用 text-md (14px)
if (index < 0) {
index = 2;
}
return index;
};
/**
* 获取最终的字号大小
* @param size - 指定字号大小,为空则使用预设值
*/
getSize = (size: number | string | null): null | string => {
// 如果未设置全局字号且未指定size直接返回null否则返回对应rpx值
if (config.fontSize == null && size == null) {
return null;
}
return this.getRpx(size ?? this.sizes[this.getIndex()]);
};
/**
* 获取当前行高
*/
getLineHeight = (): null | string => {
// 未设置全局字号时返回null
if (config.fontSize == null) {
return null;
}
const lineHeight = this.lineHeights[this.getIndex()];
return lineHeight == 1 ? `1` : this.getRpx(lineHeight);
};
}
/**
* 字号管理Hook
* @param className - 类名
*/
export function useSize(cb: (() => string) | null = null): Size {
return new Size(cb);
}

View File

@@ -0,0 +1,120 @@
import { router } from "@/cool";
import type { ClConfirmAction, ClConfirmOptions, ClToastOptions } from "../types";
import { t } from "@/locale";
/**
* UiInstance 类型定义
* - showConfirm: 显示确认弹窗的方法
* - showTips: 显示提示弹窗的方法
*/
export type UiInstance = {
/**
* 显示确认弹窗
* @param options ClConfirmOptions 弹窗配置项
*/
showConfirm: (options: ClConfirmOptions) => void;
/**
* 显示提示弹窗
* @param message 提示消息
* @param callback 回调函数,参数为用户操作类型
*/
showTips: (message: string, callback: (action: ClConfirmAction) => void) => void;
/**
* 显示提示弹窗
* @param options ClToastOptions 弹窗配置项
*/
showToast: (options: ClToastOptions) => void;
};
/**
* 存储每个页面对应的 UiInstance 实例
* key: 当前页面路由
* value: UiInstance 实例
*/
const list = new Map<string, UiInstance>();
/**
* Ui 类,提供全局弹窗调用能力
*/
class Ui {
/**
* 获取当前页面的 UiInstance 实例
* @returns UiInstance | undefined
*/
getInstance() {
return list.get(router.path());
}
/**
* 显示确认弹窗
* @param options ClConfirmOptions 弹窗配置项
*/
showConfirm(options: ClConfirmOptions): void {
const instance = this.getInstance();
if (instance != null) {
instance.showConfirm(options);
}
}
/**
* 显示提示弹窗
* @param message 提示消息
* @param callback 回调函数
*/
showTips(message: string, callback: (action: ClConfirmAction) => void): void {
const instance = this.getInstance();
if (instance != null) {
instance.showTips(message, callback);
}
}
/**
* 显示提示弹窗
* @param options ClToastOptions 弹窗配置项
*/
showToast(options: ClToastOptions): void {
const instance = this.getInstance();
if (instance != null) {
instance.showToast(options);
}
}
/**
* 显示加载中弹窗
* @param title 提示内容
* @param mask 是否显示蒙层
*/
showLoading(title: string | null = null, mask: boolean | null = null): void {
uni.showLoading({
title: title ?? t("加载中"),
mask: mask ?? true
});
}
/**
* 隐藏加载中弹窗
*/
hideLoading(): void {
uni.hideLoading();
}
}
/**
* 获取 Ui 实例(始终返回同一个 Ui 实例)
* @returns Ui
*/
const ui = new Ui();
export function useUi() {
return ui;
}
/**
* 注册当前页面的 UiInstance 实例
* @param instance UiInstance
*/
export function createUi(instance: UiInstance): void {
list.set(router.path(), instance);
}