小程序初始提交

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,206 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('选择器')">
<cl-calendar-select v-model="date"></cl-calendar-select>
</demo-item>
<demo-item :label="t('多选')">
<cl-calendar-select v-model:date="dateArr" mode="multiple"></cl-calendar-select>
</demo-item>
<demo-item :label="t('范围选')">
<cl-calendar-select v-model:date="dateRange" mode="range"></cl-calendar-select>
</demo-item>
<demo-item :label="t('开始 / 结束')">
<cl-calendar-select
v-model:date="dateRange3"
mode="range"
:start="startDate"
:end="endDate"
></cl-calendar-select>
</demo-item>
<demo-item :label="t('禁用部分日期')">
<cl-calendar-select v-model="date" :date-config="dateConfig"></cl-calendar-select>
</demo-item>
<!-- <demo-item :label="t('日历长列表')">
<cl-button>{{ t("打开日历长列表") }}</cl-button>
</demo-item> -->
<demo-item :label="t('日历面板')">
<cl-calendar
v-model:date="dateRange2"
mode="range"
:month="10"
:show-header="isShowHeader"
:show-weeks="isShowWeeks"
:show-other-month="isShowOtherMonth"
:date-config="dateConfig2"
@change="onChange"
></cl-calendar>
<cl-list
border
:pt="{
className: 'mt-5'
}"
>
<cl-list-item :label="t('自定义文案和颜色')">
<cl-switch v-model="isCustomDateConfig"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('显示头')">
<cl-switch v-model="isShowHeader"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('显示星期')">
<cl-switch v-model="isShowWeeks"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('显示其他月份')">
<cl-switch v-model="isShowOtherMonth"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { computed, ref } from "vue";
import { t } from "@/locale";
import DemoItem from "../components/item.uvue";
import { dayUts, first, last } from "@/cool";
import type { ClCalendarDateConfig } from "@/uni_modules/cool-ui";
const date = ref<string | null>(dayUts().format("YYYY-MM-DD"));
const dateArr = ref<string[]>([
dayUts().format("YYYY-MM-DD"),
dayUts().add(1, "day").format("YYYY-MM-DD")
]);
const dateRange = ref<string[]>([
dayUts().format("YYYY-MM-DD"),
dayUts().add(10, "day").format("YYYY-MM-DD")
]);
const dateConfig = ref<ClCalendarDateConfig[]>([
{
date: dayUts().add(1, "day").format("YYYY-MM-DD"),
disabled: true
},
{
date: dayUts().add(2, "day").format("YYYY-MM-DD"),
disabled: true
},
{
date: dayUts().add(3, "day").format("YYYY-MM-DD"),
disabled: true
}
]);
const isShowHeader = ref(true);
const isShowWeeks = ref(true);
const isShowOtherMonth = ref(true);
const isCustomDateConfig = ref(true);
const dateRange2 = ref<string[]>([]);
const dateConfig2 = computed(() => {
const dates = (
isCustomDateConfig.value
? [
{
date: "2025-10-01",
topText: "国庆节",
bottomText: "¥958",
color: "red"
},
{
date: "2025-10-02",
topText: "休",
bottomText: "¥613",
color: "red"
},
{
date: "2025-10-03",
topText: "休",
bottomText: "¥613",
color: "red"
},
{
date: "2025-10-04",
topText: "休",
bottomText: "¥613",
color: "red"
},
{
date: "2025-10-05",
topText: "休",
bottomText: "¥613",
color: "red"
},
{
date: "2025-10-06",
topText: "休",
bottomText: "¥613",
color: "red"
},
{
date: "2025-10-07",
topText: "休",
bottomText: "¥613",
color: "red"
},
{
date: "2025-10-08",
topText: "休",
bottomText: "¥613",
color: "red"
}
]
: []
) as ClCalendarDateConfig[];
const startDate = first(dateRange2.value);
const endDate = last(dateRange2.value);
if (startDate != null) {
const item = dates.find((e) => e.date == startDate);
if (item == null) {
dates.push({
date: startDate,
bottomText: "入住"
} as ClCalendarDateConfig);
} else {
item.bottomText = "入住";
}
}
if (endDate != null && dateRange2.value.length > 1) {
const item = dates.find((e) => e.date == endDate);
if (item == null) {
dates.push({
date: endDate,
bottomText: "离店"
} as ClCalendarDateConfig);
} else {
item.bottomText = "离店";
}
}
return dates;
});
const dateRange3 = ref<string[]>([]);
const startDate = dayUts().format("YYYY-MM-DD");
const endDate = dayUts().add(10, "day").format("YYYY-MM-DD");
function onChange(date: string[]) {
console.log("日期变化:", date);
}
</script>

View File

