Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev
This commit is contained in:
commit
d2a82edbe4
|
@ -13,25 +13,28 @@ declare module '@vue/runtime-core' {
|
|||
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
|
||||
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
|
||||
ACol: typeof import('ant-design-vue/es')['Col']
|
||||
ACollapse: typeof import('ant-design-vue/es')['Collapse']
|
||||
ACollapsePanel: typeof import('ant-design-vue/es')['CollapsePanel']
|
||||
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
|
||||
ADivider: typeof import('ant-design-vue/es')['Divider']
|
||||
AEmpty: typeof import('ant-design-vue/es')['Empty']
|
||||
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
|
||||
ADivider: typeof import('ant-design-vue/es')['Divider']
|
||||
AEmpty: typeof import('ant-design-vue/es')['Empty']
|
||||
AForm: typeof import('ant-design-vue/es')['Form']
|
||||
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||
AInput: typeof import('ant-design-vue/es')['Input']
|
||||
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
|
||||
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
||||
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||
APagination: typeof import('ant-design-vue/es')['Pagination']
|
||||
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
||||
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
||||
ARow: typeof import('ant-design-vue/es')['Row']
|
||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||
ASpace: typeof import('ant-design-vue/es')['Space']
|
||||
ASpin: typeof import('ant-design-vue/es')['Spin']
|
||||
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
||||
ATable: typeof import('ant-design-vue/es')['Table']
|
||||
ATimePicker: typeof import('ant-design-vue/es')['TimePicker']
|
||||
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
||||
ATreeSelect: typeof import('ant-design-vue/es')['TreeSelect']
|
||||
AUpload: typeof import('ant-design-vue/es')['Upload']
|
||||
BadgeStatus: typeof import('./src/components/BadgeStatus/index.vue')['default']
|
||||
CardBox: typeof import('./src/components/CardBox/index.vue')['default']
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
</div>
|
||||
|
||||
<!-- 按钮 -->
|
||||
<slot name="botton-tool">
|
||||
<slot name="bottom-tool">
|
||||
<div v-if="showTool" class="card-tools">
|
||||
<div
|
||||
v-for="item in actions"
|
||||
|
|
|
@ -1,11 +1,252 @@
|
|||
<template>
|
||||
<div class=''>
|
||||
|
||||
<div class='JForm-content'>
|
||||
<a-form
|
||||
ref='form'
|
||||
v-bind='props'
|
||||
:model='formData.data'
|
||||
layout='vertical'
|
||||
>
|
||||
<a-row :type='rowType'>
|
||||
<a-col v-for='item in formOptions.data' :key='item.key' :span='item.span'>
|
||||
<a-form-item
|
||||
:name='item.name'
|
||||
:required='item.required'
|
||||
:rules='item.rules'
|
||||
:noStyle='item.noStyle'
|
||||
>
|
||||
<template #label>
|
||||
<span>{{ item.title }}</span>
|
||||
<a-tooltip :title='item.tooltip'>
|
||||
<QuestionCircleOutlined v-if='!!item.tooltip' style='margin-left: 4px; color: rgba(0,0,0,.45) ' />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-input
|
||||
v-if='item.component === componentType.input'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
/>
|
||||
<a-select
|
||||
v-else-if='item.component === componentType.select'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
:options='item.options'
|
||||
/>
|
||||
<a-inputnumber
|
||||
v-else-if='item.component === componentType.inputNumber'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
/>
|
||||
<a-input-password
|
||||
v-else-if='item.component === componentType.password'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
/>
|
||||
<a-switch
|
||||
v-else-if='item.component === componentType.switch'
|
||||
v-bind='item.componentProps'
|
||||
v-model:checked='formData.data[item.name]'
|
||||
/>
|
||||
<a-radio-group
|
||||
v-else-if='item.component === componentType.radio'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
/>
|
||||
<a-checkbox-group
|
||||
v-else-if='item.component === componentType.checkbox'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
:options='item.options'
|
||||
/>
|
||||
<a-time-picker
|
||||
v-else-if='item.component === componentType.time'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
/>
|
||||
<a-date-picker
|
||||
v-else-if='item.component === componentType.date'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
/>
|
||||
<a-tree-select
|
||||
v-else-if='item.component === componentType.tree'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
:tree-data='item.options'
|
||||
/>
|
||||
<a-upload
|
||||
v-else-if='item.component === componentType.upload'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
/>
|
||||
<component
|
||||
v-else
|
||||
:is='item.component'
|
||||
v-bind='item.componentProps'
|
||||
v-model:value='formData.data[item.name]'
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup type='ts' name='FormBuilder'>
|
||||
const data = reactive({})
|
||||
<script setup lang='ts' name='FormBuilder'>
|
||||
import type { Options, OptionsItem, OptionsComponent } from './index.modules'
|
||||
import { PropType } from 'vue'
|
||||
import { get, isArray, isString, pick, set } from 'lodash-es'
|
||||
import { formProps } from 'ant-design-vue/es/form'
|
||||
import componentType from './util'
|
||||
import {
|
||||
QuestionCircleOutlined
|
||||
} from '@ant-design/icons-vue';
|
||||
|
||||
const form = ref()
|
||||
|
||||
const props = defineProps({
|
||||
...formProps,
|
||||
options: {
|
||||
type: Object as PropType<Options>,
|
||||
default: () => []
|
||||
},
|
||||
initValue: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
column: {
|
||||
type: Number,
|
||||
default: 1
|
||||
}
|
||||
})
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
data: {}
|
||||
})
|
||||
|
||||
const formOptions = reactive<{ data: OptionsComponent[]}>({
|
||||
data: []
|
||||
}) // 表单Item
|
||||
|
||||
const rowType = ref<string | undefined>(undefined)
|
||||
|
||||
const calculateItemSpan = (span?: number | string) => {
|
||||
const itemSpan = 24 / props.column
|
||||
if (!span) return itemSpan
|
||||
|
||||
if (isString(span) && span.includes('px')) {
|
||||
rowType.value = 'flex'
|
||||
} else {
|
||||
return span
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入的表单options生成表单
|
||||
* @param data {Options}
|
||||
* @param parentKey
|
||||
*/
|
||||
const handleFormData = (data: Options, parentKey: Array<string> = []): any => {
|
||||
const cacheModel: any = {}
|
||||
|
||||
Object.keys(data).forEach(async (key) => {
|
||||
const optionItem = data[key]
|
||||
const _key = [...parentKey, key]
|
||||
if ('type' in optionItem && optionItem.type === 'Object') {
|
||||
const dataModel = handleFormData(optionItem.properties, _key)
|
||||
cacheModel[key] = dataModel
|
||||
} else if (!('visible' in optionItem) || ('visible' in optionItem && optionItem.visible !== true)){
|
||||
// 处理默认值以及原始值
|
||||
const keyValue = get(formData.data, _key)
|
||||
let _options: any[] = []
|
||||
|
||||
if (keyValue) { // 当前值在formModel中
|
||||
cacheModel[key] = keyValue
|
||||
} else {
|
||||
cacheModel[key] = (optionItem as OptionsItem).default
|
||||
}
|
||||
// 处理options
|
||||
if ('options' in optionItem) {
|
||||
_options = optionItem.options!
|
||||
}
|
||||
// 处理 onSearch 请求
|
||||
if ('onSearch' in optionItem) {
|
||||
const data = await optionItem.onSearch!()
|
||||
if (data) {
|
||||
_options = data
|
||||
}
|
||||
}
|
||||
const optionsItemProps = pick(optionItem, ['componentProps', 'title', 'component', 'rules', 'required', 'hidden', 'tooltip', 'noStyle'])
|
||||
//
|
||||
formOptions.data.push({
|
||||
...optionsItemProps,
|
||||
name: _key,
|
||||
options: _options,
|
||||
key: isArray(_key) ? _key.toString() : _key,
|
||||
span: calculateItemSpan((optionItem as OptionsItem).span)
|
||||
})
|
||||
}
|
||||
})
|
||||
return cacheModel
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const resetModel = () => {
|
||||
form.value.resetFields()
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证并提交表单
|
||||
*/
|
||||
const formValidate = () => {
|
||||
return new Promise((res, rej) => {
|
||||
form.value.validate().then(() => {
|
||||
res(formData.data)
|
||||
}).catch((err: any) => {
|
||||
rej(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 改变单个值
|
||||
*/
|
||||
const setItemValue = (key: string | (string | number)[], value: any) => {
|
||||
set(formData.data, key, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改整个表单值
|
||||
* @param data
|
||||
*/
|
||||
const setData = (data: any) => {
|
||||
formData.data = data
|
||||
}
|
||||
|
||||
|
||||
if (props.initValue) {
|
||||
formData.data = props.initValue
|
||||
}
|
||||
|
||||
formData.data = handleFormData(props.options)
|
||||
|
||||
watch(props.options, (newValue: any) => {
|
||||
formOptions.data = []
|
||||
formData.data = handleFormData(newValue)
|
||||
})
|
||||
|
||||
watch(props.initValue, (newValue: any) => {
|
||||
formData.data = newValue
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
resetModel,
|
||||
formValidate,
|
||||
setItemValue,
|
||||
setData
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import type { FormProps } from 'ant-design-vue/es/form'
|
||||
|
||||
export interface OptionsComponent {
|
||||
/** FormItem title **/
|
||||
title?: string
|
||||
/** 组件名称 **/
|
||||
component?: string
|
||||
/** 组件Props **/
|
||||
componentProps?: any
|
||||
/** 组件Options **/
|
||||
options?: any[]
|
||||
name?: any
|
||||
[name: string]: any
|
||||
}
|
||||
|
||||
export interface OptionsItem extends OptionsComponent{
|
||||
/** 内置查询,会覆盖options **/
|
||||
onSearch?: () => Promise<any>
|
||||
default?: any
|
||||
/** 隐藏Item,值不会进入到FormModel中 **/
|
||||
visible?: boolean
|
||||
/** 表单隐藏域 **/
|
||||
hidden?: boolean,
|
||||
span?: number | string
|
||||
rules?: FormProps.rules
|
||||
required?: boolean
|
||||
tooltip?: string
|
||||
noStyle?: boolean
|
||||
}
|
||||
|
||||
interface ObjectTypes {
|
||||
type: 'Object'
|
||||
properties: {
|
||||
[name: string]: OptionsItem
|
||||
}
|
||||
}
|
||||
|
||||
export interface Options extends FormProps {
|
||||
[name: string]: ObjectTypes | OptionsItem
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import FormBuilder from './FormBuilder.vue'
|
||||
export { default as componentType } from './util'
|
||||
|
||||
export default FormBuilder
|
|
@ -0,0 +1,15 @@
|
|||
const optionComponentType = {
|
||||
input: 'input',
|
||||
inputNumber: 'inputNumber',
|
||||
password: 'password',
|
||||
switch: 'switch',
|
||||
radio: 'radio',
|
||||
checkbox: 'checkbox',
|
||||
time: 'time',
|
||||
date: 'date',
|
||||
treeSelect: 'treeSelect',
|
||||
upload: 'upload',
|
||||
tree: 'tree',
|
||||
select: 'select'
|
||||
}
|
||||
export default optionComponentType
|
|
@ -1,62 +1,106 @@
|
|||
<template>
|
||||
<div class="jtable-body">
|
||||
<div class="jtable-body-header">
|
||||
<div class="jtable-body-header-left">
|
||||
<slot name="headerTitle"></slot>
|
||||
</div>
|
||||
<div class="jtable-body-header-right">
|
||||
<div class="jtable-setting-item" :class="[ModelEnum.CARD === model ? 'active' : '']" @click="modelChange(ModelEnum.CARD)">
|
||||
<AppstoreOutlined />
|
||||
<a-spin :spinning="loading">
|
||||
<div class="jtable-body">
|
||||
<div class="jtable-body-header">
|
||||
<div class="jtable-body-header-left">
|
||||
<slot name="headerTitle"></slot>
|
||||
</div>
|
||||
<div class="jtable-setting-item" :class="[ModelEnum.TABLE === model ? 'active' : '']" @click="modelChange(ModelEnum.TABLE)">
|
||||
<UnorderedListOutlined />
|
||||
<div class="jtable-body-header-right" v-if="!model">
|
||||
<div class="jtable-setting-item" :class="[ModelEnum.CARD === _model ? 'active' : '']" @click="modelChange(ModelEnum.CARD)">
|
||||
<AppstoreOutlined />
|
||||
</div>
|
||||
<div class="jtable-setting-item" :class="[ModelEnum.TABLE === _model ? 'active' : '']" @click="modelChange(ModelEnum.TABLE)">
|
||||
<UnorderedListOutlined />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="jtable-content">
|
||||
<div v-if="model === ModelEnum.CARD" class="jtable-card">
|
||||
<div
|
||||
v-if="dataSource.length"
|
||||
class="jtable-card-items"
|
||||
:style="{gridTemplateColumns: `repeat(${column}, 1fr)`}"
|
||||
>
|
||||
<div class="jtable-content">
|
||||
<!-- <div class="jtable-alert">
|
||||
<a-alert message="Info Text" type="info" />
|
||||
</div> -->
|
||||
<div v-if="_model === ModelEnum.CARD" class="jtable-card">
|
||||
<div
|
||||
class="jtable-card-item"
|
||||
v-for="(item, index) in dataSource"
|
||||
:key="index"
|
||||
v-if="_dataSource.length"
|
||||
class="jtable-card-items"
|
||||
:style="{gridTemplateColumns: `repeat(${column}, 1fr)`}"
|
||||
>
|
||||
<slot name="cardRender" :item="item" :index="index"></slot>
|
||||
<div
|
||||
class="jtable-card-item"
|
||||
v-for="(item, index) in _dataSource"
|
||||
:key="index"
|
||||
>
|
||||
<CardBox :actions="actions" v-bind="cardProps">
|
||||
<template #img>
|
||||
<slot name="img">
|
||||
<img :src="getImage('/device-product.png')" />
|
||||
</slot>
|
||||
</template>
|
||||
<template #content>
|
||||
<slot name="cardContent" :item="item" :index="index"></slot>
|
||||
</template>
|
||||
</CardBox>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" />
|
||||
<a-table :rowSelection="rowSelection" :columns="[..._columns]" :dataSource="_dataSource" :pagination="false" :scroll="{ x: 1366 }">
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'action'">
|
||||
<a-space>
|
||||
<a-tooltip v-for="i in actions" :key="i.key" v-bind="i.tooltip">
|
||||
<a-popconfirm v-if="i.popConfirm" v-bind="i.popConfirm">
|
||||
<a>
|
||||
{{i.text}}
|
||||
</a>
|
||||
</a-popconfirm>
|
||||
<a v-else @click="i.onClick && i.onClick(record)">
|
||||
{{i.text}}
|
||||
</a>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
<template v-else-if="column.scopedSlots">
|
||||
<slot :name="column.key" :row="record"></slot>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<a-table :columns="columns" :dataSource="dataSource" :pagination="false" />
|
||||
<div class="jtable-pagination" v-if="_dataSource.length && !noPagination">
|
||||
<a-pagination
|
||||
size="small"
|
||||
:total="total"
|
||||
:showQuickJumper="false"
|
||||
:showSizeChanger="true"
|
||||
v-model:current="pageIndex"
|
||||
v-model:page-size="pageSize"
|
||||
:show-total="(total, range) => `第 ${range[0]} - ${range[1]} 条/总共 ${total} 条`"
|
||||
@change="pageChange"
|
||||
:page-size-options="[12, 24, 48, 60, 100]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="jtable-pagination" v-if="dataSource.length">
|
||||
<a-pagination
|
||||
size="small"
|
||||
:total="50"
|
||||
:show-total="total => `第 ${1} - ${1} 条/总共 ${total} 条`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { UnorderedListOutlined, AppstoreOutlined } from '@ant-design/icons-vue'
|
||||
import type { TableProps } from 'ant-design-vue/es/table'
|
||||
import type { TooltipProps } from 'ant-design-vue/es/tooltip'
|
||||
import type { PopconfirmProps } from 'ant-design-vue/es/popconfirm'
|
||||
import { Empty } from 'ant-design-vue'
|
||||
import { CSSProperties } from 'vue';
|
||||
import { getImage } from '@/utils/comm';
|
||||
|
||||
enum ModelEnum {
|
||||
TABLE = 'TABLE',
|
||||
CARD = 'CARD',
|
||||
}
|
||||
|
||||
export declare type RequestData = {
|
||||
type RequestData = {
|
||||
code: string;
|
||||
result: {
|
||||
data: Record<string, any>[] | undefined;
|
||||
|
@ -67,50 +111,111 @@ export declare type RequestData = {
|
|||
status: number;
|
||||
} & Record<string, any>;
|
||||
|
||||
export interface ActionsType {
|
||||
key: string;
|
||||
text?: string;
|
||||
disabled?: boolean;
|
||||
permission?: boolean;
|
||||
onClick?: (data: any) => void;
|
||||
style?: CSSProperties;
|
||||
tooltip?: TooltipProps;
|
||||
popConfirm?: PopconfirmProps;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
interface JTableProps extends TableProps{
|
||||
request: (params: Record<string, any> & {
|
||||
request?: (params: Record<string, any> & {
|
||||
pageSize: number;
|
||||
pageIndex: number;
|
||||
}) => Promise<Partial<RequestData>>;
|
||||
cardBodyClass?: string;
|
||||
columns: Record<string, any>[];
|
||||
params: Record<string, any> & {
|
||||
params?: Record<string, any> & {
|
||||
pageSize: number;
|
||||
pageIndex: number;
|
||||
}
|
||||
};
|
||||
model?: keyof typeof ModelEnum | undefined; // 显示table还是card
|
||||
actions?: ActionsType[];
|
||||
noPagination?: boolean;
|
||||
rowSelection?: TableProps['rowSelection'];
|
||||
cardProps?: Record<string, any>;
|
||||
dataSource?: Record<string, any>[];
|
||||
}
|
||||
// props和emit
|
||||
const emit = defineEmits(["modelChange"]);
|
||||
// props
|
||||
const props = withDefaults(defineProps<JTableProps>(), {
|
||||
cardBodyClass: '',
|
||||
request: undefined
|
||||
request: undefined,
|
||||
})
|
||||
|
||||
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE
|
||||
const model = ref<keyof typeof ModelEnum>(ModelEnum.CARD); // 模式切换
|
||||
const column = ref<number>(4);
|
||||
const dataSource = ref<Record<string, any>[]>([])
|
||||
console.log(props)
|
||||
// 方法
|
||||
|
||||
const _model = ref<keyof typeof ModelEnum>(props.model ? props.model : ModelEnum.CARD); // 模式切换
|
||||
const column = ref<number>(4);
|
||||
const _dataSource = ref<Record<string, any>[]>([])
|
||||
const pageIndex = ref<number>(0)
|
||||
const pageSize = ref<number>(6)
|
||||
const total = ref<number>(0)
|
||||
const _columns = ref<Record<string, any>[]>([])
|
||||
const loading = ref<boolean>(true)
|
||||
//
|
||||
// const slotColumns = computed(() => props.columns.filter((item) => item.scopedSlots))
|
||||
// 方法
|
||||
// 切换卡片和表格
|
||||
const modelChange = (type: keyof typeof ModelEnum) => {
|
||||
model.value = type
|
||||
_model.value = type
|
||||
}
|
||||
// 请求数据
|
||||
const handleSearch = async (_params?: Record<string, any>) => {
|
||||
loading.value = true
|
||||
if(props.request) {
|
||||
const resp = await props.request({
|
||||
pageSize: 12,
|
||||
pageIndex: 1,
|
||||
..._params
|
||||
})
|
||||
if(resp.status === 200){
|
||||
// 判断如果是最后一页且最后一页为空,就跳转到前一页
|
||||
if(resp.result?.data?.length === 0 && resp.result.total && resp.result.pageSize && resp.result.pageIndex) {
|
||||
handleSearch({
|
||||
..._params,
|
||||
pageSize: pageSize.value,
|
||||
pageIndex: pageIndex.value - 1,
|
||||
})
|
||||
} else {
|
||||
_dataSource.value = resp.result?.data || []
|
||||
pageIndex.value = resp.result?.pageIndex || 0
|
||||
pageSize.value = resp.result?.pageSize || 6
|
||||
total.value = resp.result?.total || 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_dataSource.value = props?.dataSource || []
|
||||
}
|
||||
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
// 请求数据
|
||||
const handleSearch = async (params1?: Record<string, any>) => {
|
||||
const resp = await props.request({
|
||||
pageSize: 10,
|
||||
pageIndex: 1,
|
||||
...params1
|
||||
const pageChange = (page: number, size: number) => {
|
||||
handleSearch({
|
||||
...props.params,
|
||||
pageSize: size,
|
||||
pageIndex: pageSize.value === size ? page : 1,
|
||||
})
|
||||
if(resp.status === 200){
|
||||
dataSource.value = resp.result?.data || []
|
||||
}
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if(Array.isArray(props.actions) && props.actions.length) {
|
||||
_columns.value = [...props.columns,
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
width: 250
|
||||
}
|
||||
]
|
||||
} else {
|
||||
_columns.value = [...props.columns]
|
||||
}
|
||||
handleSearch(props.params)
|
||||
})
|
||||
|
||||
|
@ -160,9 +265,9 @@ watchEffect(() => {
|
|||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
// position: absolute;
|
||||
// right: 24px;
|
||||
// bottom: 24px;
|
||||
/deep/ .ant-pagination-item {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -3,7 +3,8 @@ import AIcon from './AIcon'
|
|||
import PermissionButton from './PermissionButton/index.vue'
|
||||
import JTable from './Table/index.vue'
|
||||
import TitleComponent from "./TitleComponent/index.vue";
|
||||
import Form from './Form'
|
||||
import Form from './Form';
|
||||
import CardBox from './CardBox/index.vue';
|
||||
|
||||
export default {
|
||||
install(app: App) {
|
||||
|
@ -12,5 +13,6 @@ export default {
|
|||
.component('JTable', JTable)
|
||||
.component('TitleComponent', TitleComponent)
|
||||
.component('Form', Form)
|
||||
.component('CardBox', CardBox)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
.ant-form-item-required:before {
|
||||
position: absolute;
|
||||
right: -12px;
|
||||
}
|
|
@ -1,9 +1,59 @@
|
|||
<template>
|
||||
<Form />
|
||||
<Form
|
||||
ref='form'
|
||||
:options='options'
|
||||
:initValue='initValue'
|
||||
/>
|
||||
<a-button @click='submit'>提交</a-button>
|
||||
<a-button @click='reset'>重置</a-button>
|
||||
<a-button @click='setValue'>修改name</a-button>
|
||||
</template>
|
||||
|
||||
<script setup name='FormDemo'>
|
||||
const data = reactive({})
|
||||
import { componentType } from 'components/Form'
|
||||
const form = ref()
|
||||
const initValue = reactive({})
|
||||
|
||||
const submit = () => {
|
||||
form.value.formValidate().then(res => {
|
||||
console.log(res)
|
||||
})
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
|
||||
}
|
||||
|
||||
const setValue =() => {
|
||||
initValue.name = '111111'
|
||||
}
|
||||
|
||||
const options = reactive({
|
||||
name: {
|
||||
component: componentType.input,
|
||||
componentProps: {
|
||||
style: {
|
||||
width: '200px'
|
||||
}
|
||||
},
|
||||
title: '测试',
|
||||
required: true
|
||||
},
|
||||
sex: {
|
||||
component: componentType.select,
|
||||
title: '性别',
|
||||
options: [
|
||||
{ label: '111', value: 1 },
|
||||
{ label: '222', value: 2 },
|
||||
],
|
||||
required: true,
|
||||
rules: [
|
||||
{ required: true, message: '请选择性别'}
|
||||
],
|
||||
tooltip: '性别',
|
||||
default: 1
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -3,32 +3,48 @@
|
|||
<JTable
|
||||
:columns="[
|
||||
{
|
||||
title: '姓名',
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
},
|
||||
{
|
||||
title: '年龄',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
title: 'ID',
|
||||
dataIndex: 'id',
|
||||
key: 'id',
|
||||
scopedSlots: true
|
||||
},
|
||||
{
|
||||
title: '住址',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
}
|
||||
title: '分类',
|
||||
dataIndex: 'classifiedName',
|
||||
key: 'classifiedName',
|
||||
},
|
||||
]"
|
||||
:actions="actions"
|
||||
:request="request"
|
||||
:rowSelection="rowSelection"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<a-button type="primary">新增</a-button>
|
||||
</template>
|
||||
<template #cardRender="slotProps">
|
||||
<CardBox>
|
||||
<template #content>
|
||||
{{slotProps.item.name}}
|
||||
</template>
|
||||
</CardBox>
|
||||
<template #cardContent="slotProps">
|
||||
<h3>{{slotProps.item.name}}</h3>
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
设备类型
|
||||
</div>
|
||||
<div>直连设备</div>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<div class="card-item-content-text">
|
||||
产品名称
|
||||
</div>
|
||||
<div>测试固定地址</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
<template #id="slotProps">
|
||||
<a>{{slotProps.row.id}}</a>
|
||||
</template>
|
||||
</JTable>
|
||||
</div>
|
||||
|
@ -36,8 +52,43 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import server from "@/utils/request";
|
||||
import CardBox from '@/components/CardBox/index.vue';
|
||||
import type { ActionsType } from '@/components/Table/index.vue'
|
||||
import { getImage } from '@/utils/comm';
|
||||
import type { TableProps, TableColumnType } from 'ant-design-vue';
|
||||
|
||||
const request = (data: any) => server.post(`/device-product/_query`, data)
|
||||
const actions: ActionsType[] = [
|
||||
{
|
||||
key: 'edit',
|
||||
// disabled: true,
|
||||
text: "编辑",
|
||||
tooltip: {
|
||||
title: '编辑'
|
||||
},
|
||||
// component: <UnorderedListOutlined />
|
||||
},
|
||||
{
|
||||
key: 'delete',
|
||||
disabled: true,
|
||||
text: "删除",
|
||||
tooltip: {
|
||||
title: '删除'
|
||||
},
|
||||
popConfirm: {
|
||||
title: '确认删除?'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const rowSelection: TableProps['rowSelection'] = {
|
||||
onChange: (selectedRowKeys: string[], selectedRows: any[]) => {
|
||||
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
|
||||
},
|
||||
getCheckboxProps: (record: any) => ({
|
||||
disabled: record.name === 'Disabled User',
|
||||
name: record.name,
|
||||
}),
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
|
Loading…
Reference in New Issue