2.0.32 • Published 1 month ago

@qingbing/ts-v3-xz-form v2.0.32

Weekly downloads
-
License
MIT
Repository
-
Last release
1 month ago

XzForm 插件介绍

1. 概要说明

1.1 地址

1.2 插件描述

以 vue3 + element-plus 为基础封装的 form 表单组件

1.3 重要依赖

  • @element-plus/icons-vue: ^2.3.1
  • @qingbing/ts-v3-utils: ^1.0.1
  • @qingbing/ts-v3-xz-editor: ^1.0.1
  • @qingbing/ts-v3-element-plus: ^2.1.3
  • @qingbing/ts-v3-json-editor: ^2.1.6
  • @qingbing/ts-v3-md-editor: ^2.0.4
  • axios: ^1.6.8
  • element-plus: ^2.6.3
  • vue: ^3.4.21

1.4 插件安装

# yarn 安装
yarn add @qingbing/ts-v3-xz-form

# npm 安装
npm i @qingbing/ts-v3-xz-form

2. 包说明

2.1 属性说明

该包主要封装了 vue3 下表单组件的使用, 重要提供以下五个属性参数

属性名类型是否必需默认值意义
isFormbooleantrue是否作为表单来处理
itemsRecord<string, TXzFormItem>-传递的字段结果集
formDataTRecord-表单操作数据
viewFieldsstring[][]信息展示字段
showFieldsstring[][]form编辑字段

该组件的特殊之处, 在于不需要自己手动构建以上后续的四个参数, 组件提供了一个针对组件参数的工具,使用和理解该工具的配置,该组件也就没有难点了。

2.2 事件说明

事件名类型意义
--

2.3 实例暴露说明

属性名类型
-

3. 配置工具介绍

3.1 组件工具的引入和基础使用

import { XzFormItemParse } from '@qingbing/ts-v3-xz-form'

const { items, viewFields, showFields, formData, rules } = XzFormItemParse.instance([
    {
        input_type: "text-view",
        field: "uid",
        default: "11",
        label: "UID",
        rules: [{ type: "required" }],
    },
    {
        input_type: "input-text",
        field: "username",
        default: "",
        label: "用户名",
        rules: [{ required: true, type: "username" }],
    }
])
    .setViewFields(['username']) // 设置展示字段,设置后的字段,无论设置的 输入类型 如何, 得到的结果就是采取较好的方式提供用户浏览
    .setShowFields(['async_remote']) // 表单显示字段, 不设置显示全部
    .done() // 解析完毕得到结果

3.2 工具入口原型

如果向了解具体的 验证规则解析,参考 XzFormRuleParse 即可, 这里不赘述。

export declare class XzFormItemParse {
    /**
     * 获取字段处理实例
     * @param items 表单配置项目
     * @param formData 字段默认赋值
     * @returns XzFormItemParse
     */
    static instance(items: TXzFormItem[], formData?: TRecord): XzFormItemParse;
    /**
     * @param fields 展示字段集合
     * @returns XzFormItemParse
     */
    setViewFields(fields: string[]): XzFormItemParse;
    /**
     * @param fields 表单显示字段, 不设置显示全部
     * @returns XzFormItemParse
     */
    setShowFields(fields: string[]): XzFormItemParse;
    /**
     * 解析字段及规则信息并返回
     *
     * @returns { items, viewFields, showFields, formData, rules }
         */
    done(): {
         items: TXzFormItem[];
         viewFields: string[];
         showFields: string[];
         formData: TRecord;
         rules: Record<string, FormItemRule[]>;
    };
}

3.3 工具使用主要掌握以下配置规则即可

3.3.1 配置规则原型

import type { TObject, TRecord } from '@qingbing/ts-v3-utils'
import type { FormItemRule, UploadRequestOptions } from 'element-plus'
import type { RuleType, SyncValidateResult, Value } from 'async-validator'

export type TXzFormOptions = {
    name: string
}