@@ -0,0 +1,509 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-cascader v-model="form.cascader1" :options="options"></cl-cascader>
</demo-item>
<demo-item :label="t('带索引、地区选择')">
<cl-cascader v-model="form.cascader2" :options="options2"></cl-cascader>
</demo-item>
<demo-item :label="t('自定义')">
<cl-cascader
v-model="form.cascader3"
:options="options"
:disabled="isDisabled"
:text-separator="isSeparator ? ' / ' : ' - '"
:height="isHeight ? 500 : 800"
></cl-cascader>
<cl-list
border
:pt="{
className: 'mt-3'
}"
>
<cl-list-item :label="t('换个分隔符')">
<cl-switch v-model="isSeparator"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('列表高度小一点')">
<cl-switch v-model="isHeight"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { reactive, ref } from "vue";
import DemoItem from "../components/item.uvue";
import { useCascader, type ClCascaderOption } from "@/uni_modules/cool-ui";
import { t } from "@/locale";
import pca from "@/data/pca.json";
type Form = {
cascader1: string[];
cascader2: string[];
cascader3: string[];
};
const form = reactive<Form>({
cascader1: [],
cascader2: [],
cascader3: []
});
const isDisabled = ref(false);
const isSeparator = ref(false);
const isHeight = ref(false);
const options = ref<ClCascaderOption[]>([
{
label: "电子产品",
value: "1",
children: [
{
label: "手机",
value: "1-1",
children: [
{
label: "苹果",
value: "1-1-1",
children: [
{
label: "iPhone 15 Pro Max",
value: "1-1-1-1"
},
{
label: "iPhone 15 Pro",
value: "1-1-1-2"
},
{
label: "iPhone 15",
value: "1-1-1-3"
},
{
label: "iPhone 14 Pro Max",
value: "1-1-1-4"
},
{
label: "iPhone 14",
value: "1-1-1-5"
}
]
},
{
label: "华为",
value: "1-1-2",
children: [
{
label: "Mate 60 Pro+",
value: "1-1-2-1"
},
{
label: "Mate 60 Pro",
value: "1-1-2-2"
},
{
label: "Mate 60",
value: "1-1-2-3"
},
{
label: "P60 Pro",
value: "1-1-2-4"
},
{
label: "P60",
value: "1-1-2-5"
}
]
},
{
label: "小米",
value: "1-1-3",
children: [
{
label: "小米14 Pro",
value: "1-1-3-1"
},
{
label: "小米14",
value: "1-1-3-2"
},
{
label: "Redmi K70 Pro",
value: "1-1-3-3"
},
{
label: "Redmi K70",
value: "1-1-3-4"
}
]
}
]
},
{
label: "电脑",
value: "1-2",
children: [
{
label: "笔记本",
value: "1-2-1",
children: [
{
label: "MacBook Pro 16",
value: "1-2-1-1"
},
{
label: "MacBook Pro 14",
value: "1-2-1-2"
},
{
label: "MacBook Air 15",
value: "1-2-1-3"
},
{
label: "ThinkPad X1",
value: "1-2-1-4"
},
{
label: "ROG 魔霸新锐",
value: "1-2-1-5"
},
{
label: "拯救者 Y9000P",
value: "1-2-1-6"
}
]
},
{
label: "台式机",
value: "1-2-2",
children: [
{
label: "iMac 24寸",
value: "1-2-2-1"
},
{
label: "Mac Studio",
value: "1-2-2-2"
},
{
label: "Mac Pro",
value: "1-2-2-3"
},
{
label: "外星人",
value: "1-2-2-4"
},
{
label: "惠普暗影精灵",
value: "1-2-2-5"
}
]
}
]
},
{
label: "平板",
value: "1-3",
children: [
{
label: "iPad",
value: "1-3-1",
children: [
{
label: "iPad Pro 12.9",
value: "1-3-1-1"
},
{
label: "iPad Pro 11",
value: "1-3-1-2"
},
{
label: "iPad Air",
value: "1-3-1-3"
},
{
label: "iPad mini",
value: "1-3-1-4"
}
]
},
{
label: "安卓平板",
value: "1-3-2",
children: [
{
label: "小米平板6 Pro",
value: "1-3-2-1"
},
{
label: "华为MatePad Pro",
value: "1-3-2-2"
},
{
label: "三星Galaxy Tab S9",
value: "1-3-2-3"
}
]
}
]
}
]
},
{
label: "服装",
value: "2",
children: [
{
label: "男装",
value: "2-1",
children: [
{
label: "上衣",
value: "2-1-1",
children: [
{
label: "短袖T恤",
value: "2-1-1-1"
},
{
label: "长袖T恤",
value: "2-1-1-2"
},
{
label: "衬衫",
value: "2-1-1-3"
},
{
label: "卫衣",
value: "2-1-1-4"
},
{
label: "夹克",
value: "2-1-1-5"
},
{
label: "毛衣",
value: "2-1-1-6"
}
]
},
{
label: "裤装",
value: "2-1-2",
children: [
{
label: "牛仔裤",
value: "2-1-2-1"
},
{
label: "休闲裤",
value: "2-1-2-2"
},
{
label: "运动裤",
value: "2-1-2-3"
},
{
label: "西裤",
value: "2-1-2-4"
},
{
label: "短裤",
value: "2-1-2-5"
}
]
},
{
label: "外套",
value: "2-1-3",
children: [
{
label: "羽绒服",
value: "2-1-3-1"
},
{
label: "大衣",
value: "2-1-3-2"
},
{
label: "夹克",
value: "2-1-3-3"
},
{
label: "西装",
value: "2-1-3-4"
}
]
}
]
},
{
label: "女装",
value: "2-2",
children: [
{
label: "裙装",
value: "2-2-1",
children: [
{
label: "连衣裙",
value: "2-2-1-1"
},
{
label: "半身裙",
value: "2-2-1-2"
},
{
label: "A字裙",
value: "2-2-1-3"
},
{
label: "包臀裙",
value: "2-2-1-4"
},
{
label: "百褶裙",
value: "2-2-1-5"
}
]
},
{
label: "上装",
value: "2-2-2",
children: [
{
label: "衬衫",
value: "2-2-2-1"
},
{
label: "T恤",
value: "2-2-2-2"
},
{
label: "毛衣",
value: "2-2-2-3"
},
{
label: "卫衣",
value: "2-2-2-4"
},
{
label: "雪纺衫",
value: "2-2-2-5"
}
]
},
{
label: "外套",
value: "2-2-3",
children: [
{
label: "风衣",
value: "2-2-3-1"
},
{
label: "羽绒服",
value: "2-2-3-2"
},
{
label: "大衣",
value: "2-2-3-3"
},
{
label: "西装",
value: "2-2-3-4"
},
{
label: "皮衣",
value: "2-2-3-5"
}
]
}
]
}
]
},
{
label: "食品",
value: "3",
children: [
{
label: "水果",
value: "3-1",
children: [
{
label: "苹果",
value: "3-1-1"
},
{
label: "香蕉",
value: "3-1-2"
},
{
label: "橘子",
value: "3-1-3"
}
]
},
{
label: "蔬菜",
value: "3-2",
children: [
{
label: "西红柿",
value: "3-2-1"
},
{
label: "黄瓜",
value: "3-2-2"
},
{
label: "胡萝卜",
value: "3-2-3"
}
]
}
]
},
{
label: "饮料",
value: "4",
children: [
{
label: "果汁",
value: "4-1",
children: [
{
label: "苹果汁",
value: "4-1-1"
},
{
label: "橙汁",
value: "4-1-2"
},
{
label: "葡萄汁",
value: "4-1-3"
},
{
label: "西瓜汁",
value: "4-1-4"
}
]
}
]
}
]);
const options2 = useCascader(pca);
</script>

View File

