93 changed files with 4515 additions and 267 deletions
@ -0,0 +1,7 @@ |
|||
dependencies { |
|||
api( |
|||
project(":io.sc.platform.mvc"), |
|||
|
|||
"org.springframework.boot:spring-boot-starter-mail", |
|||
) |
|||
} |
@ -0,0 +1,45 @@ |
|||
package io.sc.platform.communication.service; |
|||
|
|||
import javax.mail.MessagingException; |
|||
import javax.mail.internet.MimeMessage; |
|||
|
|||
import org.springframework.mail.SimpleMailMessage; |
|||
|
|||
/** |
|||
* 邮件发送器服务 |
|||
*/ |
|||
public interface MailSenderService { |
|||
/** |
|||
* 发送简单邮件 |
|||
* @param from 发件人 |
|||
* @param to 收件人 |
|||
* @param cc 抄送人 |
|||
* @param subject 标题 |
|||
* @param text 文本 |
|||
*/ |
|||
public void sendSimpleMessage(String from,String[] to,String[] cc,String subject,String text); |
|||
|
|||
/** |
|||
* 发送简单邮件 |
|||
* @param messages 邮件消息 |
|||
*/ |
|||
public void sendSimpleMessage(SimpleMailMessage... messages); |
|||
|
|||
|
|||
/** |
|||
* 发送富文本邮件 |
|||
* @param from 发件人 |
|||
* @param to 收件人 |
|||
* @param cc 抄送人 |
|||
* @param subject 标题 |
|||
* @param text 文本 |
|||
* @throws MessagingException 违例 |
|||
*/ |
|||
public void sendMimeMessage(String from,String[] to,String[] cc,String subject,String text) throws MessagingException; |
|||
|
|||
/** |
|||
* 发送富文本邮件 |
|||
* @param mimeMessages 邮件消息 |
|||
*/ |
|||
public void sendMimeMessage(MimeMessage... mimeMessages); |
|||
} |
@ -0,0 +1,66 @@ |
|||
package io.sc.platform.communication.service.impl; |
|||
|
|||
import javax.annotation.PostConstruct; |
|||
import javax.mail.MessagingException; |
|||
import javax.mail.internet.MimeMessage; |
|||
|
|||
import io.sc.platform.communication.service.MailSenderService; |
|||
import io.sc.platform.core.util.BeanUtil; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.context.ApplicationContext; |
|||
import org.springframework.mail.SimpleMailMessage; |
|||
import org.springframework.mail.javamail.JavaMailSender; |
|||
import org.springframework.mail.javamail.MimeMessageHelper; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
@Service |
|||
public class MailSenderServiceImpl implements MailSenderService { |
|||
@Autowired private ApplicationContext applicationContext; |
|||
private JavaMailSender mailSender; |
|||
|
|||
@PostConstruct |
|||
public void initMailSenderService(){ |
|||
this.mailSender = BeanUtil.getBean(applicationContext,JavaMailSender.class); |
|||
} |
|||
|
|||
@Override |
|||
public void sendSimpleMessage(String from, String[] to, String[] cc, String subject, String text) { |
|||
if(mailSender!=null){ |
|||
SimpleMailMessage message = new SimpleMailMessage(); |
|||
message.setFrom(from); |
|||
message.setTo(to); |
|||
message.setCc(cc); |
|||
message.setSubject(subject); |
|||
message.setText(text); |
|||
sendSimpleMessage(message); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void sendSimpleMessage(SimpleMailMessage... messages) { |
|||
if(mailSender!=null){ |
|||
mailSender.send(messages); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void sendMimeMessage(String from, String[] to, String[] cc, String subject, String html) throws MessagingException { |
|||
if(mailSender!=null) { |
|||
MimeMessage message = mailSender.createMimeMessage(); |
|||
MimeMessageHelper helper = new MimeMessageHelper(message, true); |
|||
helper.setFrom(from); |
|||
helper.setTo(to); |
|||
helper.setCc(cc); |
|||
helper.setSubject(subject); |
|||
helper.setText(html, true); |
|||
sendMimeMessage(message); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void sendMimeMessage(MimeMessage... mimeMessages) { |
|||
if(mailSender!=null) { |
|||
mailSender.send(mimeMessages); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,17 @@ |
|||
[ |
|||
{ |
|||
"module" : "io.sc.platform.communication", |
|||
"order" : 4000, |
|||
"description": "email configuration", |
|||
"properties": [ |
|||
"spring.mail.host=zzz.xxx.yyy", |
|||
"spring.mail.port=25", |
|||
"spring.mail.protocol=smtp", |
|||
"spring.mail.test-connection=false", |
|||
"spring.mail.default-encoding=UTF-8", |
|||
"spring.mail.properties.mail.smtp.auth=true", |
|||
"spring.mail.username=xxx", |
|||
"spring.mail.password=yyy" |
|||
] |
|||
} |
|||
] |
@ -0,0 +1,5 @@ |
|||
{ |
|||
"includes":[ |
|||
"io.sc.platform.communication.service.impl" |
|||
] |
|||
} |
@ -0,0 +1,22 @@ |
|||
{ |
|||
"container":[ |
|||
"spring.mail.host", |
|||
"spring.mail.port", |
|||
"spring.mail.protocol", |
|||
"spring.mail.test-connection", |
|||
"spring.mail.default-encoding", |
|||
"spring.mail.properties.mail.smtp.auth", |
|||
"spring.mail.username", |
|||
"spring.mail.password" |
|||
], |
|||
"jar": [ |
|||
"spring.mail.host", |
|||
"spring.mail.port", |
|||
"spring.mail.protocol", |
|||
"spring.mail.test-connection", |
|||
"spring.mail.default-encoding", |
|||
"spring.mail.properties.mail.smtp.auth", |
|||
"spring.mail.username", |
|||
"spring.mail.password" |
|||
] |
|||
} |
@ -1,10 +1,5 @@ |
|||
<template> |
|||
<DndProvider :backend="HTML5Backend"> |
|||
<w-platform-page></w-platform-page> |
|||
</DndProvider> |
|||
<w-platform-page></w-platform-page> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { DndProvider } from 'vue3-dnd'; |
|||
import { HTML5Backend } from 'react-dnd-html5-backend'; |
|||
</script> |
|||
<script setup lang="ts"></script> |
|||
|
@ -0,0 +1,118 @@ |
|||
<template> |
|||
<q-dialog v-model="dialog.dialogShow" allow-focus-outside v-bind="extractDialogProps(dialogProps)" :maximized="dialog.maximizedToggle"> |
|||
<q-card :style="dialogStyleComputed"> |
|||
<div class="w-full h-full"> |
|||
<div style="height: 69px"> |
|||
<q-card-section> |
|||
<div class="flex justify-between"> |
|||
<div class="text-h6">{{ dialogTitle }}</div> |
|||
<div class="flex justify-end gap-4"> |
|||
<template v-for="(btn, index) in dialogButtons as any" :key="index"> |
|||
<q-btn |
|||
v-if="typeof btn === 'object'" |
|||
:loading="btn.loading ? btn.loading : false" |
|||
:label="btn.label" |
|||
:icon="btn.icon" |
|||
color="primary" |
|||
@click="btn.click()" |
|||
> |
|||
</q-btn> |
|||
</template> |
|||
<q-btn |
|||
v-if="dialogMaximized" |
|||
dense |
|||
flat |
|||
:icon="!dialog.maximizedToggle ? PlatformIconEnum.全屏 : PlatformIconEnum.退出全屏" |
|||
@click="dialogMaximizeBtnClick" |
|||
> |
|||
<q-tooltip v-if="!dialog.maximizedToggle">全屏</q-tooltip> |
|||
<q-tooltip v-else-if="dialog.maximizedToggle">退出全屏</q-tooltip> |
|||
</q-btn> |
|||
<q-btn v-close-popup dense flat :icon="PlatformIconEnum.关闭"> |
|||
<q-tooltip>关闭</q-tooltip> |
|||
</q-btn> |
|||
</div> |
|||
</div> |
|||
</q-card-section> |
|||
<q-separator /> |
|||
</div> |
|||
<div style="height: calc(100% - 69px)"> |
|||
<q-card-section v-if="!dialogSplitter" style="height: 100%" class="scroll"> |
|||
<slot name="content"></slot> |
|||
</q-card-section> |
|||
<q-splitter v-else v-model="dialog.splitterModel" :limits="dialog.splitterLimits" :horizontal="dialog.splitterHorizontal" style="height: 100%"> |
|||
<template #before> |
|||
<slot name="splitterBefore"></slot> |
|||
</template> |
|||
<template #after> |
|||
<slot name="splitterAfter"></slot> |
|||
</template> |
|||
</q-splitter> |
|||
</div> |
|||
</div> |
|||
</q-card> |
|||
</q-dialog> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { reactive, computed } from 'vue'; |
|||
import { extractDialogProps, PlatformIconEnum } from '@/platform/components/utils'; |
|||
|
|||
import '@/css/tailwind.css'; |
|||
|
|||
const props = defineProps({ |
|||
dialogProps: { |
|||
type: Object, |
|||
default: () => { |
|||
return {}; |
|||
}, |
|||
}, |
|||
dialogTitle: { type: String, default: '' }, |
|||
dialogInitWidth: { type: String, default: '70%' }, |
|||
dialogInitHeight: { type: String, default: '70%' }, |
|||
dialogInitMaximized: { type: Boolean, default: false }, |
|||
dialogMaximized: { type: Boolean, default: true }, |
|||
dialogButtons: { type: Array, default: () => [] }, |
|||
dialogSplitter: { type: Object, default: undefined }, |
|||
}); |
|||
|
|||
const emit = defineEmits<{ |
|||
( |
|||
e: 'dialogMaximize', // 全屏按钮点击事件 |
|||
maximizedToggle: boolean, // 第一个参数,true:全屏状态,false:退出全屏 |
|||
): void; |
|||
}>(); |
|||
|
|||
const dialog = reactive({ |
|||
dialogShow: false, |
|||
maximizedToggle: props.dialogInitMaximized, |
|||
splitterModel: props.dialogSplitter?.splitterModel || 50, |
|||
splitterLimits: props.dialogSplitter?.limits || [0, 100], |
|||
splitterHorizontal: props.dialogSplitter?.horizontal || false, |
|||
}); |
|||
|
|||
const dialogMaximizeBtnClick = () => { |
|||
dialog.maximizedToggle = !dialog.maximizedToggle; |
|||
emit('dialogMaximize', dialog.maximizedToggle); |
|||
}; |
|||
|
|||
const dialogStyleComputed = computed(() => { |
|||
if (!dialog.maximizedToggle) { |
|||
return { width: props.dialogInitWidth, 'max-width': '100vw', height: props.dialogInitHeight, 'max-height': '100vh' }; |
|||
} else { |
|||
return { width: '100vw', 'max-width': '100vw', height: '100vh', 'max-height': '100vh' }; |
|||
} |
|||
}); |
|||
|
|||
const dialogShow = () => { |
|||
dialog.dialogShow = true; |
|||
}; |
|||
const dialogHide = () => { |
|||
dialog.dialogShow = false; |
|||
}; |
|||
|
|||
defineExpose({ |
|||
dialogShow, |
|||
dialogHide, |
|||
}); |
|||
</script> |
@ -0,0 +1,107 @@ |
|||
<template> |
|||
<q-dialog v-model="dialog.dialogShow" allow-focus-outside v-bind="attrs"> |
|||
<q-card |
|||
:style="{ |
|||
width: dialog.maximized ? '100vw' : props.width, |
|||
'max-width': '100vw', |
|||
height: dialog.maximized ? '100vh' : props.height, |
|||
'max-height': '100vh', |
|||
}" |
|||
> |
|||
<div class="w-full h-full"> |
|||
<div style="height: 69px"> |
|||
<q-card-section> |
|||
<div class="flex justify-between"> |
|||
<div class="text-h6">{{ title }}</div> |
|||
<div class="flex justify-end gap-4"> |
|||
<template v-for="(btn, index) in buttons as any" :key="index"> |
|||
<q-btn |
|||
v-if="typeof btn === 'object'" |
|||
:loading="btn.loading ? btn.loading : false" |
|||
:label="btn.label" |
|||
:icon="btn.icon" |
|||
color="primary" |
|||
@click="btn.click()" |
|||
> |
|||
</q-btn> |
|||
</template> |
|||
<q-btn v-if="canMaximize" dense flat :icon="!dialog.maximized ? IconEnum.全屏 : IconEnum.退出全屏" @click="maximizeBtnClick"> |
|||
<q-tooltip v-if="!dialog.maximized">全屏</q-tooltip> |
|||
<q-tooltip v-else-if="dialog.maximized">退出全屏</q-tooltip> |
|||
</q-btn> |
|||
<q-btn v-close-popup dense flat :icon="IconEnum.关闭"> |
|||
<q-tooltip>关闭</q-tooltip> |
|||
</q-btn> |
|||
</div> |
|||
</div> |
|||
</q-card-section> |
|||
<q-separator /> |
|||
</div> |
|||
<div style="height: calc(100% - 69px)"> |
|||
<q-card-section v-if="!splitter" style="height: 100%" class="scroll"> |
|||
<slot name="content"></slot> |
|||
</q-card-section> |
|||
<q-splitter v-else v-model="dialog.splitterModel" :limits="dialog.splitterLimits" :horizontal="dialog.splitterHorizontal" style="height: 100%"> |
|||
<template #before> |
|||
<slot name="splitterBefore"></slot> |
|||
</template> |
|||
<template #after> |
|||
<slot name="splitterAfter"></slot> |
|||
</template> |
|||
</q-splitter> |
|||
</div> |
|||
</div> |
|||
</q-card> |
|||
</q-dialog> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { reactive, useAttrs } from 'vue'; |
|||
import { IconEnum } from '@/platform/enums'; |
|||
import { Tools } from '@/platform/utils'; |
|||
|
|||
import '@/css/tailwind.css'; |
|||
|
|||
const attrs = useAttrs(); |
|||
|
|||
const props = defineProps({ |
|||
title: { type: String, default: '' }, |
|||
width: { type: String, default: '70%' }, |
|||
height: { type: String, default: '70%' }, |
|||
canMaximize: { type: Boolean, default: true }, |
|||
buttons: { type: Array, default: () => [] }, |
|||
splitter: { type: Object, default: undefined }, |
|||
}); |
|||
|
|||
const emit = defineEmits<{ |
|||
( |
|||
e: 'maximized', // 全屏按钮点击事件 |
|||
maximized: boolean, // 第一个参数,true:全屏状态,false:退出全屏 |
|||
): void; |
|||
}>(); |
|||
|
|||
const dialog = reactive({ |
|||
show: false, |
|||
maximized: attrs.maximized, |
|||
splitterModel: props.splitter?.splitterModel || 50, |
|||
splitterLimits: props.splitter?.limits || [0, 100], |
|||
splitterHorizontal: props.splitter?.horizontal || false, |
|||
}); |
|||
|
|||
const maximizeBtnClick = () => { |
|||
dialog.maximized = !dialog.maximized; |
|||
emit('maximized', dialog.maximized); |
|||
}; |
|||
|
|||
const show = () => { |
|||
dialog.dialogShow = true; |
|||
}; |
|||
const hide = () => { |
|||
dialog.dialogShow = false; |
|||
}; |
|||
|
|||
defineExpose({ |
|||
show, |
|||
hide, |
|||
}); |
|||
</script> |
@ -0,0 +1,103 @@ |
|||
<template> |
|||
<q-dialog v-model="drawer.drawerShow" v-bind="extractDialogProps(drawerProps)" :maximized="drawer.maximizedToggle"> |
|||
<q-card :style="drawerStyleComputed"> |
|||
<div class="w-full h-full"> |
|||
<div style="height: 64px"> |
|||
<q-card-section> |
|||
<div class="flex justify-between"> |
|||
<div class="text-h6">{{ drawerTitle }}</div> |
|||
<div class="flex justify-end gap-4"> |
|||
<q-btn |
|||
v-if="drawerMaximized" |
|||
dense |
|||
flat |
|||
:icon="!drawer.actualMaximizedToggle ? PlatformIconEnum.全屏 : PlatformIconEnum.退出全屏" |
|||
@click="drawerMaximizeBtnClick" |
|||
> |
|||
<q-tooltip v-if="!drawer.actualMaximizedToggle">全屏</q-tooltip> |
|||
<q-tooltip v-else-if="drawer.actualMaximizedToggle">退出全屏</q-tooltip> |
|||
</q-btn> |
|||
<q-btn v-close-popup dense flat :icon="PlatformIconEnum.关闭"> |
|||
<q-tooltip>关闭</q-tooltip> |
|||
</q-btn> |
|||
</div> |
|||
</div> |
|||
</q-card-section> |
|||
<q-separator /> |
|||
</div> |
|||
<div :style="drawerButtons && drawerButtons.length > 0 ? 'height:calc(100% - 132px)' : 'height:calc(100% - 64px)'"> |
|||
<q-card-section style="height: 100%" class="scroll"> |
|||
<slot name="content"></slot> |
|||
</q-card-section> |
|||
</div> |
|||
<div v-if="drawerButtons && drawerButtons.length > 0" style="height: 64px"> |
|||
<q-separator /> |
|||
<q-card-actions align="right" class="px-6 pt-4"> |
|||
<template v-for="(btn, index) in drawerButtons as any" :key="index"> |
|||
<q-btn |
|||
v-if="typeof btn === 'object'" |
|||
:loading="btn.loading ? btn.loading : false" |
|||
:label="btn.label" |
|||
:icon="btn.icon" |
|||
unelevated |
|||
outline |
|||
@click="btn.click()" |
|||
></q-btn> |
|||
</template> |
|||
</q-card-actions> |
|||
</div> |
|||
</div> |
|||
</q-card> |
|||
</q-dialog> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { reactive, computed } from 'vue'; |
|||
import { extractDialogProps, PlatformIconEnum } from '@/platform/components/utils'; |
|||
|
|||
import '@/css/tailwind.css'; |
|||
|
|||
const props = defineProps({ |
|||
drawerProps: { type: Object, default: () => {} }, |
|||
drawerTitle: { type: String, default: '' }, |
|||
drawerInitWidth: { type: String, default: '50vw' }, |
|||
drawerInitHeight: { type: String, default: '100vh' }, |
|||
drawerMaximized: { type: Boolean, default: true }, |
|||
drawerButtons: { type: Array, default: () => [] }, |
|||
}); |
|||
|
|||
const drawer = reactive({ |
|||
drawerShow: false, |
|||
maximizedToggle: true, |
|||
/** |
|||
* 实际全屏属性,Drawer 使用的 dialog 进行封装,而 dialog 的非全屏模式, |
|||
* 不管高宽给到多少,Quasar 内置的 css 样式都会有一个 padding: 24px 的属性, |
|||
* 所以封装 Drawer 时默认就是 dialog 的全屏模式,同时希望提供全屏的功能,所以需要一个实际是否全屏的属性。 |
|||
*/ |
|||
actualMaximizedToggle: false, |
|||
}); |
|||
|
|||
const drawerMaximizeBtnClick = () => { |
|||
drawer.actualMaximizedToggle = !drawer.actualMaximizedToggle; |
|||
}; |
|||
|
|||
const drawerStyleComputed = computed(() => { |
|||
if (!drawer.actualMaximizedToggle) { |
|||
return { width: props.drawerInitWidth, 'max-width': '100vw', height: props.drawerInitHeight, 'max-height': '100vh' }; |
|||
} else { |
|||
return { width: '100vw', 'max-width': '100vw', height: '100vh', 'max-height': '100vh' }; |
|||
} |
|||
}); |
|||
|
|||
const drawerShow = () => { |
|||
drawer.drawerShow = true; |
|||
}; |
|||
const drawerHide = () => { |
|||
drawer.drawerShow = false; |
|||
}; |
|||
|
|||
defineExpose({ |
|||
drawerShow, |
|||
drawerHide, |
|||
}); |
|||
</script> |
@ -0,0 +1,528 @@ |
|||
<template> |
|||
<q-form ref="formRef" v-bind="extractFormProps(formProps)"> |
|||
<div class="grid gap-2" :class="formLayoutComputed"> |
|||
<template v-for="(field, index) in formFields as any" :key="String(index)"> |
|||
<q-input |
|||
v-if="field.type === 'dateRange' && index < queryFormShowFieldNumber" |
|||
v-show="!field.hasOwnProperty('hide') || !field.hide" |
|||
v-model="formData[field.fmtModelName]" |
|||
:label="field.required ? '* ' + field.label : field.label" |
|||
:rules="fieldRulesFun(field.required, field)" |
|||
v-bind="extractFormItemComponentProps(field.type, field)" |
|||
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false" |
|||
@update:model-value="field.changeFun" |
|||
> |
|||
<template #append> |
|||
<q-icon :name="PlatformIconEnum.日期范围" class="cursor-pointer"> |
|||
<q-popup-proxy cover transition-show="scale" transition-hide="scale"> |
|||
<q-date |
|||
v-model="formData[field.modelName]" |
|||
range |
|||
:mask="field.mask ? field.mask : 'YYYY-MM-DD'" |
|||
:readonly="formStatus === 'view' || field.readonly ? true : false" |
|||
> |
|||
<div class="row items-center justify-end"> |
|||
<q-btn v-close-popup label="关闭" color="primary" flat /> |
|||
</div> |
|||
</q-date> |
|||
</q-popup-proxy> |
|||
</q-icon> |
|||
</template> |
|||
</q-input> |
|||
<q-input |
|||
v-else-if="field.type === 'date' && index < queryFormShowFieldNumber" |
|||
v-show="!field.hasOwnProperty('hide') || !field.hide" |
|||
v-model="formData[field.modelName]" |
|||
:label="field.required ? '* ' + field.label : field.label" |
|||
:rules="fieldRulesFun(field.required, field)" |
|||
v-bind="extractFormItemComponentProps(field.type, field)" |
|||
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false" |
|||
@update:model-value="field.changeFun" |
|||
> |
|||
<template #append> |
|||
<q-icon :name="PlatformIconEnum.日期" class="cursor-pointer"> |
|||
<q-popup-proxy cover transition-show="scale" transition-hide="scale"> |
|||
<q-date |
|||
v-model="formData[field.modelName]" |
|||
today-btn |
|||
:mask="field.mask ? field.mask : 'YYYY-MM-DD'" |
|||
:readonly="formStatus === 'view' || field.readonly ? true : false" |
|||
> |
|||
<div class="row items-center justify-end"> |
|||
<q-btn v-close-popup label="关闭" color="primary" flat /> |
|||
</div> |
|||
</q-date> |
|||
</q-popup-proxy> |
|||
</q-icon> |
|||
</template> |
|||
</q-input> |
|||
<q-select |
|||
v-else-if="field.type === 'select' && index < queryFormShowFieldNumber" |
|||
v-show="!field.hasOwnProperty('hide') || !field.hide" |
|||
v-model="formData[field.modelName]" |
|||
:label="field.required ? '* ' + field.label : field.label" |
|||
:rules="fieldRulesFun(field.required, field)" |
|||
v-bind="extractFormItemComponentProps(field.type, field)" |
|||
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false" |
|||
@update:model-value="field.changeFun" |
|||
@filter="field.filterFun" |
|||
@focus="field.focusFun" |
|||
> |
|||
<template v-if="field.afterButton" #after> |
|||
<q-btn |
|||
:round="field.afterButton.round" |
|||
:dense="field.afterButton.dense" |
|||
:flat="field.afterButton.flat" |
|||
:unelevated="field.afterButton.unelevated" |
|||
:outline="field.afterButton.outline" |
|||
:color="field.afterButton.color" |
|||
:icon="field.afterButton.icon" |
|||
:label="field.afterButton.label" |
|||
:disable="formStatus === PageStatusEnum.查看 || field.afterButton.disable ? true : false" |
|||
@click="field.afterButton.click" |
|||
/> |
|||
</template> |
|||
</q-select> |
|||
<q-checkbox |
|||
v-else-if="field.type === 'checkbox' && index < queryFormShowFieldNumber" |
|||
v-show="!field.hasOwnProperty('hide') || !field.hide" |
|||
v-model="formData[field.modelName]" |
|||
:label="field.required ? '* ' + field.label : field.label" |
|||
v-bind="extractFormItemComponentProps(field.type, field)" |
|||
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false" |
|||
@update:model-value="field.changeFun" |
|||
/> |
|||
<div |
|||
v-else-if="field.type === 'optionGroup' && index < queryFormShowFieldNumber" |
|||
v-show="!field.hasOwnProperty('hide') || !field.hide" |
|||
class="border-solid border" |
|||
> |
|||
<span class="p-2.5">{{ field.label }}</span> |
|||
<q-option-group |
|||
v-model="formData[field.modelName]" |
|||
v-bind="extractFormItemComponentProps(field.type, field)" |
|||
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false" |
|||
@update:model-value="field.changeFun" |
|||
/> |
|||
</div> |
|||
<q-input |
|||
v-else-if="index < queryFormShowFieldNumber" |
|||
v-show="!field.hasOwnProperty('hide') || !field.hide" |
|||
v-model="formData[field.modelName]" |
|||
:label="field.required ? '* ' + field.label : field.label" |
|||
:rules="fieldRulesFun(field.required, field)" |
|||
v-bind="extractFormItemComponentProps(field.type, field)" |
|||
:readonly="formStatus === PageStatusEnum.查看 || field.readonly ? true : false" |
|||
@update:model-value="field.changeFun" |
|||
> |
|||
<template v-if="field.afterButton" #after> |
|||
<q-btn |
|||
round |
|||
dense |
|||
flat |
|||
:disable="formStatus === PageStatusEnum.查看 || field.afterButton.disable ? true : false" |
|||
:icon="field.afterButton.icon" |
|||
@click="field.afterButton.click" |
|||
/> |
|||
</template> |
|||
</q-input> |
|||
</template> |
|||
</div> |
|||
<slot></slot> |
|||
</q-form> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { ref, reactive, watch, computed, toRaw, defineProps } from 'vue'; |
|||
import { |
|||
extractFormProps, |
|||
extractFormItemComponentProps, |
|||
arrayToMap, |
|||
PlatformIconEnum, |
|||
FormComponentValidateEnum, |
|||
PageStatusEnum, |
|||
isEmpty, |
|||
} from '@/platform/components/utils'; |
|||
|
|||
const props = defineProps({ |
|||
formProps: { |
|||
type: Object, |
|||
default: () => { |
|||
return { autofocus: false, greedy: true }; |
|||
}, |
|||
}, |
|||
formColsNumber: { type: Number, default: 3 }, |
|||
formColsAuto: { type: Boolean, default: true }, |
|||
formFields: { |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
}, |
|||
}, |
|||
queryFormShowFieldNumber: { type: Number, default: 999 }, |
|||
}); |
|||
|
|||
const formRef = ref(); |
|||
const formStatus = ref('add'); |
|||
const formFieldsMap = arrayToMap('modelName', props.formFields); |
|||
|
|||
// 由于采用字符串拼接 class 名称,tailwind 无法生效,模板文件中必须出现完整的类名,最终构建的css文件中才会包含进去。 |
|||
const formLayoutComputed = computed(() => { |
|||
let className = ''; |
|||
switch (props.formColsNumber) { |
|||
case 1: |
|||
className = !props.formColsAuto ? 'grid-cols-1' : 'xs:grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'; |
|||
break; |
|||
case 2: |
|||
className = !props.formColsAuto ? 'grid-cols-2' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'; |
|||
break; |
|||
case 4: |
|||
className = !props.formColsAuto ? 'grid-cols-4' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-4 xl:grid-cols-6'; |
|||
break; |
|||
case 5: |
|||
className = !props.formColsAuto ? 'grid-cols-5' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-6'; |
|||
break; |
|||
case 6: |
|||
className = !props.formColsAuto ? 'grid-cols-6' : 'xs:grid-cols-1 sm:grid-cols-3 md:grid-cols-6 lg:grid-cols-6 xl:grid-cols-6'; |
|||
break; |
|||
case 7: |
|||
className = !props.formColsAuto ? 'grid-cols-7' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-7 lg:grid-cols-7 xl:grid-cols-7'; |
|||
break; |
|||
case 8: |
|||
className = !props.formColsAuto ? 'grid-cols-8' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-8 lg:grid-cols-8 xl:grid-cols-8'; |
|||
break; |
|||
case 9: |
|||
className = !props.formColsAuto ? 'grid-cols-9' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-9 lg:grid-cols-9 xl:grid-cols-9'; |
|||
break; |
|||
case 10: |
|||
className = !props.formColsAuto ? 'grid-cols-10' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-10 lg:grid-cols-10 xl:grid-cols-10'; |
|||
break; |
|||
case 11: |
|||
className = !props.formColsAuto ? 'grid-cols-11' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-11 lg:grid-cols-11 xl:grid-cols-11'; |
|||
break; |
|||
case 12: |
|||
className = !props.formColsAuto ? 'grid-cols-12' : 'xs:grid-cols-1 sm:grid-cols-4 md:grid-cols-12 lg:grid-cols-12 xl:grid-cols-12'; |
|||
break; |
|||
default: |
|||
className = !props.formColsAuto ? 'grid-cols-3' : 'xs:grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6'; |
|||
} |
|||
return className; |
|||
}); |
|||
|
|||
const selectDefaultValue = (field) => { |
|||
if (field.hasOwnProperty.call('defaultValue') && field.defaultValue !== null) { |
|||
if (typeof field.defaultValue === 'string' || typeof field.defaultValue === 'boolean' || typeof field.defaultValue === 'number') { |
|||
const dftValue = field.options.filter((item) => { |
|||
return item.value === field.defaultValue; |
|||
}); |
|||
if (dftValue && dftValue.length > 0) { |
|||
return field.multiple ? [dftValue[0]] : dftValue[0]; |
|||
} else { |
|||
return field.multiple ? [] : ''; |
|||
} |
|||
} else if (Array.isArray(field.defaultValue)) { |
|||
const dftValue = field.options.filter((item) => { |
|||
return field.defaultValue.filter((val) => { |
|||
return val === item.value; |
|||
}); |
|||
}); |
|||
return field.multiple ? dftValue : dftValue[0]; |
|||
} |
|||
} else { |
|||
return field.multiple ? [] : ''; |
|||
} |
|||
}; |
|||
|
|||
const numberDefaultValue = (field) => { |
|||
if (field.hasOwnProperty.call('defaultValue') && typeof field.defaultValue === 'number') { |
|||
return field.defaultValue; |
|||
} else { |
|||
return ''; |
|||
} |
|||
}; |
|||
|
|||
const checkboxDefaultValue = (field) => { |
|||
if (field.hasOwnProperty.call('defaultValue')) { |
|||
return field.defaultValue; |
|||
} else { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
const optionGroupDefaultValue = (field) => { |
|||
if (field.hasOwnProperty.call('defaultValue')) { |
|||
return field.defaultValue; |
|||
} else if (field.optionGroupType && field.optionGroupType === 'checkbox') { |
|||
return []; |
|||
} else { |
|||
return ''; |
|||
} |
|||
}; |
|||
|
|||
const textDefaultValue = (field) => { |
|||
if (field.hasOwnProperty.call('defaultValue')) { |
|||
return field.defaultValue; |
|||
} else { |
|||
return ''; |
|||
} |
|||
}; |
|||
|
|||
const formModel: any = {}; |
|||
for (const field of props.formFields as any) { |
|||
if (field.type === 'dateRange') { |
|||
formModel[field.fmtModelName] = ''; |
|||
} else if (field.type === 'select') { |
|||
formModel[field.modelName] = selectDefaultValue(field); |
|||
} else if (field.type === 'number') { |
|||
formModel[field.modelName] = numberDefaultValue(field); |
|||
} else if (field.type === 'checkbox') { |
|||
formModel[field.modelName] = checkboxDefaultValue(field); |
|||
} else if (field.type === 'optionGroup') { |
|||
formModel[field.modelName] = optionGroupDefaultValue(field); |
|||
} else { |
|||
formModel[field.modelName] = textDefaultValue(field); |
|||
} |
|||
} |
|||
const formData = reactive(formModel); |
|||
for (const field of props.formFields as any) { |
|||
if (field.type === 'dateRange') { |
|||
watch( |
|||
() => formData[field.modelName], |
|||
(newVal, oldVal) => { |
|||
if (!newVal || newVal.from === '') { |
|||
formData[field.fmtModelName] = ''; |
|||
} else { |
|||
formData[field.fmtModelName] = newVal.from + ' 至 ' + newVal.to; |
|||
} |
|||
}, |
|||
); |
|||
} |
|||
} |
|||
|
|||
const isNumber = (num) => { |
|||
return !isNaN(parseFloat(num)) && isFinite(num); |
|||
}; |
|||
|
|||
const fieldRulesFun = (required, field) => { |
|||
let resultRules = <any>[]; |
|||
if (field.type === 'select' && field.multiple && required) { |
|||
resultRules.push((val) => { |
|||
if (val !== null && val.length > 0) { |
|||
return true; |
|||
} else { |
|||
return '该字段为必填项'; |
|||
} |
|||
}); |
|||
} else if (required) { |
|||
resultRules.push((val) => (val !== null && val !== '') || '该字段为必填项'); |
|||
} |
|||
if (field.rules && field.rules.length > 0) { |
|||
field.rules.forEach((rule) => { |
|||
if (typeof rule === 'string' && rule === FormComponentValidateEnum.字符串不能包含空格校验) { |
|||
// 字符串不能包含空格校验 |
|||
resultRules.push((val) => { |
|||
if (isEmpty(val) || val.indexOf(' ') === -1) { |
|||
return true; |
|||
} else { |
|||
return '不能包含空格'; |
|||
} |
|||
}); |
|||
} else if (typeof rule === 'string' && rule === FormComponentValidateEnum.默认日期格式校验) { |
|||
resultRules.push((val) => { |
|||
if (isEmpty(val) || /^(\d{4})-(\d{2})-(\d{2})$/.test(val)) { |
|||
return true; |
|||
} else { |
|||
return '日期格式校验未通过'; |
|||
} |
|||
}); |
|||
} else if (typeof rule === 'string' && rule === FormComponentValidateEnum.必须为整数校验) { |
|||
// 必须为整数校验 |
|||
resultRules.push((val) => { |
|||
const tmp = String(val); |
|||
if (val === null || (tmp.indexOf('.') === -1 && Number.isInteger(parseInt(tmp)))) { |
|||
return true; |
|||
} else { |
|||
return '只能输入整数'; |
|||
} |
|||
}); |
|||
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.字符串最大长度校验) { |
|||
// 字符串最大长度校验 |
|||
resultRules.push((val) => { |
|||
const tmp = String(val); |
|||
if (val === null || tmp.length <= rule.value) { |
|||
return true; |
|||
} else { |
|||
return '最大允许输入的长度为:' + rule.value; |
|||
} |
|||
}); |
|||
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.最大小数位数校验) { |
|||
// 最大小数位数校验 |
|||
resultRules.push((val) => { |
|||
const tmp = String(val); |
|||
if (val === null || tmp.indexOf('.') === -1 || tmp.substring(tmp.indexOf('.') + 1).length <= rule.value) { |
|||
return true; |
|||
} else { |
|||
return '最大允许输入的小数位数为:' + rule.value; |
|||
} |
|||
}); |
|||
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.数字最小值校验) { |
|||
// 数字最小值校验 |
|||
resultRules.push((val) => { |
|||
const tmp = String(val); |
|||
if (val === null || parseFloat(tmp) >= rule.value) { |
|||
return true; |
|||
} else { |
|||
return '最小允许输入的值为:' + rule.value; |
|||
} |
|||
}); |
|||
} else if (typeof rule === 'object' && rule.name === FormComponentValidateEnum.数字最大值校验) { |
|||
// 数字最大值校验 |
|||
resultRules.push((val) => { |
|||
const tmp = String(val); |
|||
if (val === null || parseFloat(tmp) <= rule.value) { |
|||
return true; |
|||
} else { |
|||
return '最大允许输入的值为:' + rule.value; |
|||
} |
|||
}); |
|||
} else { |
|||
resultRules.push(rule); |
|||
} |
|||
}); |
|||
} |
|||
return resultRules; |
|||
}; |
|||
|
|||
const formValidateFun = async () => { |
|||
const v = await formValidate(); |
|||
return v; |
|||
}; |
|||
const formValidate = async () => { |
|||
let validate = false; |
|||
await formRef.value.validate().then((success) => { |
|||
if (success) { |
|||
validate = true; |
|||
} |
|||
}); |
|||
return validate; |
|||
}; |
|||
|
|||
const getFormDataFun = () => { |
|||
const data = { ...toRaw(formData) }; |
|||
const selectFields = props.formFields.filter((item: any) => { |
|||
return item.type === 'select'; |
|||
}); |
|||
selectFields.forEach((item: any) => { |
|||
let selectValues = ''; |
|||
if (item.multiple && data[item.modelName] && data[item.modelName].length > 0) { |
|||
data[item.modelName].forEach((val) => { |
|||
selectValues = selectValues + ',' + val.value; |
|||
}); |
|||
selectValues = selectValues.substring(1, selectValues.length); |
|||
} else if (data[item.modelName]) { |
|||
selectValues = data[item.modelName].value ?? data[item.modelName]; |
|||
} |
|||
data[item.modelName] = selectValues; |
|||
}); |
|||
return data; |
|||
}; |
|||
|
|||
const setFormDataFun = (record) => { |
|||
for (const field of props.formFields as any) { |
|||
if (field.type === 'select') { |
|||
if (field.multiple && record[field.modelName].indexOf(',') > -1) { |
|||
const recordSelectValues = record[field.modelName].split(','); |
|||
const selectValues = <any>[]; |
|||
recordSelectValues.forEach((item) => { |
|||
selectValues.push(setSelectValue(field.options, item)); |
|||
}); |
|||
formData[field.modelName] = selectValues; |
|||
} else { |
|||
formData[field.modelName] = setSelectValue(field.options, record[field.modelName]); |
|||
} |
|||
} else if (field.type === 'optionGroup') { |
|||
if (record[field.modelName]) { |
|||
formData[field.modelName] = record[field.modelName]; |
|||
} else { |
|||
formData[field.modelName] = []; |
|||
} |
|||
} else { |
|||
formData[field.modelName] = record[field.modelName]; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const setSelectValue = (options, val) => { |
|||
const opt = options.filter((option) => { |
|||
return option.value === val; |
|||
}); |
|||
if (opt && opt.length > 0) { |
|||
return opt[0]; |
|||
} else { |
|||
return val; |
|||
} |
|||
}; |
|||
|
|||
const setFieldValueFun = (fieldName, value) => { |
|||
const field = formFieldsMap.get(fieldName); |
|||
if (field.type === 'select') { |
|||
if (field.multiple && Array.isArray(value)) { |
|||
const selectValues = <any>[]; |
|||
value.forEach((item) => { |
|||
selectValues.push(setSelectValue(field.options, item)); |
|||
}); |
|||
formData[field.modelName] = selectValues; |
|||
} else { |
|||
formData[field.modelName] = setSelectValue(field.options, value); |
|||
} |
|||
} else { |
|||
formData[field.modelName] = value; |
|||
} |
|||
}; |
|||
const getFieldValueFun = (fieldName) => { |
|||
return formData[fieldName]; |
|||
}; |
|||
|
|||
const resetFormDataFun = () => { |
|||
Object.keys(formData).forEach((key) => { |
|||
switch (typeof formData[key]) { |
|||
case 'string': |
|||
formData[key] = ''; |
|||
break; |
|||
case 'boolean': |
|||
formData[key] = false; |
|||
break; |
|||
case 'number': |
|||
formData[key] = ''; |
|||
break; |
|||
default: |
|||
formData[key] = undefined; |
|||
break; |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
const setFormStatusFun = (status) => { |
|||
formStatus.value = status; |
|||
}; |
|||
|
|||
const getFormStatusFun = () => { |
|||
return toRaw(formStatus.value); |
|||
}; |
|||
|
|||
const getFormFieldMapFun = () => { |
|||
return formFieldsMap; |
|||
}; |
|||
|
|||
defineExpose({ |
|||
formValidateFun, |
|||
getFormDataFun, |
|||
setFormDataFun, |
|||
getFormStatusFun, |
|||
setFormStatusFun, |
|||
resetFormDataFun, |
|||
setFieldValueFun, |
|||
getFieldValueFun, |
|||
getFormFieldMapFun, |
|||
}); |
|||
</script> |
File diff suppressed because it is too large
@ -0,0 +1,30 @@ |
|||
<template> |
|||
<div :ref="(node) => drag(drop(node as any))" :class="borderClass"> |
|||
<q-icon v-if="typeof tdValue[0] === 'boolean' && tdValue[0]" :name="PlatformIconEnum.是状态" color="green" size="sm"> </q-icon> |
|||
<template v-else-if="typeof tdValue[0] === 'boolean' && !tdValue[0]"> </template> |
|||
<template v-else> |
|||
{{ tdValue[0] }} |
|||
</template> |
|||
</div> |
|||
</template> |
|||
|
|||
<script lang="ts" setup> |
|||
import { computed, unref } from 'vue'; |
|||
import { toRefs } from '@vueuse/core'; |
|||
import { PlatformIconEnum } from '@/platform/components/utils'; |
|||
|
|||
const props = defineProps({ |
|||
tdValue: { |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
}, |
|||
}, |
|||
rowIndex: { type: Number, default: 0 }, |
|||
}); |
|||
const emit = defineEmits(['tableSortFun']); |
|||
|
|||
export interface DropResult { |
|||
name: string; |
|||
} |
|||
</script> |
@ -0,0 +1,85 @@ |
|||
<template> |
|||
<q-markup-table separator="cell" flat bordered wrap-cells> |
|||
<tbody> |
|||
<template v-for="(trItem, trIndex) in tableComputed" :key="trIndex"> |
|||
<tr class="q-tr--no-hover"> |
|||
<template v-for="(tdItem, tdIndex) in trItem as any" :key="tdIndex"> |
|||
<td :class="labelAlignClassComputed">{{ tdItem.label }}</td> |
|||
<td :class="valueAlignClassComputed">{{ tdItem.value }}</td> |
|||
</template> |
|||
</tr> |
|||
</template> |
|||
</tbody> |
|||
</q-markup-table> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { computed } from 'vue'; |
|||
import { getCssVar } from 'quasar'; |
|||
import { Environment } from '@/platform'; |
|||
|
|||
const gc = Environment.getConfigure(); |
|||
const darkBgColor = getCssVar('dark'); |
|||
const bgColor = gc.theme.dark ? darkBgColor : gc.theme?.grid?.headBgColor || '#f5f7fa'; |
|||
const props = defineProps({ |
|||
column: { type: Number, default: 1 }, |
|||
labelAlign: { type: String, default: 'left' }, |
|||
valueAlign: { type: String, default: 'left' }, |
|||
infoArray: { |
|||
type: Array, |
|||
default: () => { |
|||
return []; |
|||
}, |
|||
}, |
|||
}); |
|||
|
|||
const tableComputed = computed(() => { |
|||
const table = <any>[]; |
|||
let tmp = <any>[]; |
|||
props.infoArray.forEach((item, index) => { |
|||
if (tmp.length < props.column) { |
|||
tmp.push(item); |
|||
} else { |
|||
table.push(tmp); |
|||
tmp = []; |
|||
tmp.push(item); |
|||
} |
|||
}); |
|||
table.push(tmp); |
|||
return table; |
|||
}); |
|||
const labelAlignClassComputed = computed(() => { |
|||
let className = ''; |
|||
switch (props.labelAlign) { |
|||
case 'right': |
|||
className = 'text-right'; |
|||
break; |
|||
case 'center': |
|||
className = 'text-center'; |
|||
break; |
|||
default: |
|||
className = 'text-left'; |
|||
} |
|||
return className; |
|||
}); |
|||
const valueAlignClassComputed = computed(() => { |
|||
let className = ''; |
|||
switch (props.valueAlign) { |
|||
case 'right': |
|||
className = 'text-right'; |
|||
break; |
|||
case 'center': |
|||
className = 'text-center'; |
|||
break; |
|||
default: |
|||
className = 'text-left'; |
|||
} |
|||
return className; |
|||
}); |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.q-table td:nth-child(odd) { |
|||
background-color: v-bind(bgColor); |
|||
} |
|||
</style> |
@ -0,0 +1,186 @@ |
|||
import { QVueGlobals } from 'quasar'; |
|||
|
|||
/** |
|||
* 平台icon,使用【material icons】,以下为列举的一些平台常用的图标,并不包含全部 |
|||
* 不在该枚举中时可使用自定义的图标,目的是以后方便全局替换。 |
|||
*/ |
|||
export enum PlatformIconEnum { |
|||
查询 = 'search', |
|||
更多查询 = 'zoom_in', |
|||
重置 = 'restart_alt', |
|||
刷新 = 'loop', |
|||
新增 = 'add', |
|||
新增2 = 'add_box', |
|||
新增3 = 'playlist_add_circle', |
|||
编辑 = 'edit', |
|||
删除 = 'delete', |
|||
查看 = 'visibility', |
|||
全屏 = 'fullscreen', |
|||
退出全屏 = 'fullscreen_exit', |
|||
关闭 = 'close', |
|||
保存 = 'save', |
|||
提交 = 'beenhere', |
|||
字母 = 'abc', |
|||
时钟 = 'access_time', |
|||
上箭头 = 'arrow_upward', |
|||
下箭头 = 'arrow_downward', |
|||
左箭头 = 'arrow_back', |
|||
右箭头 = 'arrow_forward', |
|||
附件 = 'attach_file', |
|||
否状态 = 'cancel', |
|||
是状态 = 'check_circle', |
|||
首页 = 'home', |
|||
设置 = 'settings', |
|||
设置2 = 'settings_applications', |
|||
扳手 = 'build_circle', |
|||
收起 = 'arrow_drop_up', |
|||
展开 = 'arrow_drop_down', |
|||
提示 = 'info', |
|||
警告 = 'warning', |
|||
日期 = 'event', |
|||
日期范围 = 'date_range', |
|||
文件夹 = 'folder', |
|||
校验 = 'published_with_changes', |
|||
下载 = 'download', |
|||
上传 = 'upload', |
|||
选取变量 = 'find_in_page', |
|||
报表通用 = 'assessment', |
|||
复制 = 'file_copy', |
|||
发送 = 'send', |
|||
} |
|||
|
|||
/** |
|||
* 页面状态(包含:新增=add、编辑=edit、查看=view) |
|||
*/ |
|||
export enum PageStatusEnum { |
|||
新增 = 'add', |
|||
编辑 = 'edit', |
|||
查看 = 'view', |
|||
} |
|||
|
|||
/** |
|||
* Form元素类型枚举 |
|||
*/ |
|||
export enum FormTypeEnum { |
|||
文本框 = 'text', |
|||
文本域 = 'textarea', |
|||
下拉框 = 'select', |
|||
多选下拉框 = 'selectMultiple', |
|||
数字框 = 'number', |
|||
日期 = 'date', |
|||
日期时间 = 'dateTime', |
|||
日期范围 = 'dateRange', |
|||
} |
|||
|
|||
/** |
|||
* 数据类型枚举 |
|||
*/ |
|||
export enum DataTypeEnum { |
|||
字符串 = 'String', |
|||
整数 = 'Integer', |
|||
小数 = 'BigDecimal', |
|||
日期 = 'Date', |
|||
布尔 = 'Boolean', |
|||
} |
|||
|
|||
/** |
|||
* 下拉框选项值来源枚举 |
|||
*/ |
|||
export enum OptionComeFromEnum { |
|||
数据字典 = 'dictionary', |
|||
Java接口 = 'javaApi', |
|||
自定义数组 = 'array', |
|||
} |
|||
|
|||
/** |
|||
* 平台Form组件内置校验name枚举 |
|||
*/ |
|||
export enum FormComponentValidateEnum { |
|||
字符串不能包含空格校验 = 'noSpace', |
|||
必须为整数校验 = 'integer', |
|||
默认日期格式校验 = 'date', |
|||
字符串最大长度校验 = 'maxLength', |
|||
最大小数位数校验 = 'maxPrecision', |
|||
数字最小值校验 = 'minValue', |
|||
数字最大值校验 = 'maxValue', |
|||
} |
|||
|
|||
/** |
|||
* 查询操作类型枚举 |
|||
*/ |
|||
export enum OperatorTypeEnum { |
|||
isBlank = 'isBlank', // value is null or value=''
|
|||
notBlank = 'notBlank', // value is not null && value<>''
|
|||
|
|||
isNull = 'isNull', // value is null
|
|||
notNull = 'notNull', // value is not null
|
|||
|
|||
equals = 'equals', // =
|
|||
notEqual = 'notEqual', // <>
|
|||
|
|||
greaterThan = 'greaterThan', // >
|
|||
greaterOrEqual = 'greaterOrEqual', // >=
|
|||
|
|||
lessThan = 'lessThan', // <
|
|||
lessOrEqual = 'lessOrEqual', // <=
|
|||
|
|||
contains = 'contains', // like %xxx%
|
|||
notContains = 'notContains', // not like %xxx%
|
|||
|
|||
startsWith = 'startsWith', // like xxx%
|
|||
notStartsWith = 'notStartsWith', // not like xxx%
|
|||
|
|||
endsWith = 'endsWith', // like %xxx
|
|||
notEndsWith = 'notEndsWith', // not like %xxx
|
|||
|
|||
between = 'between', // min<x and x<max
|
|||
betweenInclusive = 'betweenInclusive', // min<=x and x<=max
|
|||
|
|||
inSet = 'inSet', // in ()
|
|||
notInSet = 'notInSet', // not in ()
|
|||
} |
|||
|
|||
// 查询对象
|
|||
export type CriteriaType = { |
|||
fieldName: string; |
|||
operator: OperatorTypeEnum; |
|||
value: any; |
|||
}; |
|||
|
|||
/** |
|||
* 平台消息提示类型枚举 |
|||
*/ |
|||
export enum PlatformNotifyTypeEnum { |
|||
成功 = 'positive', |
|||
错误 = 'negative', |
|||
警告 = 'warning', |
|||
信息 = 'info', |
|||
灰色消息 = 'ongoing', |
|||
} |
|||
/** |
|||
* 平台消息提示 |
|||
* @param message 提示消息 |
|||
* @param type PlatformNotifyTypeEnum 枚举提供值,默认 PlatformNotifyTypeEnum.警告 |
|||
*/ |
|||
export function platformNotify($q: QVueGlobals, message: string, type?: PlatformNotifyTypeEnum) { |
|||
$q.notify({ |
|||
message: message, |
|||
position: 'top', |
|||
type: type ?? PlatformNotifyTypeEnum.警告, |
|||
actions: [{ label: '知道了', handler: () => {} }], |
|||
timeout: 3000, |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 判断是否为空(一般用于Form元素) |
|||
* @param obj 需要判断的对象 |
|||
* @returns |
|||
*/ |
|||
export function isEmpty(obj) { |
|||
if (typeof obj === 'undefined' || obj === null || obj === '') { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
} |
@ -0,0 +1,332 @@ |
|||
import { Tools } from '@/platform/utils'; |
|||
/** |
|||
* 抽取窗口组件属性 |
|||
* @param {Object} props 属性对象 |
|||
* @returns 窗口组件属性 |
|||
*/ |
|||
export function extractDialogProps(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.persistent = props.persistent; // 设置后,用户在对话框外单击或按 ESC 键时不再关闭对话框;此外,应用程序路由更改也不会关闭它
|
|||
result.noEscDismiss = props.noEscDismiss; // 用户不能按 ESC 键关闭对话框;如果还设置了 'persistent' 属性,则无需设置它
|
|||
result.noBackdropDismiss = props.noBackdropDismiss; // 用户不能通过单击对话框外部来关闭对话框;如果还设置了 'persistent' 属性,则无需设置它
|
|||
result.noRouteDismiss = props.noRouteDismiss; // 更改路由应用程序不会关闭对话框;如果还设置了 'persistent' 属性,则无需设置它
|
|||
result.autoClose = props.autoClose; // 对话框内的任何单击/点击都将关闭它
|
|||
result.noShake = props.noShake; // 不要晃动对话框来引起用户的注意。
|
|||
result.allowFocusOutside = props.allowFocusOutside; // 允许对话框外的元素可聚焦;出于辅助功能的原因,默认情况下 QDialog 不允许外部聚焦.
|
|||
result.seamless = props.seamless; // 使对话框进入无缝模式;不使用背景,因此用户也可以与页面的其他部分进行交互
|
|||
result.position = props.position; // 将对话框附着到一侧(默认:standard、top、right、bottom、left)
|
|||
result.square = props.square; // 强制内容具有方形边框
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 抽取form表单组件属性 |
|||
* @param {Object} props 属性对象 |
|||
* @returns 表单组件属性 |
|||
*/ |
|||
export function extractFormProps(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.autofocus = props.autofocus; // 在初始组件渲染时将第一个可聚焦元素聚焦
|
|||
result.greedy = props.greedy; // 验证表单中的所有字段(默认情况下,它在通过同步的验证找到第一个无效字段后停止)
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 抽取表单项组件属性 |
|||
* @param {String} type 组件类型 |
|||
* @param {Object} props 属性对象 |
|||
* @returns 表单项组件属性 |
|||
*/ |
|||
export function extractFormItemComponentProps(type: string, props: any) { |
|||
if ('dateRange' === type) { |
|||
return dateRange(props); |
|||
} else if ('date' === type) { |
|||
return date(props); |
|||
} else if ('select' === type) { |
|||
return select(props); |
|||
} else if ('checkbox' === type) { |
|||
return checkbox(props); |
|||
} else if ('optionGroup' === type) { |
|||
return optionGroup(props); |
|||
} else { |
|||
return input(props); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* input组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function input(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
|
|||
result.hideBottomSpace = props.hideBottomSpace ?? true; |
|||
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
|
|||
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
|
|||
result.prefix = props.prefix; // 前缀
|
|||
result.suffix = props.suffix; // 后缀
|
|||
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
|
|||
result.counter = props.counter; // 在右下角显示自动计数器(字符数)
|
|||
result.autogrow = props.autogrow; // 使字段及其内容自动增长(内容过长时组件变高,内容换行)
|
|||
result.maxlength = props.maxlength; // 指定模型的最大长度
|
|||
result.disable = props.disable; // 将组件置于禁用模式
|
|||
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
|
|||
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
|
|||
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
|
|||
result.filled = props.filled; // 对字段使用“填充”设计
|
|||
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
|
|||
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
|
|||
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
|
|||
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
|
|||
result.type = props.type; // 组件类型
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 日期范围组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function dateRange(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
|
|||
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
|
|||
result.hideBottomSpace = props.hideBottomSpace ?? true; |
|||
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
|
|||
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
|
|||
result.disable = props.disable; // 将组件置于禁用模式
|
|||
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
|
|||
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
|
|||
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
|
|||
result.filled = props.filled; // 对字段使用“填充”设计
|
|||
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
|
|||
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
|
|||
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
|
|||
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 日期组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function date(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
|
|||
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
|
|||
result.hideBottomSpace = props.hideBottomSpace ?? true; |
|||
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
|
|||
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
|
|||
result.disable = props.disable; // 将组件置于禁用模式
|
|||
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
|
|||
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
|
|||
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
|
|||
result.filled = props.filled; // 对字段使用“填充”设计
|
|||
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
|
|||
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
|
|||
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
|
|||
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 下拉框组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function select(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.hint = props.hint; // 辅助(提示)文本,放在组件下面
|
|||
result.hideHint = props.hideHint ?? true; // 当字段没有焦点时隐藏辅助(提示)文本
|
|||
result.hideBottomSpace = props.hideBottomSpace ?? true; |
|||
result.stackLabel = props.stackLabel; // 标签将始终显示在字段上方,而不考虑字段内容(如果有)
|
|||
result.prefix = props.prefix; // 前缀
|
|||
result.suffix = props.suffix; // 后缀
|
|||
result.clearable = props.clearable; // 设置值(非 undefined 或 null )时附加可清除图标;单击时,模型将变为空
|
|||
result.counter = props.counter; // 在右下角显示自动计数器(字符数)
|
|||
result.useInput = props.useInput; // 使用一个输入标签,用户可以在其中输入
|
|||
result.autogrow = props.autogrow; // 使字段及其内容自动增长(内容过长时组件变高,内容换行)
|
|||
result.disable = props.disable; // 将组件置于禁用模式
|
|||
result.labelColor = props.labelColor; // 组件 label 的文字颜色,来自 Quasar 调色板的颜色名称
|
|||
result.color = props.color; // 组件颜色,来自 Quasar 调色板的颜色名称
|
|||
result.bgColor = props.bgColor; // 组件背景颜色,来自 Quasar 调色板的颜色名称
|
|||
result.filled = props.filled; // 对字段使用“填充”设计
|
|||
result.outlined = props.outlined ?? true; // 对字段使用“轮廓线”设计
|
|||
result.borderless = props.borderless; // 对字段采用“无边界”设计,与 outlined 冲突
|
|||
result.rounded = props.rounded; // 为组件应用较小标准的边框圆角,也就是边框为椭圆
|
|||
result.dense = props.dense ?? true; // 紧凑模式,占用更少的空间
|
|||
result.multiple = props.multiple; // 支持多选
|
|||
result.options = props.options; // 下拉选项集合
|
|||
result.maxValues = props.maxValues; // 允许用户可以进行的最大选择数
|
|||
result.useChips = props.useChips; // 使用QChip显示当前选择的内容
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 复选框组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function checkbox(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.keepColor = props.keepColor; // 当组件未勾选/关闭时,是否应保留颜色?
|
|||
result.checkedIcon = props.checkedIcon; // 此图标将会在 model 值为 true 时被使用(代替默认的设计)
|
|||
result.uncheckedIcon = props.uncheckedIcon; // 此图标将会在 model 值为 false 时被使用(代替默认的设计)
|
|||
result.toggleIndeterminate = props.toggleIndeterminate ?? false; // 当用户点击组件时,除 true 和 false 外,是否还添加一个不确定(indeterminate)的状态?
|
|||
result.leftLabel = props.leftLabel; // 如有标签,应显示在组件的左侧
|
|||
result.trueValue = props.trueValue; // model 为何值时被视为选中/勾选/启用?
|
|||
result.falseValue = props.falseValue; // model 为何值时被视为未选中/未勾选/关闭?
|
|||
result.disable = props.disable; // 将组件置于禁用模式
|
|||
result.size = props.size; // 带有 CSS 单位的尺寸大小,包括单位的名称或标准大小名称(xs | sm | md | lg | xl)
|
|||
result.color = props.color; // 组件的颜色,来自 Quasar 调色板的颜色名称
|
|||
result.dense = props.dense; // 紧凑模式,占用更少的空间
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 选项组组件 |
|||
* @param props |
|||
* @returns |
|||
*/ |
|||
function optionGroup(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.name = props.name; // 用于指定控件的名称;如果处理直接提交到 URL 的表单时很有用
|
|||
result.keepColor = props.keepColor; // 当组件未勾选/关闭时,是否应保留颜色?
|
|||
result.type = props.optionGroupType; // 要使用的输入组件类型,默认radio,可选:radio、checkbox、toggle
|
|||
result.leftLabel = props.leftLabel; // 如有标签,应显示在组件的左侧
|
|||
result.inline = props.inline ?? true; // 将输入组件显示为内联块,而不是每个组件都有自己的行
|
|||
result.options = props.options; //具有值、标签和禁用(可选)属性的对象数组,包含的属性:label、value、disable等
|
|||
result.disable = props.disable; // 将组件置于禁用模式下
|
|||
result.size = props.size; // 带有 CSS 单位的尺寸大小,包括单位的名称或标准大小名称(xs | sm | md | lg | xl)
|
|||
result.color = props.color; // 组件的颜色,来自 Quasar 调色板的颜色名称
|
|||
result.dense = props.dense; // 紧凑模式,占用更少的空间
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
/** |
|||
* 抽取表格组件属性 |
|||
* @param {Object} props 属性对象 |
|||
* @returns 表格组件属性 |
|||
*/ |
|||
export function extractTableProps(props: any) { |
|||
if (props) { |
|||
const result: any = {}; |
|||
result.color = props.color; // 组件的颜色,来自 Quasar 调色板的颜色名称
|
|||
result.dense = props.dense; // 密恐模式;
|
|||
result.dark = props.dark; // 设置组件背景为深色
|
|||
result.flat = props.flat; // 应用“平面”设计(无默认阴影)
|
|||
result.bordered = props.bordered; // 将默认边框应用于组件
|
|||
result.square = props.square; // 删除边框圆角(border-radius),使边框为正方形
|
|||
return Tools.pickNotNil(result); |
|||
} |
|||
return {}; |
|||
} |
|||
|
|||
function columnStyle(item: any) { |
|||
let style = ''; |
|||
if (Object.hasOwnProperty.call(item, 'style')) { |
|||
style = item.style; |
|||
} |
|||
if (Object.hasOwnProperty.call(item, 'width')) { |
|||
item.style = `min-width: ` + item.width + `px; max-width: ` + item.width + `px;` + style; |
|||
delete item.width; |
|||
|
|||
if (Object.hasOwnProperty.call(item, 'classes')) { |
|||
item.classes = item.classes + ' truncate'; |
|||
} else { |
|||
item.classes = 'truncate'; |
|||
} |
|||
} |
|||
} |
|||
function columnChildrenHandler(item: any, gridColumns: any) { |
|||
if (item.childrenColumns && item.childrenColumns.length > 0) { |
|||
item.childrenColumns.forEach((column) => { |
|||
columnChildrenHandler(column, gridColumns); |
|||
}); |
|||
} else { |
|||
columnStyle(item); |
|||
gridColumns.push({ |
|||
...{ align: 'left', label: item.name, field: item.name, sortable: true }, |
|||
...item, |
|||
}); |
|||
} |
|||
} |
|||
/** |
|||
* 处理表格列属性 |
|||
*/ |
|||
export function extractTableColumnsProps(props: any) { |
|||
const gridColumns = <any>[]; |
|||
if (props.tableColumns && props.tableColumns.length > 0) { |
|||
if (props.tableShowSortNo) { |
|||
gridColumns.push({ name: '_sortNo_', align: 'center', label: '序号', field: '_sortNo_' }); |
|||
} |
|||
props.tableColumns.forEach((item: any) => { |
|||
columnChildrenHandler(item, gridColumns); |
|||
}); |
|||
return gridColumns; |
|||
} |
|||
return []; |
|||
} |
|||
|
|||
const formColsScreenMap = new Map(); |
|||
formColsScreenMap.set(1, { xs: 1, sm: 1, md: 2, lg: 3, xl: 4 }); |
|||
formColsScreenMap.set(2, { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }); |
|||
formColsScreenMap.set(3, { xs: 1, sm: 2, md: 3, lg: 4, xl: 6 }); |
|||
formColsScreenMap.set(4, { xs: 1, sm: 2, md: 4, lg: 4, xl: 6 }); |
|||
formColsScreenMap.set(5, { xs: 1, sm: 2, md: 5, lg: 6, xl: 6 }); |
|||
formColsScreenMap.set(6, { xs: 1, sm: 3, md: 6, lg: 6, xl: 6 }); |
|||
formColsScreenMap.set(7, { xs: 1, sm: 4, md: 7, lg: 7, xl: 7 }); |
|||
formColsScreenMap.set(8, { xs: 1, sm: 4, md: 8, lg: 8, xl: 8 }); |
|||
formColsScreenMap.set(9, { xs: 1, sm: 4, md: 9, lg: 9, xl: 9 }); |
|||
formColsScreenMap.set(10, { xs: 1, sm: 4, md: 10, lg: 10, xl: 10 }); |
|||
formColsScreenMap.set(11, { xs: 1, sm: 4, md: 11, lg: 11, xl: 11 }); |
|||
formColsScreenMap.set(12, { xs: 1, sm: 4, md: 12, lg: 12, xl: 12 }); |
|||
/** |
|||
* 根据设置的每列显示数、屏幕断点获取当前查询表单每行显示多少个字段 |
|||
* @param configColsNumber |
|||
* @param screen |
|||
*/ |
|||
export function getQueryFormColsNumberByScreen(configColsNumber: number, screen: any) { |
|||
return formColsScreenMap.get(configColsNumber)[screen]; |
|||
} |
|||
|
|||
/** |
|||
* 集合根据传入的key转map |
|||
* @param key |
|||
* @param array |
|||
*/ |
|||
export function arrayToMap(key, array) { |
|||
const map = new Map(); |
|||
array.forEach((item) => { |
|||
if (item.name !== '_sortNo_') { |
|||
map.set(item[key], item); |
|||
} |
|||
}); |
|||
return map; |
|||
} |
@ -0,0 +1,19 @@ |
|||
export { PlatformIconEnum } from './commUtil'; |
|||
export { PageStatusEnum } from './commUtil'; |
|||
export { FormTypeEnum } from './commUtil'; |
|||
export { DataTypeEnum } from './commUtil'; |
|||
export { OptionComeFromEnum } from './commUtil'; |
|||
export { FormComponentValidateEnum } from './commUtil'; |
|||
export { OperatorTypeEnum } from './commUtil'; |
|||
export type { CriteriaType } from './commUtil'; |
|||
export { PlatformNotifyTypeEnum } from './commUtil'; |
|||
export { platformNotify } from './commUtil'; |
|||
export { isEmpty } from './commUtil'; |
|||
|
|||
export { extractDialogProps } from './componentComm'; |
|||
export { extractFormProps } from './componentComm'; |
|||
export { extractFormItemComponentProps } from './componentComm'; |
|||
export { extractTableProps } from './componentComm'; |
|||
export { extractTableColumnsProps } from './componentComm'; |
|||
export { getQueryFormColsNumberByScreen } from './componentComm'; |
|||
export { arrayToMap } from './componentComm'; |
@ -0,0 +1,48 @@ |
|||
/** |
|||
* 平台icon,使用【material icons】,以下为列举的一些平台常用的图标,并不包含全部 |
|||
* 不在该枚举中时可使用自定义的图标,目的是以后方便全局替换。 |
|||
*/ |
|||
export enum IconEnum { |
|||
查询 = 'search', |
|||
更多查询 = 'zoom_in', |
|||
重置 = 'restart_alt', |
|||
刷新 = 'loop', |
|||
新增 = 'add', |
|||
新增2 = 'add_box', |
|||
新增3 = 'playlist_add_circle', |
|||
编辑 = 'edit', |
|||
删除 = 'delete', |
|||
查看 = 'visibility', |
|||
全屏 = 'fullscreen', |
|||
退出全屏 = 'fullscreen_exit', |
|||
关闭 = 'close', |
|||
保存 = 'save', |
|||
提交 = 'beenhere', |
|||
字母 = 'abc', |
|||
时钟 = 'access_time', |
|||
上箭头 = 'arrow_upward', |
|||
下箭头 = 'arrow_downward', |
|||
左箭头 = 'arrow_back', |
|||
右箭头 = 'arrow_forward', |
|||
附件 = 'attach_file', |
|||
否状态 = 'cancel', |
|||
是状态 = 'check_circle', |
|||
首页 = 'home', |
|||
设置 = 'settings', |
|||
设置2 = 'settings_applications', |
|||
扳手 = 'build_circle', |
|||
收起 = 'arrow_drop_up', |
|||
展开 = 'arrow_drop_down', |
|||
提示 = 'info', |
|||
警告 = 'warning', |
|||
日期 = 'event', |
|||
日期范围 = 'date_range', |
|||
文件夹 = 'folder', |
|||
校验 = 'published_with_changes', |
|||
下载 = 'download', |
|||
上传 = 'upload', |
|||
选取变量 = 'find_in_page', |
|||
报表通用 = 'assessment', |
|||
复制 = 'file_copy', |
|||
发送 = 'send', |
|||
} |
@ -0,0 +1 @@ |
|||
export { IconEnum } from './IconEnum'; |
@ -1,7 +1,7 @@ |
|||
import login from './api/login.json'; |
|||
import session from './api/system/user/session.json'; |
|||
import appConfigure from './api/system/user/appConfigure.json'; |
|||
import activeConfigure from './api/lcdp/configure/getActiveConfigure.json'; |
|||
|
|||
const PLATFORM_MOCKS = [login, session, appConfigure]; |
|||
const PLATFORM_MOCKS = [login, session, activeConfigure]; |
|||
|
|||
export default PLATFORM_MOCKS; |
|||
|
@ -1,9 +1,39 @@ |
|||
<template> |
|||
<div>{{ message }}</div> |
|||
<w-dialog |
|||
ref="dialogRef" |
|||
:persistent="true" |
|||
:maximized="false" |
|||
title="xxx" |
|||
width="50%" |
|||
height="50%" |
|||
:can-maximize="false" |
|||
:buttons="[ |
|||
{ |
|||
icon: IconEnum.保存, |
|||
label: '保存', |
|||
loading: false, |
|||
click: async () => {}, |
|||
}, |
|||
]" |
|||
@maximized="dialogMaximize" |
|||
></w-dialog> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { Environment, axios } from '@/platform'; |
|||
// import { Environment, axios } from '@/platform'; |
|||
|
|||
const response = await axios.get(Environment.apiContextPath('/api/sample/action1')); |
|||
const message = response.data.message; |
|||
// const response = await axios.get(Environment.apiContextPath('/api/sample/action1')); |
|||
// const message = response.data.message; |
|||
|
|||
import { ref, reactive, onMounted } from 'vue'; |
|||
import { IconEnum } from '@/platform'; |
|||
|
|||
const dialogRef = ref(); |
|||
|
|||
const dialogMaximize = (maximizedToggle: boolean) => { |
|||
console.log(maximizedToggle); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
dialogRef.value.show(); |
|||
}); |
|||
</script> |
|||
|
@ -1,10 +1,7 @@ |
|||
<template> |
|||
<DndProvider :backend="HTML5Backend"> |
|||
<w-platform-page></w-platform-page> |
|||
</DndProvider> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { DndProvider } from 'vue3-dnd'; |
|||
import { HTML5Backend } from 'react-dnd-html5-backend'; |
|||
|
|||
</script> |
|||
|
@ -1,9 +1,39 @@ |
|||
<template> |
|||
<div>{{ message }}</div> |
|||
<w-dialog |
|||
ref="dialogRef" |
|||
:persistent="true" |
|||
:maximized="false" |
|||
title="xxx" |
|||
width="50%" |
|||
height="50%" |
|||
:can-maximize="false" |
|||
:buttons="[ |
|||
{ |
|||
icon: IconEnum.保存, |
|||
label: '保存', |
|||
loading: false, |
|||
click: async () => {}, |
|||
}, |
|||
]" |
|||
@maximized="dialogMaximize" |
|||
></w-dialog> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { Environment, axios } from 'platform-core'; |
|||
// import { Environment, axios } from 'platform-core'; |
|||
|
|||
const response = await axios.get(Environment.apiContextPath('/api/sample/action1')); |
|||
const message = response.data.message; |
|||
// const response = await axios.get(Environment.apiContextPath('/api/sample/action1')); |
|||
// const message = response.data.message; |
|||
|
|||
import { ref, reactive, onMounted } from 'vue'; |
|||
import { IconEnum } from 'platform-core'; |
|||
|
|||
const dialogRef = ref(); |
|||
|
|||
const dialogMaximize = (maximizedToggle: boolean) => { |
|||
console.log(maximizedToggle); |
|||
}; |
|||
|
|||
onMounted(() => { |
|||
dialogRef.value.show(); |
|||
}); |
|||
</script> |
|||
|
@ -1,10 +1,5 @@ |
|||
<template> |
|||
<DndProvider :backend="HTML5Backend"> |
|||
<w-platform-page></w-platform-page> |
|||
</DndProvider> |
|||
<w-platform-page></w-platform-page> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { DndProvider } from 'vue3-dnd'; |
|||
import { HTML5Backend } from 'react-dnd-html5-backend'; |
|||
</script> |
|||
<script setup lang="ts"></script> |
|||
|
@ -1,10 +1,5 @@ |
|||
<template> |
|||
<DndProvider :backend="HTML5Backend"> |
|||
<w-platform-page></w-platform-page> |
|||
</DndProvider> |
|||
<w-platform-page></w-platform-page> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { DndProvider } from 'vue3-dnd'; |
|||
import { HTML5Backend } from 'react-dnd-html5-backend'; |
|||
</script> |
|||
<script setup lang="ts"></script> |
|||
|
@ -0,0 +1,11 @@ |
|||
[ |
|||
{ |
|||
"module" : "io.sc.platform.security", |
|||
"order" : 153, |
|||
"description" : "", |
|||
"properties": [ |
|||
"# - io.sc.platform.security", |
|||
"application.default-password = password" |
|||
] |
|||
} |
|||
] |
Loading…
Reference in new issue