// 支持的表单输入方式
export type TXzFormInputType =
    | 'text-view' // 文本显示
    | 'input-text' // 文本框编辑
    | 'input-password' // 密码框编辑
    | 'input-area' // 文本域编辑
    | 'input-number' // 数字输入
    | 'input-radio' // 单选按钮组
    | 'input-checkbox' // 复选按钮组
    | 'input-select' // 选择框
    | 'switch' // 开关控制
    | 'cascader' // 级联选择
    | 'slider' // 滑块输入
    | 'rate' // 评分
    | 'color' // 取色器
    | 'uploader' // 上传图片
    | 'time-select' // 时间选择器
    | 'time-picker' // 时间选择器
    | 'date-picker' // 日期选择器
    | 'auto-complete' // 自动补全输入
    | 'json-editor' // json-editor
    | 'md-editor' // md-editor
    | 'content-editor' // text-editor

// 表单验证类型扩展
export type TXzFormRuleItem = Omit<FormItemRule, 'type'> & {
    type?:
    | RuleType
    | 'required'
    | 'id-card' // 身份证号
    | 'qq' // qq
    | 'username' // 用户名
    | 'password' // 密码
    | 'zipcode' // 邮编
    | 'mobile' // 手机
    | 'phone' // 座机
    | 'contact' // 联系人(手机 | 座机)
    | 'fax' // 传真
    | 'ipv4' // ipv4 地址
    | 'color' // 颜色值
    | 'rate' // 评分
    | 'slider' // 滑块
    | 'switch' // 开关
    | 'confirm' // 确认
    | 'callback' // 回调函数
    fullField?: string // bug for element-plus
    params?: TObject // 回调或后端请求时携带的额外参数
    callback?: TXzFormCallback // 同步回调函数,配合 type == callback 使用
    asyncCallback?: TXzFormAsyncCallback // 异步回调函数,配合 type == callback 使用, 异步和同步可以同时使用,不建议
}

// 表单项目的配置字段配置类型
export type TXzFormItem = {
    field: string // 操作字段
    label: string // 显示标签
    default?: any // 默认值
    input_type: TXzFormInputType // 表单输入类型
    exts?: TRecord // 额外参数
    rules?: TXzFormRuleItem[] // 规则
}

/**
 * 项目中的 option 选项类型
 */
export type TXzFormInputOption = {
    id?: any,
    value: PropertyKey,
    label: string
}

/**
 * 异步验证回调函数
 */
export type TXzFormAsyncCallback = (
    callback: (error?: string | Error) => void,
    value: unknown,
    formData: TRecord,
    params: TRecord
) => void | Promise<void>

/**
 * 同步验证回调函数
 */
export type TXzFormCallback = (
    callback: (error?: string | Error) => void,
    value: Value,
    formData: TRecord,
    params: TRecord
) => SyncValidateResult | void

/**
 * select 远端搜索并获取选项卡的函数类型
 */
export type TXzFormRemoteOption = (
    keyword: string,
    formData: TRecord,
    callback: ((ops: TXzFormInputOption[]) => void)
) => void

/**
 * 自定义上传的函数类型
 */
export type TXzFormCustomUpload = (
    options: UploadRequestOptions,
    formData: TRecord,
    callback: {
        success: (fileUrl: string, message?: string) => void,
        failure: (message: string) => void,
    }
) => void

3.4.1 TXzFormItem 属性说明

key类型必须意义
fieldstring操作字段
labelstring显示标签
defaultany默认值
input_typeTXzFormInputType表单输入类型
extsTRecord额外参数
rulesTXzFormRuleItem[]规则

3.4.2 TXzFormItem.input_type 说明

类型
text-view文本显示
input-text文本框编辑
input-password密码框编辑
input-area文本域编辑
input-number数字输入
input-radio单选按钮组
input-checkbox复选按钮组
input-select选择框
switch开关控制
cascader级联选择
slider滑块输入
rate评分
color取色器
uploader上传图片
time-select时间选择器
time-picker时间选择器
date-picker日期选择器
auto-complete自动补全输入
json-editorjson-editor
md-editormd-editor
content-editortext-editor

3.4.3 TXzFormItem.rules(TXzFormRuleItem[]) 说明

规则参考 async-validator.RuleItem, 这里介绍下增加或不同的内容