@@ -0,0 +1,163 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<view class="flex flex-row flex-wrap">
<cl-checkbox
v-model="checked2"
v-for="(item, index) in options"
:key="index"
:value="item.value"
:pt="{
className: 'mr-5'
}"
>
{{ item.label }}
</cl-checkbox>
</view>
</demo-item>
<demo-item :label="t('单个 true / false')">
<view class="flex flex-row items-center">
<cl-checkbox v-model="checked4">同意并阅读</cl-checkbox>
<cl-text color="primary">《用户协议》</cl-text>
<view class="flex-1"></view>
<cl-switch v-model="checked4"></cl-switch>
</view>
</demo-item>
<demo-item :label="t('纵向排列')">
<cl-checkbox
v-model="checked"
v-for="(item, index) in options"
:key="index"
:value="item.value"
:pt="{
className: parseClass([
'py-2',
[
isVerticalCustom,
'justify-between border border-solid border-surface-200 rounded-lg p-2 !my-1'
]
])
}"
>
{{ item.label }}
</cl-checkbox>
<cl-list
border
:pt="{
className: 'mt-2'
}"
>
<cl-list-item :label="t('换个样式')">
<cl-switch v-model="isVerticalCustom"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
<demo-item :label="t('自定义')">
<view class="mb-3 flex flex-row flex-wrap">
<cl-checkbox
v-model="checked3"
v-for="(item, index) in options"
:key="index"
:value="item.value"
:disabled="isDisabled"
:show-icon="!isHideIcon"
:active-icon="isIcon ? 'heart-fill' : 'checkbox-line'"
:inactive-icon="isIcon ? 'heart-line' : 'checkbox-blank-line'"
:pt="{
className: parseClass([
'mr-5',
[isCustom, 'bg-surface-100 py-2 px-3 rounded-lg !mr-2 !mb-2'],
{
'!bg-surface-700': isDark && isCustom
}
]),
icon: {
className: parseClass([
[
isCustom && checked3.includes(item.value as string),
'text-red-500'
]
])
},
label: {
className: parseClass([
[
isCustom && checked3.includes(item.value as string),
'text-red-500'
]
])
}
}"
>
{{ item.label }}
</cl-checkbox>
</view>
<cl-list border>
<cl-list-item :label="t('换个图标')">
<cl-switch v-model="isIcon"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('不显示图标')">
<cl-switch v-model="isHideIcon"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('其他样式')">
<cl-switch v-model="isCustom"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import DemoItem from "../components/item.uvue";
import { useUi, type ClCheckboxOption } from "@/uni_modules/cool-ui";
import { isDark, parseClass } from "@/cool";
import { t } from "@/locale";
const ui = useUi();
const isIcon = ref(false);
const isCustom = ref(false);
const isDisabled = ref(false);
const isHideIcon = ref(false);
const isVerticalCustom = ref(false);
const checked = ref<string[]>([]);
const checked2 = ref<string[]>(["2"]);
const checked3 = ref<string[]>(["2", "3"]);
const checked4 = ref(false);
const options = ref<ClCheckboxOption[]>([
{
label: "Vue",
value: "1"
},
{
label: "React",
value: "2"
},
{
label: "Angular",
value: "3"
},
{
label: "Svelte",
value: "4"
}
]);
</script>

View File

@@ -0,0 +1,381 @@
<template>
<cl-page>
<view class="p-3">
<demo-item>
<cl-form
:pt="{
className: 'p-2 pb-0'
}"
v-model="formData"
ref="formRef"
:rules="rules"
:disabled="saving"
label-position="top"
>
<cl-form-item prop="avatarUrl">
<cl-upload v-model="formData.avatarUrl" test></cl-upload>
</cl-form-item>
<cl-form-item :label="t('用户名')" prop="nickName" required>
<cl-input
v-model="formData.nickName"
:placeholder="t('请输入用户名')"
clearable
></cl-input>
</cl-form-item>
<cl-form-item :label="t('邮箱')" prop="email">
<cl-input
v-model="formData.email"
:placeholder="t('请输入邮箱地址')"
></cl-input>
</cl-form-item>
<cl-form-item :label="t('动态验证')" required prop="contacts">
<view
class="contacts border border-solid border-surface-200 rounded-xl p-3 dark:!border-surface-700"
>
<cl-form-item
v-for="(item, index) in formData.contacts"
:key="index"
:label="t('联系人') + ` - ${index + 1}`"
:prop="`contacts[${index}].phone`"
:rules="
[
{
required: true,
message: t('手机号不能为空')
}
] as ClFormRule[]
"
required
>
<view class="flex flex-row items-center">
<cl-input
:pt="{
className: 'flex-1 mr-2'
}"
v-model="item.phone"
:placeholder="t('请输入手机号')"
></cl-input>
<cl-button
type="light"
icon="subtract-line"
@tap="removeContact(index)"
></cl-button>
</view>
</cl-form-item>
<cl-button icon="add-line" @tap="addContact">{{
t("添加联系人")
}}</cl-button>
</view>
</cl-form-item>
<cl-form-item :label="t('身高')" prop="height" required>
<cl-slider v-model="formData.height" :max="220" show-value>
<template #value="{ value }">
<cl-text
:pt="{
className: 'text-center w-[120rpx]'
}"
>{{ value }} cm</cl-text
>
</template>
</cl-slider>
</cl-form-item>
<cl-form-item :label="t('体重')" prop="weight" required>
<cl-slider v-model="formData.weight" :max="150" show-value>
<template #value="{ value }">
<cl-text
:pt="{
className: 'text-center w-[120rpx]'
}"
>{{ value }} kg</cl-text
>
</template>
</cl-slider>
</cl-form-item>
<cl-form-item :label="t('标签')" prop="tags" required>
<view class="flex flex-row flex-wrap">
<cl-checkbox
v-model="formData.tags"
v-for="(item, index) in tagsOptions"
:key="index"
:value="index"
:pt="{
className: 'mr-5 mt-2'
}"
>{{ item.label }}</cl-checkbox
>
</view>
</cl-form-item>
<cl-form-item :label="t('性别')" prop="gender" required>
<cl-select v-model="formData.gender" :options="genderOptions"></cl-select>
</cl-form-item>
<cl-form-item :label="t('所在地区')" prop="pca" required>
<cl-cascader v-model="formData.pca" :options="pcaOptions"></cl-cascader>
</cl-form-item>
<cl-form-item :label="t('出生年月')" prop="birthday" required>
<cl-select-date v-model="formData.birthday" type="date"></cl-select-date>
</cl-form-item>
<cl-form-item :label="t('个人简介')" prop="description">
<cl-textarea
v-model="formData.description"
:placeholder="t('请输入个人简介')"
:maxlength="200"
></cl-textarea>
</cl-form-item>
<cl-form-item :label="t('公开状态')">
<cl-switch v-model="formData.isPublic"></cl-switch>
</cl-form-item>
</cl-form>
</demo-item>
<demo-item>
<cl-text pre-wrap :pt="{ className: 'text-sm p-2' }">{{
JSON.stringify(formData, null, 4)
}}</cl-text>
</demo-item>
</view>
<cl-footer>
<view class="flex flex-row">
<cl-button type="info" :pt="{ className: 'flex-1' }" @click="reset">{{
t("重置")
}}</cl-button>
<cl-button
type="primary"
:loading="saving"
:pt="{ className: 'flex-1' }"
@click="submit"
>{{ t("提交") }}</cl-button
>
</view>
</cl-footer>
</cl-page>
</template>
<script setup lang="ts">
import { ref, type Ref } from "vue";
import DemoItem from "../components/item.uvue";
import {
useCascader,
useForm,
useUi,
type ClFormRule,
type ClSelectOption
} from "@/uni_modules/cool-ui";
import pca from "@/data/pca.json";
import { t } from "@/locale";
import { dayUts } from "@/cool";
const ui = useUi();
const { formRef, validate, clearValidate } = useForm();
// 性别选项
const genderOptions = [
{
label: t("未知"),
value: 0
},
{
label: t("男"),
value: 1
},
{
label: t("女"),
value: 2
}
] as ClSelectOption[];
// 标签选项
const tagsOptions = [
{
label: t("篮球"),
value: 1
},
{
label: t("足球"),
value: 2
},
{
label: t("羽毛球"),
value: 3
},
{
label: t("乒乓球"),
value: 4
},
{
label: t("游泳"),
value: 5
}
] as ClSelectOption[];
// 地区选项
const pcaOptions = useCascader(pca);
type Contact = {
phone: string;
};
// 自定义表单数据类型
type FormData = {
avatarUrl: string;
nickName: string;
email: string;
height: number;
weight: number;
gender: number;
description: string;
pca: string[];
tags: number[];
birthday: string;
isPublic: boolean;
contacts: Contact[];
};
// 表单数据
const formData = ref<FormData>({
avatarUrl: "",
nickName: "神仙都没用",
email: "",
height: 180,
weight: 70,
gender: 0,
description: "",
pca: [],
tags: [1, 2],
birthday: "",
isPublic: false,
contacts: []
}) as Ref<FormData>;
// 表单验证规则
const rules = new Map<string, ClFormRule[]>([
[
"nickName",
[
{ required: true, message: t("用户名不能为空") },
{ min: 3, max: 20, message: t("用户名长度在3-20个字符之间") }
]
],
[
"email",
[
{ required: true, message: t("邮箱不能为空") },
{ pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: t("邮箱格式不正确") }
]
],
[
"height",
[
{ required: true, message: t("身高不能为空") },
{ min: 160, max: 190, message: t("身高在160-190cm之间") }
]
],
[
"weight",
[
{ required: true, message: t("体重不能为空") },
{ min: 40, max: 100, message: t("体重在40-100kg之间") }
]
],
[
"tags",
[
{ required: true, message: t("标签不能为空") },
{ min: 1, max: 2, message: t("标签最多选择2个") }
]
],
["gender", [{ required: true, message: t("性别不能为空") }]],
["pca", [{ required: true, message: t("所在地区不能为空") }]],
[
"birthday",
[
{ required: true, message: t("出生年月不能为空") },
{
validator(value) {
if (dayUts(value).isAfter(dayUts("2010-01-01"))) {
return t("出生年月不大于2010-01-01");
}
return true;
}
}
]
],
[
"contacts",
[
{
required: true,
message: t("联系人不能为空")
}
]
]
]);
// 是否保存中
const saving = ref(false);
// 重置表单数据
function reset() {
formData.value.avatarUrl = "";
formData.value.nickName = "";
formData.value.email = "";
formData.value.height = 180;
formData.value.weight = 70;
formData.value.gender = 0;
formData.value.description = "";
formData.value.pca = [];
formData.value.tags = [];
formData.value.birthday = "";
formData.value.isPublic = false;
formData.value.contacts = [];
clearValidate();
}
// 提交表单
function submit() {
validate((valid, errors) => {
if (valid) {
saving.value = true;
setTimeout(() => {
ui.showToast({
message: t("提交成功"),
icon: "check-line"
});
saving.value = false;
reset();
}, 2000);
} else {
ui.showToast({
message: errors[0].message
});
}
});
}
function addContact() {
formData.value.contacts.push({
phone: ""
});
}
function removeContact(index: number) {
formData.value.contacts.splice(index, 1);
}
</script>

View File

@@ -0,0 +1,93 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-input-number></cl-input-number>
</demo-item>
<demo-item :label="t('自定义')">
<view class="mb-5 flex flex-row justify-center">
<cl-input-number
v-model="num"
:step="isStep ? 10 : 1"
:min="isMin ? 10 : 0"
:max="isMax ? 50 : 100"
:input-type="isDigit ? 'digit' : 'number'"
:inputable="isInput"
:disabled="isDisabled"
:size="isSize ? 60 : 50"
:pt="{
op: {
className: parseClass({
'!rounded-full': isCustom
})
},
value: {
className: parseClass({
'!rounded-full': isCustom
})
}
}"
@change="onChange"
></cl-input-number>
</view>
<cl-list border>
<cl-list-item :label="t('步进为10')">
<cl-switch v-model="isStep"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('最小为10')">
<cl-switch v-model="isMin"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('最大为50')">
<cl-switch v-model="isMax"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('可以小数')">
<cl-switch v-model="isDigit"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('可以输入')">
<cl-switch v-model="isInput"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('大一点')">
<cl-switch v-model="isSize"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('自定义样式')">
<cl-switch v-model="isCustom"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import DemoItem from "../components/item.uvue";
import { parseClass } from "@/cool";
import { t } from "@/locale";
const num = ref(0);
const isStep = ref(false);
const isMin = ref(false);
const isMax = ref(false);
const isDigit = ref(false);
const isInput = ref(true);
const isDisabled = ref(false);
const isSize = ref(false);
const isCustom = ref(false);
function onChange(value: number) {
console.log(value);
}
</script>

View File

@@ -0,0 +1,73 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-input-otp @done="toDone"></cl-input-otp>
</demo-item>
<demo-item :label="t('自动聚焦')">
<cl-input-otp autofocus @done="toDone"></cl-input-otp>
</demo-item>
<demo-item :label="t('自定义')">
<cl-input-otp
:length="isLength ? 6 : 4"
:disabled="isDisabled"
:pt="{
item: {
className: parseClass({
'!bg-sky-100': isCustom,
'!border-white': isCustom
})
},
value: {
className: parseClass({
'!text-sky-700': isCustom
})
},
cursor: {
className: parseClass({
'!bg-sky-700': isCustom
})
}
}"
@done="toDone"
></cl-input-otp>
<cl-list border :pt="{ className: 'mt-5' }">
<cl-list-item :label="t('长度为6')">
<cl-switch v-model="isLength"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('其他样式')">
<cl-switch v-model="isCustom"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import DemoItem from "../components/item.uvue";
import { useUi } from "@/uni_modules/cool-ui";
import { parseClass } from "@/cool";
import { t } from "@/locale";
const ui = useUi();
const isLength = ref(true);
const isDisabled = ref(false);
const isCustom = ref(false);
function toDone() {
ui.showToast({
message: "Done"
});
}
</script>

View File