类型必填说明
typestring支持原有的所有类型,同时还提供几种扩展类型
fullFieldstring该字段不算新增,卡bug,验证不过时的字段替换位置,不设置使用 TXzFormItem.label 字段顶替
paramsTObject回调或后端请求时携带的额外参数
callbackTXzFormCallback同步回调函数,配合 type == callback 使用
asyncCallbackTXzFormAsyncCallback异步回调函数,配合 type == callback 使用

callback 和 asyncCallback 可以同时使用,不建议

3.4.3 TXzFormItem.rules(TXzFormRuleItem[]).type 说明

组件支持所有原有的类型,同时扩展如下几种常用验证

类型
required必填,不必须的,常规可使用 rule.required=true
id-card身份证号
qqqq
username用户名
password密码
zipcode邮编
mobile手机
phone座机
contact联系人(手机,座机)
fax传真
ipv4ipv4 地址
color颜色值
rate评分
slider滑块
switch开关
confirm确认
callback回调函数

3.4.4 TXzFormItem.exts 说明

该参数主要提供了不同规则、不同输入类型的个性化属性,全部罗列在了该字段里面 对于输入参数,提供了 element-plus 官网组件属性中个人觉得有用的大部分属性 具体配置可参考底部示例, 提供几个组件参数配置地址参考:

json-editor: @qingbing/ts-v3-json-editor md-editor: @qingbing/ts-v3-md-editor content-editor: @qingbing/ts-v3-xz-editor

对于 element-plus 封装的表单项, 以 switch 为例: 属性参考网址

内部规则代码如下: (ps: 其他element-plus 组件的规则解析类似,不再赘述)

const binding: TRecord = {}

binding.size = getExtData<string>('size', 'default')
binding.activeText = getExtData<string>('active-text', '')
binding.inactiveText = getExtData<string>('inactive-text', '')

const fileType = typeof props.formData[props.item.field]
// active-value 处理
let activeValue = getExtData<string | number | boolean | undefined>('active-value', undefined)
if (activeValue === undefined) {
    switch (fileType) {
        case "string":
            activeValue = "1"
            break;
        case "number":
            activeValue = 1
            break;
        default:
            activeValue = true
            break;
    }
}
binding.activeValue = activeValue
// inactive-value 处理
let inactiveValue = getExtData<string | number | boolean | undefined>('inactive-value', undefined)
if (inactiveValue === undefined) {
    switch (fileType) {
        case "string":
            inactiveValue = "0"
            break;
        case "number":
            inactiveValue = 0
            break;
        default:
            inactiveValue = false
            break;
    }
}
binding.inactiveValue = inactiveValue

const width = getExtData<string | number | false>('width', false)
false !== width && (binding.width = width)

const activeIcon = getExtData<string | Component | false>('active-icon', false)
false !== activeIcon && (binding.activeIcon = activeIcon)

const inactiveIcon = getExtData<string | Component | false>('inactive-icon', false)
false !== inactiveIcon && (binding.inactiveIcon = inactiveIcon)

if (props.isText) {
    binding.disabled = true
} else {
    binding.disabled = getExtData<boolean>('disabled', false)
}

4. item 生成工具

提供 快速生成大多数 form-item 的工具 XzFormItemMachine, 基础的类型验证以包含, 额外的演奏需要自行 mixins. 使用示例如下

import { XzFormItemMachine } from '@qingbing/ts-v3-xz-form'

const items= {
    uid: mixins(XzFormItemMachine('textView', 'id', 'UID')),
    nickname: mixins(XzFormItemMachine('text', 'nickname', '用户昵称'), {
        rules: [{ type: "required" }],
    }),
}

5. 示例

5.1 建议全局注册验证提示的中文包,不注册也不影响组件使用,那样每个规则最好都带上 message 就好

// main.ts
import '@qingbing/ts-v3-xz-form/dist/messages'

5.2 全局注册使用

  • 一旦注册, XzForm 作为组件全局通用
  • 使用方法参考 4.2 模板组件使用, 去掉组件导入的语句即可
  • 如果可以,建议全局安装并注册使用 @element-plus/icons-vue, 测试过程中组件手动引入时报错(或者全局注册下 Plus 组件即可,组件只在 uploader 时使用了该组件, 如果不使用 uploader 输入不注册也可)
  • 对于样式的处理,md-editor 和 wangeditor 的样式比较大,最好按需导入, 如果不会使用到,建议不 import 到项目中
// main.ts

// icon 全导入并注册
// import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
//   app.component(key, component)
// }

// icon 导入并注册 Plus 插件
// import { Plus } from '@element-plus/icons-vue'
// app.component('Plus', Plus)

// 导入表单组件
import '@qingbing/ts-v3-xz-form/dist/style.css'
import { XzFormPlugin } from '@qingbing/ts-v3-xz-form'
app.use(XzFormPlugin, {
  name: 'XzForm',
  options: {}
})

3.2 模板组件使用

<template>
    <el-form ref="refForm" :model="formData" :rules="rules" label-width="160px">

        <XzForm :isForm="isForm" :items="items" :formData="formData" :viewFields="viewFields" :showFields="showFields" />

        <el-form-item>
            <el-button type="primary" @click="submitForm(refForm)">Create </el-button>
            <el-button @click="resetForm(refForm)">Reset</el-button>
        </el-form-item>
    </el-form>

    <el-row>
        <el-col :span="8" style="border-right: 1px solid #ccc;">
            <p>items</p>
            <pre><code>{{ items }}</code></pre>
        </el-col>
        <el-col :span="8" style="border-right: 1px solid #ccc;">
            <p>rules</p>
            <pre><code>{{ rules }}</code></pre>
        </el-col>
        <el-col :span="8">
            <p>formData</p>
            <pre><code>{{ formData }}</code></pre>
        </el-col>
    </el-row>
</template>

<script lang="ts" setup>
import 'md-editor-v3/lib/style.css'; // md-editor 编辑器样式
import 'md-editor-v3/lib/preview.css'; // md-editor 编辑器预览样式

import '@wangeditor/editor/dist/css/style.css' // wangeditor 样式表
import "@qingbing/ts-v3-xz-editor/dist/css/preview.css" // xz-editor 组件定义的一套编辑器基础样式

import '@qingbing/ts-v3-xz-form/dist/style.css' //  xz-form 组件样式(整合了 json-editor 和 xz-editor 组件样式)

import type { FormInstance, UploadRawFile } from 'element-plus'
import type { TRecord } from "@qingbing/ts-v3-utils";
import type { TXzFormRemoteOption, TXzFormCustomUpload, TXzFormItem } from "@qingbing/ts-v3-xz-form";
import { XzForm, XzFormItemParse, XzFormItemMachine } from "@qingbing/ts-v3-xz-form";
import { mixins } from "@qingbing/ts-v3-utils";
import { ref } from 'vue'
import request from "axios";

const isForm = ref(true)
const refForm = ref<FormInstance>()

const submitForm = (form: FormInstance | undefined) => {
    if (!form) { return }
    form.validate((valid) => {
        if (valid) {
            console.log('哦业,验证都通过了!')
        } else {
            console.log('哎呀,验证到有错误呢!')
            return false
        }
    })
}

const resetForm = (form: FormInstance | undefined) => {
    if (!form) { return }
    form.resetFields()
}

const fetchRemote = (data?: TRecord) => {
    return request.create({
        baseURL: 'http://mock.qiyezhu.net/mock/64e35b8e4a2b7b001dd2e4ec/example/ajax-test', // 默认就是 "/",
        timeout: 5000, // 5000毫秒,5秒
        headers: {
            'Content-Type': 'application/json;charset=utf-8'
        }
    }).post('/', data ?? {})
}

const remoteFunc: TXzFormRemoteOption = (keyword, _, cb) => {
    request.create({
        baseURL: 'http://mock.qiyezhu.net/mock/64e35b8e4a2b7b001dd2e4ec/example/select-options',
        timeout: 5000, // 5000毫秒,5秒
        headers: {
            'Content-Type': 'application/json;charset=utf-8'
        }
    })
        .post('/', { keyword, })
        .then(res => {
            cb(res.data.data)
        })
        .catch(err => err)
}