@@ -0,0 +1,136 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-input></cl-input>
</demo-item>
<demo-item :label="t('数字输入')">
<cl-input type="number"></cl-input>
</demo-item>
<demo-item :label="t('密码输入')">
<cl-input password></cl-input>
</demo-item>
<demo-item :label="t('可清除')">
<cl-input clearable :pt="{ className: 'mb-2' }"></cl-input>
<demo-tips>设置 hold-keyboard 属性后,清除内容时输入框将保持聚焦状态</demo-tips>
<cl-input clearable hold-keyboard></cl-input>
</demo-item>
<demo-item :label="t('左右插槽')">
<cl-input
:pt="{
className: '!pr-1 mb-2'
}"
>
<template #append>
<cl-button
type="primary"
size="small"
icon="send-plane-fill"
:pt="{
className: 'ml-2'
}"
@tap="toAlert"
></cl-button>
</template>
</cl-input>
<cl-input
:pt="{
className: '!pl-1'
}"
>
<template #prepend>
<cl-button
type="primary"
size="small"
icon="search-line"
:pt="{
className: 'mr-2'
}"
@tap="toAlert"
></cl-button>
</template>
</cl-input>
</demo-item>
<demo-item :label="t('自定义')">
<cl-input
v-model="content"
:border="isBorder"
:suffix-icon="isRightIcon ? 'text' : ''"
:prefix-icon="isLeftIcon ? 'search-line' : ''"
:disabled="isDisabled"
:pt="{
className: parseClass({
'!bg-sky-100': isColor,
'!border-sky-700': isColor
}),
inner: {
className: parseClass({
'!text-sky-700': isColor
})
},
prefixIcon: {
className: parseClass({
'!text-sky-700': isColor
})
}
}"
></cl-input>
<cl-list border :pt="{ className: 'mt-5' }">
<cl-list-item :label="t('边框')">
<cl-switch v-model="isBorder"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('左图标')">
<cl-switch v-model="isLeftIcon"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('右图标')">
<cl-switch v-model="isRightIcon"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('其他颜色')">
<cl-switch v-model="isColor"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import DemoItem from "../components/item.uvue";
import DemoTips from "../components/tips.uvue";
import { parseClass } from "@/cool";
import { useUi } from "@/uni_modules/cool-ui";
import { t } from "@/locale";
const ui = useUi();
const content = ref("Cool Unix");
const isBorder = ref(true);
const isLeftIcon = ref(true);
const isRightIcon = ref(false);
const isDisabled = ref(false);
const isColor = ref(false);
function toAlert() {
ui.showToast({
message: "Hello"
});
}
</script>

View File

@@ -0,0 +1,111 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('数字键盘')">
<view class="mb-3 overflow-visible">
<cl-input type="number" v-model="content"></cl-input>
</view>
<cl-button @tap="openKeyboardNumber">{{ t("打开键盘") }}</cl-button>
<cl-list
border
:pt="{
className: 'mt-3'
}"
>
<cl-list-item :label="t('是否显示输入值')">
<cl-switch v-model="isShowValue"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('输入即绑定')">
<cl-switch v-model="isInputImmediate"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('身份证键盘')">
<cl-switch v-model="isIdcard"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
<demo-item :label="t('密码键盘')">
<cl-button @tap="openKeyboardPassword">{{ t("打开键盘") }}</cl-button>
<cl-list
border
:pt="{
className: 'mt-3'
}"
>
<cl-list-item :label="t('是否加密')">
<cl-switch v-model="isEncrypt"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
<demo-item :label="t('车牌号键盘')">
<view class="flex mb-3 justify-center flex-row overflow-visible">
<cl-input-otp
input-type="text"
:length="8"
:pt="{
className: 'w-full',
list: {
className: 'justify-between'
},
item: {
className: '!h-9 !w-9'
},
cursor: {
className: '!h-3'
}
}"
v-model="carNumber"
></cl-input-otp>
</view>
<cl-button @tap="openKeyboardCar">{{ t("打开键盘") }}</cl-button>
</demo-item>
</view>
<cl-keyboard-number
v-model="content"
ref="keyboardNumberRef"
:show-value="isShowValue"
:input-immediate="isInputImmediate"
:type="isIdcard ? 'idcard' : 'number'"
></cl-keyboard-number>
<cl-keyboard-car v-model="carNumber" ref="keyboardCarRef"></cl-keyboard-car>
<cl-keyboard-password ref="keyboardPasswordRef" :encrypt="isEncrypt"></cl-keyboard-password>
</cl-page>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import DemoItem from "../components/item.uvue";
import { t } from "@/locale";
const keyboardNumberRef = ref<ClKeyboardNumberComponentPublicInstance | null>(null);
const isShowValue = ref(true);
const isInputImmediate = ref(false);
const isIdcard = ref(false);
const content = ref("");
function openKeyboardNumber() {
keyboardNumberRef.value!.open();
}
const keyboardPasswordRef = ref<ClKeyboardPasswordComponentPublicInstance | null>(null);
const isEncrypt = ref(false);
function openKeyboardPassword() {
keyboardPasswordRef.value!.open();
}
const keyboardCarRef = ref<ClKeyboardCarComponentPublicInstance | null>(null);
const carNumber = ref("");
function openKeyboardCar() {
keyboardCarRef.value!.open();
}
</script>

View File

@@ -0,0 +1,146 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<view class="flex flex-row flex-wrap">
<cl-radio
v-model="checked2"
v-for="(item, index) in options"
:key="index"
:value="item.value"
:pt="{
className: 'mr-5'
}"
>
{{ item.label }}
</cl-radio>
</view>
</demo-item>
<demo-item :label="t('纵向排列')">
<cl-radio
v-model="checked"
v-for="(item, index) in options"
:key="index"
:value="item.value"
:pt="{
className: parseClass([
'my-2',
[
isVerticalCustom,
'justify-between border border-solid border-surface-200 rounded-lg p-2 !my-1'
]
])
}"
>
{{ item.label }}
</cl-radio>
<cl-list
border
:pt="{
className: 'mt-2'
}"
>
<cl-list-item :label="t('换个样式')">
<cl-switch v-model="isVerticalCustom"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
<demo-item :label="t('自定义')">
<view class="mb-3 flex flex-row flex-wrap">
<cl-radio
v-model="checked3"
v-for="(item, index) in options"
:key="index"
:value="item.value"
:disabled="isDisabled"
:show-icon="!isHideIcon"
:active-icon="isIcon ? 'heart-fill' : 'checkbox-circle-line'"
:inactive-icon="isIcon ? 'heart-line' : 'checkbox-blank-circle-line'"
:pt="{
className: parseClass([
'mr-5',
[isCustom, 'bg-surface-100 py-2 px-3 rounded-lg !mr-2 !mb-2'],
{
'!bg-surface-700': isDark && isCustom
}
]),
icon: {
className: parseClass([
[isCustom && item.value == checked3, 'text-red-500']
])
},
label: {
className: parseClass([
[isCustom && item.value == checked3, 'text-red-500']
])
}
}"
>
{{ item.label }}
</cl-radio>
</view>
<cl-list border>
<cl-list-item :label="t('换个图标')">
<cl-switch v-model="isIcon"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('不显示图标')">
<cl-switch v-model="isHideIcon"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('其他样式')">
<cl-switch v-model="isCustom"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import DemoItem from "../components/item.uvue";
import { parseClass } from "@/cool";
import { useUi, type ClRadioOption } from "@/uni_modules/cool-ui";
import { isDark } from "@/cool";
import { t } from "@/locale";
const ui = useUi();
const isIcon = ref(false);
const isCustom = ref(false);
const isDisabled = ref(false);
const isHideIcon = ref(false);
const isVerticalCustom = ref(false);
const checked = ref("1");
const checked2 = ref("2");
const checked3 = ref("3");
const options = ref<ClRadioOption[]>([
{
label: "Vue",
value: "1"
},
{
label: "React",
value: "2"
},
{
label: "Angular",
value: "3"
},
{
label: "Svelte",
value: "4"
}
]);
</script>

View File

@@ -0,0 +1,62 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-rate v-model="num"></cl-rate>
</demo-item>
<demo-item :label="t('自定义')">
<cl-rate
v-model="num2"
:disabled="isDisabled"
:show-score="isShowScore"
:allow-half="isAllowHalf"
:size="isSize ? 50 : 40"
:void-icon="isIcon ? 'heart-fill' : 'star-fill'"
:icon="isIcon ? 'heart-fill' : 'star-fill'"
></cl-rate>
<cl-list
border
:pt="{
className: 'mt-3'
}"
>
<cl-list-item :label="t('只读')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('显示分数')">
<cl-switch v-model="isShowScore"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('允许半星')">
<cl-switch v-model="isAllowHalf"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('换个图标')">
<cl-switch v-model="isIcon"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('大一点')">
<cl-switch v-model="isSize"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import DemoItem from "../components/item.uvue";
import { t } from "@/locale";
const num = ref(1);
const num2 = ref(3.5);
const isDisabled = ref(false);
const isShowScore = ref(true);
const isAllowHalf = ref(true);
const isSize = ref(false);
const isIcon = ref(false);
</script>

View File

@@ -0,0 +1,286 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-select-date
v-model="form.date1"
type="date"
@change="onDateChange"
></cl-select-date>
</demo-item>
<demo-item :label="t('固定开始、结束日期')">
<cl-select-date
v-model="form.date3"
start="2025-06-01"
end="2027-08-01"
type="date"
></cl-select-date>
</demo-item>
<demo-item :label="t('自定义触发器')">
<view class="flex flex-row">
<cl-button @tap="openSelect4">{{ t("打开选择器") }}</cl-button>
</view>
<cl-select-date
ref="selectRef4"
v-model="form.date4"
type="date"
:show-trigger="false"
></cl-select-date>
</demo-item>
<demo-item :label="t('范围选择')">
<cl-text :pt="{ className: 'mb-3' }">{{ form.date5 }}</cl-text>
<cl-select-date v-model:values="form.date5" type="date" rangeable></cl-select-date>
</demo-item>
<demo-item :label="t('自定义快捷选项')">
<cl-select-date
v-model:values="form.date6"
type="date"
rangeable
:shortcuts="shortcuts"
></cl-select-date>
</demo-item>
<demo-item :label="t('自定义')">
<cl-select-date
v-model="form.date7"
:type="type"
:label-format="labelFormat"
:disabled="isDisabled"
></cl-select-date>
<cl-list
border
:pt="{
className: 'mt-3'
}"
>
<cl-list-item label="YYYY">
<cl-switch v-model="isYear"></cl-switch>
</cl-list-item>
<cl-list-item label="YYYY-MM">
<cl-switch v-model="isMonth"></cl-switch>
</cl-list-item>
<cl-list-item
label="YYYY-MM-DD"
:pt="{
label: {
className: 'flex-[2]'
}
}"
>
<cl-switch v-model="isDate"></cl-switch>
</cl-list-item>
<cl-list-item
label="YYYY-MM-DD HH"
:pt="{
label: {
className: 'flex-[2]'
}
}"
>
<cl-switch v-model="isHour"></cl-switch>
</cl-list-item>
<cl-list-item
label="YYYY-MM-DD HH:mm"
:pt="{
label: {
className: 'flex-[2]'
}
}"
>
<cl-switch v-model="isMinute"></cl-switch>
</cl-list-item>
<cl-list-item
label="YYYY-MM-DD HH:mm:ss"
:pt="{
label: {
className: 'flex-[2]'
}
}"
>
<cl-switch v-model="isSecond"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('标签格式化')">
<cl-switch v-model="isFormat"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { computed, reactive, ref } from "vue";
import DemoItem from "../components/item.uvue";
import { t } from "@/locale";
import { useUi, type ClSelectDateShortcut } from "@/uni_modules/cool-ui";
import { dayUts } from "@/cool";
const ui = useUi();
// 测试日期选择变化事件
function onDateChange(value: string) {
console.log("日期选择变化:", value);
ui.showToast({
message: `选择了日期: ${value}`,
type: "success"
});
}
type Form = {
date1: string;
date2: string;
date3: string;
date4: string;
date5: string[];
date6: string[];
date7: string;
};
const form = reactive<Form>({
date1: "2023-06-24",
date2: "",
date3: "",
date4: "",
date5: [],
date6: [],
date7: ""
});
const isDisabled = ref(false);
const isYear = ref(false);
const isMonth = ref(false);
const isDate = ref(true);
const isHour = ref(false);
const isMinute = ref(false);
const isSecond = ref(false);
const isFormat = ref(false);
const type = computed(() => {
if (isSecond.value) {
return "second";
}
if (isMinute.value) {
return "minute";
}
if (isHour.value) {
return "hour";
}
if (isDate.value) {
return "date";
}
if (isMonth.value) {
return "month";
}
if (isYear.value) {
return "year";
}
return "second";
});
const labelFormat = computed(() => {
if (isFormat.value) {
if (isSecond.value) {
return "YYYY年MM月DD日 HH时mm分ss秒";
}
if (isMinute.value) {
return "YYYY年MM月DD日 HH时mm分";
}
if (isHour.value) {
return "YYYY年MM月DD日 HH时";
}
if (isDate.value) {
return "YYYY年MM月DD日";
}
if (isMonth.value) {
return "YYYY年MM月";
}
if (isYear.value) {
return "YYYY年";
}
} else {
if (isSecond.value) {
return "YYYY-MM-DD HH:mm:ss";
}
if (isMinute.value) {
return "YYYY-MM-DD HH:mm";
}
if (isHour.value) {
return "YYYY-MM-DD HH";
}
if (isDate.value) {
return "YYYY-MM-DD";
}
if (isMonth.value) {
return "YYYY-MM";
}
if (isYear.value) {
return "YYYY";
}
}
return "YYYY-MM-DD HH:mm:ss";
});
const selectRef4 = ref<ClSelectDateComponentPublicInstance | null>(null);
function openSelect4() {
selectRef4.value!.open((value) => {
ui.showToast({
message: `你选择了:${value}`
});
});
}
const shortcuts = ref<ClSelectDateShortcut[]>([
{
label: "昨日",
value: [dayUts().subtract(1, "day").format("YYYY-MM-DD"), dayUts().format("YYYY-MM-DD")]
},
{
label: "本周",
value: [
dayUts().startOf("week").add(1, "day").format("YYYY-MM-DD"),
dayUts().endOf("week").add(1, "day").format("YYYY-MM-DD")
]
},
{
label: "本月",
value: [
dayUts().startOf("month").format("YYYY-MM-DD"),
dayUts().endOf("month").format("YYYY-MM-DD")
]
}
]);
</script>