const customUpload: TXzFormCustomUpload = (options, data: TRecord, callback) => {
    const form = new FormData();
    form.append('file', options.file);
    form.append('name', 'qingbing');
    request.post('http://mock.qiyezhu.net/mock/64e35b8e4a2b7b001dd2e4ec/example/upload-avatar', form)
        .then(res => {
            callback.success(res.data.data.url, "ok")
        }).catch(err => callback.success(err.message))
}
const { items, viewFields, showFields, formData, rules } = XzFormItemParse.instance([
    {
        input_type: "text-view",
        field: "uid",
        default: "11",
        label: "UID",
        rules: [{ type: "required" }],
    },
    {
        input_type: "auto-complete",
        field: "suggestion",
        default: "",
        label: "建议输入",
        exts: {
            fetchSuggestions: (keyword: string, cb: (arg: any) => void) => {
                console.log(keyword);
                request.create({
                    baseURL: 'http://mock.qiyezhu.net/mock/64e35b8e4a2b7b001dd2e4ec/example/fetch-suggestion',
                    timeout: 5000, // 5000毫秒,5秒
                    headers: {
                        'Content-Type': 'application/json;charset=utf-8'
                    }
                })
                    .post('/', { keyword, })
                    .then(res => {
                        cb(res.data.data)
                    })
                    .catch(err => err)
            }
        },
    },
    {
        input_type: "input-select",
        field: "remote",
        default: "",
        label: "UID",
        exts: {
            remoteMethod: remoteFunc
        },
    },
    {
        input_type: "input-text",
        field: "username",
        default: "",
        label: "用户名",
        rules: [{ required: true, type: "username" }],
    },
    {
        input_type: "input-text",
        field: "nickname",
        default: "",
        label: "昵称",
        rules: [{ type: "required" }],
    },
    {
        input_type: "input-text",
        field: "email",
        default: "",
        label: "邮箱",
        rules: [{ required: true, type: "email" }],
    },
    {
        input_type: "input-text",
        field: "id_card",
        default: "",
        label: "身份证",
        rules: [{ required: true, type: "id-card" }],
    },
    {
        input_type: "input-text",
        field: "qq",
        default: "",
        label: "QQ",
        rules: [{ required: true, type: "qq" }],
    },
    {
        input_type: "input-text",
        field: "zipcode",
        default: "",
        label: "邮编",
        rules: [{ required: true, type: "zipcode" }],
    },
    {
        input_type: "input-text",
        field: "mobile",
        default: "",
        label: "手机",
        rules: [{ required: true, type: "mobile" }],
    },
    {
        input_type: "input-text",
        field: "phone",
        default: "",
        label: "座机",
        rules: [{ required: true, type: "phone" }],
    },
    {
        input_type: "input-text",
        field: "contact",
        default: "",
        label: "联系人",
        rules: [{ required: true, type: "contact" }],
    },
    {
        input_type: "input-text",
        field: "fax",
        default: "",
        label: "传真",
        rules: [{ required: true, type: "fax" }],
    },
    {
        input_type: "input-text",
        field: "ipv4",
        default: "",
        label: "ipv4 地址",
        rules: [{ required: true, type: "ipv4" }],
    },
    {
        input_type: "color",
        field: "color",
        default: "",
        label: "颜色",
        rules: [{ required: true, type: "color" }],
    },
    {
        input_type: "rate",
        field: "rate",
        default: 0,
        label: "评分",
        rules: [{ required: true, type: "rate" }],
    },
    {
        input_type: "slider",
        field: "slider",
        default: '',
        label: "滑块",
        exts: {
            min: 0,
            max: 10
        },
        rules: [{ required: true, type: "slider" }],
    },
    {
        input_type: "switch",
        field: "switch",
        default: 1,
        label: "开关",
        rules: [{ required: true, type: "switch" }],
        exts: {
            'inactiveValue': 0,
            'activeValue': 1,
        }
    },
    {
        input_type: "input-area",
        field: "info",
        default: "",
        label: "个人简介",
        rules: [{ type: "required" }],
    },
    {
        input_type: "input-number",
        field: "age",
        default: 0,
        label: "年龄",
        exts: {
            min: 0,
            max: 127
        },
        rules: [{ type: "number", required: true }],
    },
    {
        input_type: "input-radio",
        field: "fav_fruit",
        default: "banana",
        label: "最爱水果",
        exts: {
            options: [
                { value: "apple", label: "苹果" },
                { value: "pear", label: "梨子" },
                { value: "banana", label: "香蕉" },
                { value: "pomegranate", label: "石榴" },
                { value: "persimmon", label: "柿子" },
            ]
        },
        rules: [{ required: true, type: "enum" }],
    },
    {
        input_type: "input-checkbox",
        field: "like_fruit",
        default: ["apple", "banana"],
        label: "喜欢水果",
        exts: {
            min: 2,
            max: 4,
            options: [
                { value: "apple", label: "苹果" },
                { value: "pear", label: "梨子" },
                { value: "banana", label: "香蕉" },
                { value: "pomegranate", label: "石榴" },
                { value: "persimmon", label: "柿子" },
            ]
        },
        rules: [{ required: true, type: "array" }],
    },
    {
        input_type: "input-select",
        field: "sex",
        default: "2",
        label: "性别",
        exts: {
            min: 2,
            max: 4,
            options: [
                { value: "1", label: "秘密" },
                { value: "2", label: "男生" },
                { value: "3", label: "女生" },
            ]
        },
        rules: [{ required: true, type: "enum" }],
    },
    {
        input_type: "input-select",
        field: "hobby",
        default: ["sing", "run"],
        label: "爱好",
        exts: {
            min: 2,
            max: 3,
            multiple: true,
            options: [
                { value: "dance", label: "跳舞" },
                { value: "sing", label: "唱歌" },
                { value: "run", label: "跑步" },
                { value: "listen", label: "听歌" },
            ]
        },
        rules: [{ required: true, type: "array" }],
    },
    {
        input_type: "md-editor",
        field: "md-editor",
        default: "# hello\n```php\n$a = 5;\n$b = 5;\n$c = $a + $b\n```\n",
        label: "Md编辑",
        exts: {
            conf: {
                mode: "mini"
            }
        },
    },
    {
        input_type: "json-editor",
        field: "json-editor",
        default: '{"a":10, "b":10}',
        label: "Json Editor",
        exts: {
            options: {
                mode: "text"
            },
            height: 200
        },
    },
    {
        input_type: "content-editor",
        field: "information",
        default: '<p>我的爱好黑多</p><blockquote>test</blockquote>',
        label: "个人简介",
        exts: {
            showHtml: true,
            height: "300px"
        },
    },
    {
        input_type: "cascader",
        field: "cascader",
        default: ["510000", "511600", "511623"],
        label: "Content Editor",
        exts: {
            options: [
                {
                    value: '110000',
                    label: '北京市',
                    children: [
                        {
                            value: '110101',
                            label: '东城区'
                        },
                        {
                            value: '110102',
                            label: '西城区'
                        }
                    ]
                },
                {
                    value: '510000',
                    label: '四川省',
                    children: [
                        {
                            value: '510100',
                            label: '成都市',
                            children: [
                                {
                                    value: '510104',
                                    label: '锦江区'
                                },
                                {
                                    value: '510105',
                                    label: '青羊区'
                                }
                            ]
                        },
                        {
                            value: '510300',
                            label: '自贡市',
                            children: [
                                {
                                    value: '510302',
                                    label: '自流井区'
                                },
                                {
                                    value: '510303',
                                    label: '贡井区'
                                }
                            ]
                        },
                        {
                            value: '511600',
                            label: '广安市',
                            children: [
                                {
                                    value: '511602',
                                    label: '广安区'
                                },
                                {
                                    value: '511623',
                                    label: '邻水县'
                                },
                                {
                                    value: '511681',
                                    label: '华蓥市'
                                }
                            ]
                        },
                        {
                            value: '511700',
                            label: '达州市',
                            children: [
                                {
                                    value: '511702',
                                    label: '通川区'
                                },
                                {
                                    value: '511703',
                                    label: '达川区'
                                }
                            ]
                        }
                    ]
                },
                {
                    value: '130000',
                    label: '河北省',
                    children: [
                        {
                            value: '130100',
                            label: '石家庄市',
                            children: [
                                {
                                    value: '130102',
                                    label: '长安区'
                                },
                                {
                                    value: '130104',
                                    label: '桥西区'
                                }
                            ]
                        },
                        {
                            value: '130300',
                            label: '秦皇岛市',
                            children: [
                                {
                                    value: '130302',
                                    label: '海港区'
                                }
                            ]
                        }
                    ]
                }
            ],
        },
    },
    {
        input_type: "uploader",
        field: "avatar",
        default: '',
        label: "头像",
        exts: {
            class: "avatar-upload",
            action: "/personal/upload-avatar",
            name: "file", // 上传的文件字段名
            autoUpload: true, // 是否在选取文件后立即进行上传
            withCredentials: true, // 支持发送 cookie 凭证信息
            headers: {}, // 文件头
            data: {}, // 上传时附带的参数
            accept: "image/png, image/jpeg", // 接受上传的文件类型
            // 上传前检查
            beforeUpload: (rawFile: UploadRawFile) => {
                if (rawFile.type !== 'image/png' && rawFile.type !== 'image/jpeg') {
                    alert('上传头像图片只能是 JPG 或 PNG 格式!')
                    return false
                } else if (rawFile.size / 1024 / 1024 > 2) {
                    alert('上传头像图片大小不能超过 2MB!')
                    return false
                }
                return true;
            },
            customUpload: customUpload,
        },
    },
    {
        input_type: "date-picker",
        field: "year",
        default: '',
        label: "年份",
        exts: {
            type: 'year',
        },
    },
    {
        input_type: "date-picker",
        field: "years",
        default: '',
        label: "年份(多)",
        exts: {
            type: 'years',
        },
    },
    {
        input_type: "date-picker",
        field: "month",
        default: '',
        label: "月份",
        exts: {
            type: 'month',
        },
    },
    {
        input_type: "date-picker",
        field: "monthrange",
        default: '',
        label: "月份范围",
        exts: {
            type: 'monthrange',
        },
    },
    {
        input_type: "date-picker",
        field: "daterange",
        default: '',
        label: "日期范围",
        exts: {
            type: 'daterange',
        },
    },
    {
        input_type: "date-picker",
        field: "datetime",
        default: '',
        label: "时间",
        exts: {
            type: 'datetime',
        },
    },
    {
        input_type: "date-picker",
        field: "datetimerange",
        default: '',
        label: "时间范围",
        exts: {
            type: 'datetimerange',
        },
    },
    {
        input_type: "date-picker",
        field: "week",
        default: '',
        label: "周",
        exts: {
            type: 'week',
        },
    },
    {
        input_type: "date-picker",
        field: "dates",
        default: '',
        label: "日期(多)",
        exts: {
            type: 'dates',
        },
    },
    {
        input_type: "date-picker",
        field: "date",
        default: '',
        label: "日期",
        exts: {
            type: 'date',
        },
    },
    {
        input_type: "date-picker",
        field: "past_date",
        default: '',
        label: "以往日期",
        exts: {
            type: 'date',
            'disabledDate': 'future',
        },
    },
    {
        input_type: "date-picker",
        field: "future_date",
        default: '',
        label: "往后日期",
        exts: {
            type: 'date',
            'disabledDate': 'past',
        },
    },
    {
        input_type: "time-picker",
        field: "time",
        default: '',
        label: "选择时间1",
        exts: {},
    },
    {
        input_type: "time-picker",
        field: "timerange",
        default: '',
        label: "时间范围2",
        exts: {
            'is-range': true, // 是否时间范围
        },
    },
    {
        input_type: "time-select",
        field: "time_select1",
        default: '',
        label: "时间选择3",
        exts: {
        },
    },
    {
        input_type: "input-password",
        field: "new_password",
        default: "",
        label: "新密码",
        rules: [{ required: true, type: "password" }],
    },
    {
        input_type: "input-password",
        field: "confirm_password",
        default: "",
        label: "确认密码",
        rules: [
            // { required: true, type: "password" },
            { required: true, type: "confirm", message: "确认密码和上次密码不同" }
        ],
        exts: {
            field: 'new_password',
            value: 'admin' // field 存在时, field 优先
        }
    },
    {
        input_type: "input-text",
        field: "callback",
        default: "",
        label: "同步回调",
        exts: {
            params: {
                name: "qingbing"
            }
        },
        rules: [
            {
                required: true, type: "callback", trigger: 'blur', callback: <TXzFormCallback>(
                    callback: (error?: string | Error) => void,
                    value: unknown,
                    formData: TRecord,
                    params: TRecord
                ) => {
                    console.log(value);
                    console.log(formData);
                    console.log(params);
                    /**
                     * validator 为同步验证,验证失败方式
                     *  1. return false
                     *  2. 调用 callback(), 除了不给参数,其它都是失败
                     *      1. 如果设置了 message, 提示为 message
                     *      2. 没有message时, callback 参数不为空就以参数为提示,否则为 "{FullField} fails"
                     */
                    // 成功
                    // return true
                    // callback()
                    // 失败
                    callback("错误提示1")
                    // callback(new Error("错误提示2"))
                    // return false
                },
            }
        ],
    },
    {
        input_type: "input-text",
        field: "async_callback",
        default: "",
        label: "异步回调",
        rules: [
            {
                required: true, type: "callback", trigger: 'blur', asyncCallback: <TXzFormCallback>(
                    callback: (error?: string | Error) => void,
                    value: unknown,
                    formData: TRecord,
                    params: TRecord
                ) => {
                    console.log(value);
                    console.log(formData);
                    console.log(params);
                    /**
                     * 异步验证,返回方式只能使用 callback 调用方式
                     * 成功: callback()
                     * 失败: callback('error message'); callback(new Error('error message'))
                     */
                    // 成功
                    // callback() 
                    // 失败
                    // callback('error message')
                    callback(new Error('error - message'))
                },
            }
        ],
    },
    {
        input_type: "input-text",
        field: "custom_async",
        default: "",
        label: "自定义异步",
        rules: [
            {
                required: true, trigger: 'blur', asyncValidator(rule, value, callback, source, options) {
                    return new Promise((resolve, reject) => {
                        // resolve() // "哦业,验证成功了"
                        reject("哎呀,验证有误呢")
                    })
                },
            }
        ],
    },
    {
        input_type: "input-text",
        field: "async_remote",
        default: "",
        label: "Ajax 远端回调",
        rules: [
            {
                required: true, type: "callback", trigger: 'blur', asyncCallback: <TXzFormCallback>(
                    callback: (error?: string | Error) => void,
                    value: unknown,
                    formData: TRecord,
                    params: TRecord
                ) => {
                    fetchRemote(params)
                        .then((res) => {
                            if (res.data.code == 0) {
                                callback() // 成功
                            } else {
                                callback(res.data.msg) // 失败
                            }
                        })
                        .catch(err => callback(err));
                },
            }
        ],
    },
])
    .setViewFields(['username', 'nickname'])
    // .setShowFields(['async_remote', 'custom_async', 'time_select1'])
    .done()