View File

@@ -0,0 +1,123 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-select-time v-model="form.time1"></cl-select-time>
</demo-item>
<demo-item :label="t('自定义触发器')">
<view class="flex flex-row">
<cl-button @tap="openSelect2">{{ t("打开选择器") }} </cl-button>
</view>
<cl-select-time
ref="selectRef2"
v-model="form.time2"
:show-trigger="false"
></cl-select-time>
</demo-item>
<demo-item :label="t('自定义')">
<cl-select-time
v-model="form.time3"
:disabled="isDisabled"
:label-format="labelFormat"
:type="type"
></cl-select-time>
<cl-list
border
:pt="{
className: 'mt-3'
}"
>
<cl-list-item :label="t('时')">
<cl-switch v-model="isHour"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('时:分')">
<cl-switch v-model="isMinute"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('时:分:秒')">
<cl-switch v-model="isSecond"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('标签格式化')">
<cl-switch v-model="isFormat"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { computed, reactive, ref } from "vue";
import DemoItem from "../components/item.uvue";
import { useUi } from "@/uni_modules/cool-ui";
import { t } from "@/locale";
const ui = useUi();
type Form = {
time1: string;
time2: string;
time3: string;
};
const form = reactive<Form>({
time1: "",
time2: "",
time3: ""
});
const isDisabled = ref(false);
const isFormat = ref(false);
const isHour = ref(false);
const isMinute = ref(false);
const isSecond = ref(true);
const selectRef2 = ref<ClSelectTimeComponentPublicInstance | null>(null);
function openSelect2() {
selectRef2.value!.open((value) => {
ui.showToast({
message: `你选择了:${value}`
});
});
}
const type = computed(() => {
if (isHour.value) {
return "hour";
}
if (isMinute.value) {
return "minute";
}
return "second";
});
const labelFormat = computed(() => {
if (isFormat.value) {
switch (type.value) {
case "hour":
return "{H}时";
case "minute":
return "{H}时{m}分";
case "second":
return "{H}时{m}分{s}秒";
default:
return null;
}
} else {
return null;
}
});
</script>

View File

@@ -0,0 +1,388 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-select v-model="form.selected" :options="options"></cl-select>
</demo-item>
<demo-item :label="t('自定义触发器')">
<view class="flex flex-row">
<cl-button @tap="openSelect2">{{ t("打开选择器") }}</cl-button>
</view>
<cl-select
ref="selectRef2"
v-model="form.selected2"
:options="options2"
:show-trigger="false"
></cl-select>
</demo-item>
<demo-item :label="t('多列')">
<demo-tips>
{{ t("通过 children 配置多级数据,并使用 column-count 参数指定显示的列数") }}
</demo-tips>
<cl-select
v-model="form.selected3"
:options="options3"
:column-count="3"
></cl-select>
</demo-item>
<demo-item :label="t('弹窗中使用')">
<cl-button @tap="visible3 = true">{{ t("打开") }}</cl-button>
<cl-popup v-model="visible3" direction="center" size="80%" :title="t('选择地区')">
<view class="p-3 pt-0">
<demo-tips>
H5 和 APP 端通过 teleport 实现弹窗内的选择器使用,小程序端则通过
root-portal 实现。
</demo-tips>
<cl-select
v-model="form.selected3"
:options="options3"
:column-count="3"
></cl-select>
</view>
</cl-popup>
</demo-item>
<demo-item :label="t('自定义')">
<cl-text
:pt="{
className: 'mb-3 text-sm p-3 bg-surface-100 dark:!bg-surface-700 rounded-lg'
}"
v-if="form.selected4 != null && isShowValue"
>
{{ t("绑定值") }}{{ form.selected4 }}
</cl-text>
<cl-select
v-model="form.selected4"
:options="options"
:disabled="isDisabled"
:show-cancel="isShowCancel"
:confirm-text="isButtonText ? t('下一步') : t('确定')"
:cancel-text="isButtonText ? t('关闭') : t('取消')"
></cl-select>
<cl-list
border
:pt="{
className: 'mt-3'
}"
>
<cl-list-item :label="t('显示取消按钮')">
<cl-switch v-model="isShowCancel"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('修改按钮文案')">
<cl-switch v-model="isButtonText"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('显示绑定值')">
<cl-switch v-model="isShowValue"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
<demo-item :label="t('空数据')">
<cl-select v-model="form.selected" :options="options4"></cl-select>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { reactive, ref } from "vue";
import DemoItem from "../components/item.uvue";
import DemoTips from "../components/tips.uvue";
import { useUi, type ClSelectOption } from "@/uni_modules/cool-ui";
import { t } from "@/locale";
const ui = useUi();
const selectRef2 = ref<ClSelectComponentPublicInstance | null>(null);
const isShowCancel = ref(true);
const isButtonText = ref(false);
const isDisabled = ref(false);
const isShowValue = ref(false);
type Form = {
selected: number | null; // 参数 clear 需要指定类型带有 null
selected2: string;
selected3: number[];
selected4: number | null;
};
const form = reactive<Form>({
selected: null,
selected2: "2",
selected3: [],
selected4: 3
});
const options = ref<ClSelectOption[]>([
{
label: "HTML",
value: 1
},
{
label: "CSS",
value: 2
},
{
label: "JavaScript",
value: 3
},
{
label: "Node",
value: 4
},
{
label: "Vite",
value: 5
},
{
label: "Webpack",
value: 6
}
]);
const options2 = ref<ClSelectOption[]>([
{
label: "Vue",
value: "1"
},
{
label: "React",
value: "2"
},
{
label: "Angular",
value: "3"
},
{
label: "Svelte",
value: "4"
}
]);
const options3 = ref<ClSelectOption[]>([
{
label: "福建省",
value: 1,
children: [
{
label: "福州市",
value: 1,
children: [
{
label: "鼓楼区",
value: 1
},
{
label: "台江区",
value: 2
},
{
label: "仓山区",
value: 3
},
{
label: "马尾区",
value: 4
}
]
},
{
label: "厦门市",
value: 2,
children: [
{
label: "思明区",
value: 1
},
{
label: "湖里区",
value: 2
},
{
label: "集美区",
value: 3
},
{
label: "海沧区",
value: 4
}
]
},
{
label: "泉州市",
value: 3,
children: [
{
label: "鲤城区",
value: 1
},
{
label: "丰泽区",
value: 2
},
{
label: "洛江区",
value: 3
},
{
label: "泉港区",
value: 4
}
]
}
]
},
{
label: "浙江省",
value: 2,
children: [
{
label: "杭州市",
value: 1,
children: [
{
label: "上城区",
value: 1
},
{
label: "下城区",
value: 2
},
{
label: "江干区",
value: 3
},
{
label: "拱墅区",
value: 4
}
]
},
{
label: "宁波市",
value: 2,
children: [
{
label: "海曙区",
value: 1
},
{
label: "江北区",
value: 2
},
{
label: "北仑区",
value: 3
}
]
}
]
},
{
label: "湖南省",
value: 3,
children: [
{
label: "长沙市",
value: 1,
children: [
{
label: "芙蓉区",
value: 1
},
{
label: "天心区",
value: 2
},
{
label: "岳麓区",
value: 3
}
]
},
{
label: "株洲市",
value: 2,
children: [
{
label: "荷塘区",
value: 1
},
{
label: "芦淞区",
value: 2
}
]
}
]
},
{
label: "江西省",
value: 4,
children: [
{
label: "南昌市",
value: 1,
children: [
{
label: "东湖区",
value: 1
},
{
label: "西湖区",
value: 2
},
{
label: "青云谱区",
value: 3
}
]
},
{
label: "九江市",
value: 2,
children: [
{
label: "浔阳区",
value: 1
},
{
label: "濂溪区",
value: 2
}
]
}
]
}
]);
const options4 = ref<ClSelectOption[]>([]);
function openSelect2() {
selectRef2.value!.open((value) => {
const d = options2.value.find((item) => item.value == value);
ui.showToast({
message: `你选择了 ${value} : ${d?.label}`
});
});
}
const visible3 = ref(false);
</script>

View File

@@ -0,0 +1,86 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-slider v-model="num"></cl-slider>
</demo-item>
<demo-item :label="t('范围选择')">
<cl-text
:pt="{
className: 'mb-3'
}"
>{{ num2[0] }} {{ num2[1] }}</cl-text
>
<cl-slider v-model:values="num2" range></cl-slider>
</demo-item>
<demo-item :label="t('自定义')">
<cl-slider
v-model="num3"
:disabled="isDisabled"
:show-value="isShowValue"
:block-size="isSize ? 50 : 40"
:track-height="isSize ? 12 : 8"
:step="isStep ? 10 : 1"
:max="isMax ? 50 : 100"
:pt="{
thumb: {
className: isColor ? '!bg-red-500' : ''
},
progress: {
className: isColor ? '!bg-red-200' : ''
}
}"
></cl-slider>
<cl-list
border
:pt="{
className: 'mt-3'
}"
>
<cl-list-item :label="t('显示值')">
<cl-switch v-model="isShowValue"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('步长10')">
<cl-switch v-model="isStep"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('滑块大点')">
<cl-switch v-model="isSize"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('换个颜色')">
<cl-switch v-model="isColor"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('最大50')">
<cl-switch v-model="isMax"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import DemoItem from "../components/item.uvue";
import { t } from "@/locale";
const num = ref(60);
const num2 = ref<number[]>([10, 20]);
const num3 = ref(35);
const isDisabled = ref(false);
const isShowValue = ref(true);
const isStep = ref(false);
const isSize = ref(false);
const isMax = ref(false);
const isColor = ref(false);
</script>

View File

@@ -0,0 +1,92 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-switch v-model="checked"></cl-switch>
</demo-item>
<demo-item :label="t('自定义颜色')">
<view class="flex flex-row">
<cl-switch
v-model="checked"
:pt="{
className: 'mr-5',
track: {
className: '!bg-red-100'
},
thumb: {
className: '!bg-red-500'
}
}"
></cl-switch>
<cl-switch
v-model="checked"
:pt="{
track: {
className: '!bg-purple-100'
},
thumb: {
className: '!bg-purple-500'
}
}"
></cl-switch>
</view>
</demo-item>
<demo-item :label="t('自定义')">
<cl-switch
v-model="checked"
:loading="isLoading"
:disabled="isDisabled"
:height="isSize ? 60 : 48"
:width="isSize ? 100 : 80"
:pt="{
track: {
className: parseClass([[isCustom, '!rounded-md']])
},
thumb: {
className: parseClass([[isCustom, '!rounded-md']])
}
}"
></cl-switch>
<cl-list
border
:pt="{
className: 'mt-3'
}"
>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('加载中')">
<cl-switch v-model="isLoading"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('大一点')">
<cl-switch v-model="isSize"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('正方形')">
<cl-switch v-model="isCustom"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import DemoItem from "../components/item.uvue";
import { parseClass } from "@/cool";
import { t } from "@/locale";
const checked = ref(false);
const isDisabled = ref(false);
const isLoading = ref(false);
const isSize = ref(false);
const isCustom = ref(false);
</script>

View File

@@ -0,0 +1,67 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-textarea></cl-textarea>
</demo-item>
<demo-item :label="t('自定义')">
<cl-textarea
v-model="content"
:border="isBorder"
:disabled="isDisabled"
:show-word-limit="isShowCount"
:auto-height="isAutoHeight"
:pt="{
className: parseClass({
'!bg-sky-100': isColor,
'!border-sky-700': isColor
}),
inner: {
className: parseClass({
'text-sky-700': isColor
})
}
}"
></cl-textarea>
<cl-list border :pt="{ className: 'mt-5' }">
<cl-list-item :label="t('边框')">
<cl-switch v-model="isBorder"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('显示字数')">
<cl-switch v-model="isShowCount"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('自动增高')">
<cl-switch v-model="isAutoHeight"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('禁用')">
<cl-switch v-model="isDisabled"></cl-switch>
</cl-list-item>
<cl-list-item :label="t('其他颜色')">
<cl-switch v-model="isColor"></cl-switch>
</cl-list-item>
</cl-list>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import DemoItem from "../components/item.uvue";
import { parseClass } from "@/cool";
import { t } from "@/locale";
const content = ref("Cool Unix");
const isBorder = ref(true);
const isShowCount = ref(true);
const isDisabled = ref(false);
const isColor = ref(false);
const isAutoHeight = ref(false);
</script>

View File

@@ -0,0 +1,50 @@
<template>
<cl-page>
<view class="p-3">
<demo-item :label="t('基础用法')">
<cl-upload v-model="form.upload1" test></cl-upload>
</demo-item>
<demo-item :label="t('禁用')">
<cl-upload v-model="form.upload1" disabled test></cl-upload>
</demo-item>
<demo-item :label="t('自定义图标、文字、大小')">
<cl-upload
v-model="form.upload1"
icon="id-card-line"
:text="t('上传证件照')"
:width="300"
:height="200"
test
></cl-upload>
</demo-item>
<demo-item :label="t('多选')">
<cl-upload multiple v-model="form.upload2" test></cl-upload>
</demo-item>
<demo-item :label="t('限制 3 个')">
<cl-upload multiple :limit="3" v-model="form.upload3" test></cl-upload>
</demo-item>
</view>
</cl-page>
</template>
<script lang="ts" setup>
import { t } from "@/locale";
import DemoItem from "../components/item.uvue";
import { reactive } from "vue";
type Form = {
upload1: string;
upload2: string[];
upload3: string[];
};
const form = reactive<Form>({
upload1: "",
upload2: [],
upload3: []
});
</script>