const resetPasswordItems: Record<string, TXzFormItem> = {
    oldPassword: mixins(XzFormItemMachine('password', 'oldPassword', '原始密码'), {
        rules: [{ required: true }]
    }),
    newPassword: mixins(XzFormItemMachine('password', 'newPassword', '新 密 码'), {
        rules: [{ required: true }]
    }),
    confirmPassword: mixins(XzFormItemMachine('password', 'confirmPassword', '确认密码'), {
        rules: [
            { required: true },
            { type: "confirm", message: "两次秘密输入不一致" }
        ],
        exts: {
            field: 'newPassword'
        }
    }),
}

// const { items, viewFields, showFields, formData, rules } = XzFormItemParse.instance(resetPasswordItems)
//     .done()
</script>
2.0.32

1 month ago

2.0.31

1 month ago

2.0.29

1 month ago

2.0.30

1 month ago

2.0.28

1 month ago

2.0.26

1 month ago

2.0.27

1 month ago

2.0.24

1 month ago

2.0.25

1 month ago

2.0.22

1 month ago

2.0.23

1 month ago

2.0.19

1 month ago

2.0.18

1 month ago

2.0.20

1 month ago

2.0.21

1 month ago

2.0.17

1 month ago

2.0.15

1 month ago

2.0.16

1 month ago

2.0.13

1 month ago

2.0.14

1 month ago

2.0.11

1 month ago

2.0.12

1 month ago

2.0.9

1 month ago

2.0.10

1 month ago

2.0.7

2 months ago

2.0.6

2 months ago

2.0.8

2 months ago

2.0.5

2 months ago

2.0.4

2 months ago

2.0.3

2 months ago

2.0.2

2 months ago

2.0.1

2 months ago