提交 17e54a2d authored 作者: 刘守彩's avatar 刘守彩

feat: update pkg

上级 2c7d1917
......@@ -22,7 +22,8 @@
## 启动发布
node 版本在`16`,其他版本可能启动不成功
- node 版本在`16`,其他版本可能启动不成功
- 项目已经注入[`scss变量`](http://120.55.57.35:4874/#/ty-ui/component/theme),可以在组件直接使用
```bash
# 安装包,已配置好镜像源,不需要在命令中指定registry
......
......@@ -38,21 +38,17 @@
"axios": "0.27.2",
"clipboard": "2.0.11",
"core-js": "3.28.0",
"dayjs": "1.11.10",
"echarts": "5.5.0",
"element-ui": "2.15.14",
"file-saver": "2.0.5",
"fuse.js": "6.4.3",
"highlight.js": "9.18.5",
"js-beautify": "1.15.1",
"js-cookie": "3.0.5",
"jsencrypt": "3.3.2",
"lodash-es": "4.17.21",
"nprogress": "0.2.0",
"screenfull": "5.0.2",
"sortablejs": "1.10.2",
"tailwindcss": "1.9.6",
"tinymce": "6.8.3",
"vue": "2.7.16",
"vue-count-to": "1.0.13",
"vue-cropper": "0.6.4",
"vue-echarts": "6.6.9",
"vue-meta": "2.4.0",
......
<template>
<div id="app">
<router-view />
<theme-picker />
</div>
</template>
<script>
import ThemePicker from '@/components/ThemePicker';
export default {
name: 'App',
components: { ThemePicker },
metaInfo() {
return {
title:
......
svg,
img {
display: inline;
}
img {
max-width: initial;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
input[type='number'] {
-moz-appearance: textfield;
}
button:focus {
outline: none;
}
html {
height: 100%;
box-sizing: border-box;
}
body {
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
Microsoft YaHei, Arial, sans-serif;
}
label {
font-weight: 700;
}
#app {
height: 100%;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
.no-padding {
padding: 0px !important;
}
.padding-content {
padding: 4px 0;
}
div:focus {
outline: none;
}
.fr {
float: right;
}
.fl {
float: left;
}
.pr-5 {
padding-right: 5px;
}
.pl-5 {
padding-left: 5px;
}
.block {
display: block;
}
.pointer {
cursor: pointer;
}
.inlineBlock {
display: block;
}
.clearfix {
&:after {
visibility: hidden;
display: block;
font-size: 0;
content: ' ';
clear: both;
height: 0;
}
}
aside {
background: #eef1f6;
padding: 8px 24px;
margin-bottom: 20px;
border-radius: 2px;
display: block;
line-height: 32px;
font-size: 16px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
color: #2c3e50;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
a {
color: #337ab7;
cursor: pointer;
&:hover {
color: rgb(32, 160, 255);
}
}
}
// main-container全局样式
.app-container {
padding: 15px;
&.is-gray-bg {
background-color: #e5e5e5;
}
.app-container-inner {
padding: 20px;
height: calc(100vh - 80px);
display: flex;
flex-direction: column;
}
// 设置页面唯一表格弹性高度
.app-page-table {
margin-top: 10px;
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
}
.link-type,
.link-type:focus {
color: #337ab7;
cursor: pointer;
&:hover {
color: rgb(32, 160, 255);
}
}
.top-right-btn {
position: relative;
float: right;
}
// cover some element-ui styles
.el-breadcrumb__inner,
.el-breadcrumb__inner a {
font-weight: 400 !important;
}
.el-upload {
input[type='file'] {
display: none !important;
}
}
.el-upload__input {
display: none;
}
.cell {
.el-tag {
margin-right: 0px;
}
}
.small-padding {
.cell {
padding-left: 5px;
padding-right: 5px;
}
}
.fixed-width {
.el-button--mini {
padding: 7px 10px;
width: 60px;
}
}
.status-col {
.cell {
padding: 0 10px;
text-align: center;
.el-tag {
margin-right: 0px;
}
}
}
// to fixed https://github.com/ElemeFE/element/issues/2461
.el-dialog {
transform: none;
left: 0;
position: relative;
margin: 0 auto;
}
// refine element ui upload
.upload-container {
.el-upload {
width: 100%;
.el-upload-dragger {
width: 100%;
height: 200px;
}
}
}
// dropdown
.el-dropdown-menu {
a {
display: block;
}
}
// fix date-picker ui bug in filter-item
.el-range-editor.el-input__inner {
display: inline-flex !important;
}
// to fix el-date-picker css style
.el-range-separator {
box-sizing: content-box;
}
.el-menu--collapse
> div
> .el-submenu
> .el-submenu__title
.el-submenu__icon-arrow {
display: none;
}
@import './variables.scss';
@import './mixin.scss';
@import '~@taiyuan/ty-ui/packages/styles/var.scss';
/* 设置tailwindcss */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* 引入原有若依css,暂时不做变动 */
@import './element-ui.scss';
@import './transition.scss';
@import './sidebar.scss';
@import './base.scss';
svg,
img {
display: inline;
}
img {
max-width: initial;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
input[type='number'] {
-moz-appearance: textfield;
}
button:focus {
outline: none;
}
html {
height: 100%;
box-sizing: border-box;
}
body {
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
Microsoft YaHei, Arial, sans-serif;
}
label {
font-weight: 700;
}
#app {
height: 100%;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
.no-padding {
padding: 0px !important;
}
.padding-content {
padding: 4px 0;
}
div:focus {
outline: none;
}
.fr {
float: right;
}
.fl {
float: left;
}
.pr-5 {
padding-right: 5px;
}
.pl-5 {
padding-left: 5px;
}
.block {
display: block;
}
.pointer {
cursor: pointer;
}
.inlineBlock {
display: block;
}
.clearfix {
&:after {
visibility: hidden;
display: block;
font-size: 0;
content: ' ';
clear: both;
height: 0;
}
}
aside {
background: #eef1f6;
padding: 8px 24px;
margin-bottom: 20px;
border-radius: 2px;
display: block;
line-height: 32px;
font-size: 16px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
color: #2c3e50;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
a {
color: #337ab7;
cursor: pointer;
&:hover {
color: rgb(32, 160, 255);
}
}
}
//main-container全局样式
.app-container {
padding: 20px;
}
.link-type,
.link-type:focus {
color: #337ab7;
cursor: pointer;
&:hover {
color: rgb(32, 160, 255);
}
}
.top-right-btn {
position: relative;
float: right;
}
/* 全局样式css,以g-开头命名 */
@import './global.scss';
<template>
<div :class="{ show: show }" class="header-search">
<svg-icon
class-name="search-icon"
icon-class="search"
@click.stop="click"
/>
<el-select
ref="headerSearchSelect"
v-model="search"
:remote-method="querySearch"
filterable
default-first-option
remote
placeholder="Search"
class="header-search-select"
@change="change"
>
<el-option
v-for="option in options"
:key="option.item.path"
:value="option.item"
:label="option.item.title.join(' > ')"
/>
</el-select>
</div>
</template>
<script>
// fuse is a lightweight fuzzy-search module
// make search results more in line with expectations
import Fuse from 'fuse.js/dist/fuse.min.js';
import path from 'path';
export default {
name: 'HeaderSearch',
data() {
return {
search: '',
options: [],
searchPool: [],
show: false,
fuse: undefined
};
},
computed: {
routes() {
return this.$store.getters.permission_routes;
}
},
watch: {
routes() {
this.searchPool = this.generateRoutes(this.routes);
},
searchPool(list) {
this.initFuse(list);
},
show(value) {
if (value) {
document.body.addEventListener('click', this.close);
} else {
document.body.removeEventListener('click', this.close);
}
}
},
mounted() {
this.searchPool = this.generateRoutes(this.routes);
},
methods: {
click() {
this.show = !this.show;
if (this.show) {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus();
}
},
close() {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur();
this.options = [];
this.show = false;
},
change(val) {
const path = val.path;
const query = val.query;
if (this.ishttp(val.path)) {
// http(s):// 路径新窗口打开
const pindex = path.indexOf('http');
window.open(path.substr(pindex, path.length), '_blank');
} else {
if (query) {
this.$router.push({ path: path, query: JSON.parse(query) });
} else {
this.$router.push(path);
}
}
this.search = '';
this.options = [];
this.$nextTick(() => {
this.show = false;
});
},
initFuse(list) {
this.fuse = new Fuse(list, {
shouldSort: true,
threshold: 0.4,
location: 0,
distance: 100,
minMatchCharLength: 1,
keys: [
{
name: 'title',
weight: 0.7
},
{
name: 'path',
weight: 0.3
}
]
});
},
// Filter out the routes that can be displayed in the sidebar
// And generate the internationalized title
generateRoutes(routes, basePath = '/', prefixTitle = []) {
let res = [];
for (const router of routes) {
// skip hidden router
if (router.hidden) {
continue;
}
const data = {
path: !this.ishttp(router.path)
? path.resolve(basePath, router.path)
: router.path,
title: [...prefixTitle]
};
if (router.meta && router.meta.title) {
data.title = [...data.title, router.meta.title];
if (router.redirect !== 'noRedirect') {
// only push the routes with title
// special case: need to exclude parent router without redirect
res.push(data);
}
}
if (router.query) {
data.query = router.query;
}
// recursive child routes
if (router.children) {
const tempRoutes = this.generateRoutes(
router.children,
data.path,
data.title
);
if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes];
}
}
}
return res;
},
querySearch(query) {
if (query !== '') {
this.options = this.fuse.search(query);
} else {
this.options = [];
}
},
ishttp(url) {
return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1;
}
}
};
</script>
<style lang="scss" scoped>
.header-search {
font-size: 0 !important;
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
.header-search-select {
font-size: 18px;
transition: width 0.2s;
width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
display: inline-block;
vertical-align: middle;
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none !important;
border-bottom: 1px solid #d9d9d9;
vertical-align: middle;
}
}
&.show {
.header-search-select {
width: 210px;
margin-left: 10px;
}
}
}
</style>
<template>
<div>
<svg-icon icon-class="question" @click="goto" />
</div>
</template>
<script>
export default {
name: 'RuoYiDoc',
data() {
return {
url: 'http://doc.ruoyi.vip/ruoyi-vue'
};
},
methods: {
goto() {
window.open(this.url);
}
}
};
</script>
<template>
<div>
<svg-icon icon-class="github" @click="goto" />
</div>
</template>
<script>
export default {
name: 'RuoYiGit',
data() {
return {
url: 'https://gitee.com/y_project/RuoYi-Vue'
};
},
methods: {
goto() {
window.open(this.url);
}
}
};
</script>
<template>
<div>
<svg-icon
:icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'"
@click="click"
/>
</div>
</template>
<script>
import screenfull from 'screenfull';
export default {
name: 'Screenfull',
data() {
return {
isFullscreen: false
};
},
mounted() {
this.init();
},
beforeDestroy() {
this.destroy();
},
methods: {
click() {
if (!screenfull.isEnabled) {
this.$message({ message: '你的浏览器不支持全屏', type: 'warning' });
return false;
}
screenfull.toggle();
},
change() {
this.isFullscreen = screenfull.isFullscreen;
},
init() {
if (screenfull.isEnabled) {
screenfull.on('change', this.change);
}
},
destroy() {
if (screenfull.isEnabled) {
screenfull.off('change', this.change);
}
}
}
};
</script>
<style scoped>
.screenfull-svg {
display: inline-block;
cursor: pointer;
fill: #5a5e66;
width: 20px;
height: 20px;
vertical-align: 10px;
}
</style>
<template>
<el-dropdown trigger="click" @command="handleSetSize">
<div>
<svg-icon class-name="size-icon" icon-class="size" />
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="item of sizeOptions"
:key="item.value"
:disabled="size === item.value"
:command="item.value"
>
{{ item.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script>
export default {
data() {
return {
sizeOptions: [
{ label: 'Default', value: 'default' },
{ label: 'Medium', value: 'medium' },
{ label: 'Small', value: 'small' },
{ label: 'Mini', value: 'mini' }
]
};
},
computed: {
size() {
return this.$store.getters.size;
}
},
methods: {
handleSetSize(size) {
this.$ELEMENT.size = size;
this.$store.dispatch('app/setSize', size);
this.refreshView();
this.$message({
message: 'Switch Size Success',
type: 'success'
});
},
refreshView() {
// In order to make the cached page re-rendered
this.$store.dispatch('tagsView/delAllCachedViews', this.$route);
const { fullPath } = this.$route;
this.$nextTick(() => {
this.$router.replace({
path: '/redirect' + fullPath
});
});
}
}
};
</script>
<template>
<el-color-picker
v-model="theme"
:predefine="[
'#409EFF',
'#1890ff',
'#304156',
'#212121',
'#11a983',
'#13c2c2',
'#6959CD',
'#f5222d'
]"
class="theme-picker"
popper-class="theme-picker-dropdown"
/>
</template>
<script>
const version = require('element-ui/package.json').version; // element-ui version from node_modules
const ORIGINAL_THEME = '#409EFF'; // default color
export default {
data() {
return {
chalk: '', // content of theme-chalk css
theme: ''
};
},
computed: {
defaultTheme() {
return this.$store.state.settings.theme;
}
},
watch: {
defaultTheme: {
handler: function (val, oldVal) {
this.theme = val;
},
immediate: true
},
async theme(val) {
await this.setTheme(val);
}
},
created() {
if (this.defaultTheme !== ORIGINAL_THEME) {
this.setTheme(this.defaultTheme);
}
},
methods: {
async setTheme(val) {
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME;
if (typeof val !== 'string') return;
const themeCluster = this.getThemeCluster(val.replace('#', ''));
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''));
const getHandler = (variable, id) => {
return () => {
const originalCluster = this.getThemeCluster(
ORIGINAL_THEME.replace('#', '')
);
const newStyle = this.updateStyle(
this[variable],
originalCluster,
themeCluster
);
let styleTag = document.getElementById(id);
if (!styleTag) {
styleTag = document.createElement('style');
styleTag.setAttribute('id', id);
document.head.appendChild(styleTag);
}
styleTag.innerText = newStyle;
};
};
if (!this.chalk) {
console.log(version);
// const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`;
// await this.getCSSString(url, 'chalk');
}
const chalkHandler = getHandler('chalk', 'chalk-style');
chalkHandler();
const styles = [].slice
.call(document.querySelectorAll('style'))
.filter((style) => {
const text = style.innerText;
return (
new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
);
});
styles.forEach((style) => {
const { innerText } = style;
if (typeof innerText !== 'string') return;
style.innerText = this.updateStyle(
innerText,
originalCluster,
themeCluster
);
});
this.$emit('change', val);
},
updateStyle(style, oldCluster, newCluster) {
let newStyle = style;
oldCluster.forEach((color, index) => {
newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index]);
});
return newStyle;
},
getCSSString(url, variable) {
return new Promise((resolve) => {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '');
resolve();
}
};
xhr.open('GET', url);
xhr.send();
});
},
getThemeCluster(theme) {
const tintColor = (color, tint) => {
let red = parseInt(color.slice(0, 2), 16);
let green = parseInt(color.slice(2, 4), 16);
let blue = parseInt(color.slice(4, 6), 16);
if (tint === 0) {
// when primary color is in its rgb space
return [red, green, blue].join(',');
} else {
red += Math.round(tint * (255 - red));
green += Math.round(tint * (255 - green));
blue += Math.round(tint * (255 - blue));
red = red.toString(16);
green = green.toString(16);
blue = blue.toString(16);
return `#${red}${green}${blue}`;
}
};
const shadeColor = (color, shade) => {
let red = parseInt(color.slice(0, 2), 16);
let green = parseInt(color.slice(2, 4), 16);
let blue = parseInt(color.slice(4, 6), 16);
red = Math.round((1 - shade) * red);
green = Math.round((1 - shade) * green);
blue = Math.round((1 - shade) * blue);
red = red.toString(16);
green = green.toString(16);
blue = blue.toString(16);
return `#${red}${green}${blue}`;
};
const clusters = [theme];
for (let i = 0; i <= 9; i++) {
clusters.push(tintColor(theme, Number((i / 10).toFixed(2))));
}
clusters.push(shadeColor(theme, 0.1));
return clusters;
}
}
};
</script>
<style>
.theme-message,
.theme-picker-dropdown {
z-index: 99999 !important;
}
.theme-picker .el-color-picker__trigger {
height: 26px !important;
width: 26px !important;
padding: 2px;
}
.theme-picker-dropdown .el-color-dropdown__link-btn {
display: none;
}
</style>
......@@ -62,22 +62,12 @@ import { mapGetters } from 'vuex';
import Breadcrumb from '@/components/Breadcrumb';
import TopNav from '@/components/TopNav';
import Hamburger from '@/components/Hamburger';
// import Screenfull from '@/components/Screenfull';
// import SizeSelect from '@/components/SizeSelect';
// import Search from '@/components/HeaderSearch';
// import RuoYiGit from '@/components/RuoYi/Git';
// import RuoYiDoc from '@/components/RuoYi/Doc';
export default {
components: {
Breadcrumb,
TopNav,
Hamburger
// Screenfull,
// SizeSelect,
// Search
// RuoYiGit,
// RuoYiDoc
},
computed: {
...mapGetters(['sidebar', 'avatar', 'device']),
......
......@@ -132,10 +132,7 @@
</template>
<script>
import ThemePicker from '@/components/ThemePicker';
export default {
components: { ThemePicker },
data() {
return {
theme: this.$store.state.settings.theme,
......
......@@ -147,20 +147,6 @@ export const dynamicRoutes = [
meta: { title: '调度日志', activeMenu: '/monitor/job' }
}
]
},
{
path: '/tool/gen-edit',
component: Layout,
hidden: true,
permissions: ['tool:gen:edit'],
children: [
{
path: 'index/:tableId(\\d+)',
component: () => import('@/views/tool/gen/editTable'),
name: 'GenEdit',
meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
}
]
}
];
......
差异被折叠。
const styles = {
'el-rate': '.el-rate{display: inline-block; vertical-align: text-top;}',
'el-upload': '.el-upload__tip{line-height: 1.2;}'
};
function addCss(cssList, el) {
const css = styles[el.tag];
css && cssList.indexOf(css) === -1 && cssList.push(css);
if (el.children) {
el.children.forEach((el2) => addCss(cssList, el2));
}
}
export function makeUpCss(conf) {
const cssList = [];
conf.fields.forEach((el) => addCss(cssList, el));
return cssList.join('\n');
}
export default [
{
layout: 'colFormItem',
tagIcon: 'input',
label: '手机号',
vModel: 'mobile',
formId: 6,
tag: 'el-input',
placeholder: '请输入手机号',
defaultValue: '',
span: 24,
style: { width: '100%' },
clearable: true,
prepend: '',
append: '',
'prefix-icon': 'el-icon-mobile',
'suffix-icon': '',
maxlength: 11,
'show-word-limit': true,
readonly: false,
disabled: false,
required: true,
changeTag: true,
regList: [
{
pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
message: '手机号格式错误'
}
]
}
];
差异被折叠。
[
"platform-eleme",
"eleme",
"delete-solid",
"delete",
"s-tools",
"setting",
"user-solid",
"user",
"phone",
"phone-outline",
"more",
"more-outline",
"star-on",
"star-off",
"s-goods",
"goods",
"warning",
"warning-outline",
"question",
"info",
"remove",
"circle-plus",
"success",
"error",
"zoom-in",
"zoom-out",
"remove-outline",
"circle-plus-outline",
"circle-check",
"circle-close",
"s-help",
"help",
"minus",
"plus",
"check",
"close",
"picture",
"picture-outline",
"picture-outline-round",
"upload",
"upload2",
"download",
"camera-solid",
"camera",
"video-camera-solid",
"video-camera",
"message-solid",
"bell",
"s-cooperation",
"s-order",
"s-platform",
"s-fold",
"s-unfold",
"s-operation",
"s-promotion",
"s-home",
"s-release",
"s-ticket",
"s-management",
"s-open",
"s-shop",
"s-marketing",
"s-flag",
"s-comment",
"s-finance",
"s-claim",
"s-custom",
"s-opportunity",
"s-data",
"s-check",
"s-grid",
"menu",
"share",
"d-caret",
"caret-left",
"caret-right",
"caret-bottom",
"caret-top",
"bottom-left",
"bottom-right",
"back",
"right",
"bottom",
"top",
"top-left",
"top-right",
"arrow-left",
"arrow-right",
"arrow-down",
"arrow-up",
"d-arrow-left",
"d-arrow-right",
"video-pause",
"video-play",
"refresh",
"refresh-right",
"refresh-left",
"finished",
"sort",
"sort-up",
"sort-down",
"rank",
"loading",
"view",
"c-scale-to-original",
"date",
"edit",
"edit-outline",
"folder",
"folder-opened",
"folder-add",
"folder-remove",
"folder-delete",
"folder-checked",
"tickets",
"document-remove",
"document-delete",
"document-copy",
"document-checked",
"document",
"document-add",
"printer",
"paperclip",
"takeaway-box",
"search",
"monitor",
"attract",
"mobile",
"scissors",
"umbrella",
"headset",
"brush",
"mouse",
"coordinate",
"magic-stick",
"reading",
"data-line",
"data-board",
"pie-chart",
"data-analysis",
"collection-tag",
"film",
"suitcase",
"suitcase-1",
"receiving",
"collection",
"files",
"notebook-1",
"notebook-2",
"toilet-paper",
"office-building",
"school",
"table-lamp",
"house",
"no-smoking",
"smoking",
"shopping-cart-full",
"shopping-cart-1",
"shopping-cart-2",
"shopping-bag-1",
"shopping-bag-2",
"sold-out",
"sell",
"present",
"box",
"bank-card",
"money",
"coin",
"wallet",
"discount",
"price-tag",
"news",
"guide",
"male",
"female",
"thumb",
"cpu",
"link",
"connection",
"open",
"turn-off",
"set-up",
"chat-round",
"chat-line-round",
"chat-square",
"chat-dot-round",
"chat-dot-square",
"chat-line-square",
"message",
"postcard",
"position",
"turn-off-microphone",
"microphone",
"close-notification",
"bangzhu",
"time",
"odometer",
"crop",
"aim",
"switch-button",
"full-screen",
"copy-document",
"mic",
"stopwatch",
"medal-1",
"medal",
"trophy",
"trophy-1",
"first-aid-kit",
"discover",
"place",
"location",
"location-outline",
"location-information",
"add-location",
"delete-location",
"map-location",
"alarm-clock",
"timer",
"watch-1",
"watch",
"lock",
"unlock",
"key",
"service",
"mobile-phone",
"bicycle",
"truck",
"ship",
"basketball",
"football",
"soccer",
"baseball",
"wind-power",
"light-rain",
"lightning",
"heavy-rain",
"sunrise",
"sunrise-1",
"sunset",
"sunny",
"cloudy",
"partly-cloudy",
"cloudy-and-sunny",
"moon",
"moon-night",
"dish",
"dish-1",
"food",
"chicken",
"fork-spoon",
"knife-fork",
"burger",
"tableware",
"sugar",
"dessert",
"ice-cream",
"hot-water",
"water-cup",
"coffee-cup",
"cold-drink",
"goblet",
"goblet-full",
"goblet-square",
"goblet-square-full",
"refrigerator",
"grape",
"watermelon",
"cherry",
"apple",
"pear",
"orange",
"coffee",
"ice-tea",
"ice-drink",
"milk-tea",
"potato-strips",
"lollipop",
"ice-cream-square",
"ice-cream-round"
]
import { exportDefault, titleCase } from '@/utils/index';
import { trigger } from './config';
const units = {
KB: '1024',
MB: '1024 / 1024',
GB: '1024 / 1024 / 1024'
};
let confGlobal;
const inheritAttrs = {
file: '',
dialog: 'inheritAttrs: false,'
};
export function makeUpJs(conf, type) {
confGlobal = conf = JSON.parse(JSON.stringify(conf));
const dataList = [];
const ruleList = [];
const optionsList = [];
const propsList = [];
const methodList = mixinMethod(type);
const uploadVarList = [];
conf.fields.forEach((el) => {
buildAttributes(
el,
dataList,
ruleList,
optionsList,
methodList,
propsList,
uploadVarList
);
});
const script = buildexport(
conf,
type,
dataList.join('\n'),
ruleList.join('\n'),
optionsList.join('\n'),
uploadVarList.join('\n'),
propsList.join('\n'),
methodList.join('\n')
);
confGlobal = null;
return script;
}
function buildAttributes(
el,
dataList,
ruleList,
optionsList,
methodList,
propsList,
uploadVarList
) {
buildData(el, dataList);
buildRules(el, ruleList);
if (el.options && el.options.length) {
buildOptions(el, optionsList);
if (el.dataType === 'dynamic') {
const model = `${el.vModel}Options`;
const options = titleCase(model);
buildOptionMethod(`get${options}`, model, methodList);
}
}
if (el.props && el.props.props) {
buildProps(el, propsList);
}
if (el.action && el.tag === 'el-upload') {
uploadVarList.push(
`${el.vModel}Action: '${el.action}',
${el.vModel}fileList: [],`
);
methodList.push(buildBeforeUpload(el));
if (!el['auto-upload']) {
methodList.push(buildSubmitUpload(el));
}
}
if (el.children) {
el.children.forEach((el2) => {
buildAttributes(
el2,
dataList,
ruleList,
optionsList,
methodList,
propsList,
uploadVarList
);
});
}
}
function mixinMethod(type) {
const list = [];
const minxins = {
file: confGlobal.formBtns
? {
submitForm: `submitForm() {
this.$refs['${confGlobal.formRef}'].validate(valid => {
if(!valid) return
// TODO 提交表单
})
},`,
resetForm: `resetForm() {
this.$refs['${confGlobal.formRef}'].resetFields()
},`
}
: null,
dialog: {
onOpen: 'onOpen() {},',
onClose: `onClose() {
this.$refs['${confGlobal.formRef}'].resetFields()
},`,
close: `close() {
this.$emit('update:visible', false)
},`,
handleConfirm: `handleConfirm() {
this.$refs['${confGlobal.formRef}'].validate(valid => {
if(!valid) return
this.close()
})
},`
}
};
const methods = minxins[type];
if (methods) {
Object.keys(methods).forEach((key) => {
list.push(methods[key]);
});
}
return list;
}
function buildData(conf, dataList) {
if (conf.vModel === undefined) return;
let defaultValue;
if (typeof conf.defaultValue === 'string' && !conf.multiple) {
defaultValue = `'${conf.defaultValue}'`;
} else {
defaultValue = `${JSON.stringify(conf.defaultValue)}`;
}
dataList.push(`${conf.vModel}: ${defaultValue},`);
}
function buildRules(conf, ruleList) {
if (conf.vModel === undefined) return;
const rules = [];
if (trigger[conf.tag]) {
if (conf.required) {
const type = Array.isArray(conf.defaultValue) ? "type: 'array'," : '';
let message = Array.isArray(conf.defaultValue)
? `请至少选择一个${conf.vModel}`
: conf.placeholder;
if (message === undefined) message = `${conf.label}不能为空`;
rules.push(
`{ required: true, ${type} message: '${message}', trigger: '${
trigger[conf.tag]
}' }`
);
}
if (conf.regList && Array.isArray(conf.regList)) {
conf.regList.forEach((item) => {
if (item.pattern) {
rules.push(
// eslint-disable-next-line
`{ pattern: ${eval(item.pattern)}, message: '${
item.message
}', trigger: '${trigger[conf.tag]}' }`
);
}
});
}
ruleList.push(`${conf.vModel}: [${rules.join(',')}],`);
}
}
function buildOptions(conf, optionsList) {
if (conf.vModel === undefined) return;
if (conf.dataType === 'dynamic') {
conf.options = [];
}
const str = `${conf.vModel}Options: ${JSON.stringify(conf.options)},`;
optionsList.push(str);
}
function buildProps(conf, propsList) {
if (conf.dataType === 'dynamic') {
conf.valueKey !== 'value' && (conf.props.props.value = conf.valueKey);
conf.labelKey !== 'label' && (conf.props.props.label = conf.labelKey);
conf.childrenKey !== 'children' &&
(conf.props.props.children = conf.childrenKey);
}
const str = `${conf.vModel}Props: ${JSON.stringify(conf.props.props)},`;
propsList.push(str);
}
function buildBeforeUpload(conf) {
const unitNum = units[conf.sizeUnit];
let rightSizeCode = '';
let acceptCode = '';
const returnList = [];
if (conf.fileSize) {
rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize}
if(!isRightSize){
this.$message.error('文件大小超过 ${conf.fileSize}${conf.sizeUnit}')
}`;
returnList.push('isRightSize');
}
if (conf.accept) {
acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type)
if(!isAccept){
this.$message.error('应该选择${conf.accept}类型的文件')
}`;
returnList.push('isAccept');
}
const str = `${conf.vModel}BeforeUpload(file) {
${rightSizeCode}
${acceptCode}
return ${returnList.join('&&')}
},`;
return returnList.length ? str : '';
}
function buildSubmitUpload(conf) {
const str = `submitUpload() {
this.$refs['${conf.vModel}'].submit()
},`;
return str;
}
function buildOptionMethod(methodName, model, methodList) {
const str = `${methodName}() {
// TODO 发起请求获取数据
this.${model}
},`;
methodList.push(str);
}
function buildexport(
conf,
type,
data,
rules,
selectOptions,
uploadVar,
props,
methods
) {
const str = `${exportDefault}{
${inheritAttrs[type]}
components: {},
props: [],
data () {
return {
${conf.formModel}: {
${data}
},
${conf.formRules}: {
${rules}
},
${uploadVar}
${selectOptions}
${props}
}
},
computed: {},
watch: {},
created () {},
mounted () {},
methods: {
${methods}
}
}`;
return str;
}
import { makeMap } from '@/utils/index';
// 参考https://github.com/vuejs/vue/blob/v2.6.10/src/platforms/web/server/util.js
const isAttr = makeMap(
'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,' +
'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,' +
'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,' +
'name,contenteditable,contextmenu,controls,coords,data,datetime,default,' +
'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,' +
'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,' +
'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,' +
'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,' +
'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,' +
'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,' +
'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,' +
'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,' +
'target,title,type,usemap,value,width,wrap'
);
function vModel(self, dataObject, defaultValue) {
dataObject.props.value = defaultValue;
dataObject.on.input = (val) => {
self.$emit('input', val);
};
}
const componentChild = {
'el-button': {
default(h, conf, key) {
return conf[key];
}
},
'el-input': {
prepend(h, conf, key) {
return <template slot="prepend">{conf[key]}</template>;
},
append(h, conf, key) {
return <template slot="append">{conf[key]}</template>;
}
},
'el-select': {
options(h, conf, key) {
const list = [];
conf.options.forEach((item) => {
list.push(
<el-option
label={item.label}
value={item.value}
disabled={item.disabled}
></el-option>
);
});
return list;
}
},
'el-radio-group': {
options(h, conf, key) {
const list = [];
conf.options.forEach((item) => {
if (conf.optionType === 'button') {
list.push(
<el-radio-button label={item.value}>{item.label}</el-radio-button>
);
} else {
list.push(
<el-radio label={item.value} border={conf.border}>
{item.label}
</el-radio>
);
}
});
return list;
}
},
'el-checkbox-group': {
options(h, conf, key) {
const list = [];
conf.options.forEach((item) => {
if (conf.optionType === 'button') {
list.push(
<el-checkbox-button label={item.value}>
{item.label}
</el-checkbox-button>
);
} else {
list.push(
<el-checkbox label={item.value} border={conf.border}>
{item.label}
</el-checkbox>
);
}
});
return list;
}
},
'el-upload': {
'list-type': (h, conf, key) => {
const list = [];
if (conf['list-type'] === 'picture-card') {
list.push(<i class="el-icon-plus"></i>);
} else {
list.push(
<el-button size="small" type="primary" icon="el-icon-upload">
{conf.buttonText}
</el-button>
);
}
if (conf.showTip) {
list.push(
<div slot="tip" class="el-upload__tip">
只能上传不超过 {conf.fileSize}
{conf.sizeUnit} {conf.accept}文件
</div>
);
}
return list;
}
}
};
export default {
render(h) {
const dataObject = {
attrs: {},
props: {},
on: {},
style: {}
};
const confClone = JSON.parse(JSON.stringify(this.conf));
const children = [];
const childObjs = componentChild[confClone.tag];
if (childObjs) {
Object.keys(childObjs).forEach((key) => {
const childFunc = childObjs[key];
if (confClone[key]) {
children.push(childFunc(h, confClone, key));
}
});
}
Object.keys(confClone).forEach((key) => {
const val = confClone[key];
if (key === 'vModel') {
vModel(this, dataObject, confClone.defaultValue);
} else if (dataObject[key]) {
dataObject[key] = val;
} else if (!isAttr(key)) {
dataObject.props[key] = val;
} else {
dataObject.attrs[key] = val;
}
});
return h(this.conf.tag, dataObject, children);
},
props: ['conf']
};
import { parseTime } from './ruoyi';
import dayjs from 'dayjs';
/**
* 表格时间格式化
*/
export function formatDate(cellValue) {
if (cellValue == null || cellValue == '') return '';
var date = new Date(cellValue);
var year = date.getFullYear();
var month =
date.getMonth() + 1 < 10
? '0' + (date.getMonth() + 1)
: date.getMonth() + 1;
var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours();
var minutes =
date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes();
var seconds =
date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
return (
year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
);
}
/**
* @param {number} time
* @param {string} option
* @returns {string}
*/
export function formatTime(time, option) {
if (('' + time).length === 10) {
time = parseInt(time) * 1000;
} else {
time = +time;
}
const d = new Date(time);
const now = Date.now();
const diff = (now - d) / 1000;
if (diff < 30) {
return '刚刚';
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + '分钟前';
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + '小时前';
} else if (diff < 3600 * 24 * 2) {
return '1天前';
}
if (option) {
return parseTime(time, option);
} else {
return (
d.getMonth() +
1 +
'月' +
d.getDate() +
'日' +
d.getHours() +
'时' +
d.getMinutes() +
'分'
);
}
}
/**
* @param {string} url
* @returns {Object}
*/
export function getQueryObject(url) {
url = url == null ? window.location.href : url;
const search = url.substring(url.lastIndexOf('?') + 1);
const obj = {};
const reg = /([^?&=]+)=([^?&=]*)/g;
search.replace(reg, (rs, $1, $2) => {
const name = decodeURIComponent($1);
let val = decodeURIComponent($2);
val = String(val);
obj[name] = val;
return rs;
});
return obj;
}
/**
* @param {string} input value
* @returns {number} output value
*/
export function byteLength(str) {
// returns the byte length of an utf8 string
let s = str.length;
for (var i = str.length - 1; i >= 0; i--) {
const code = str.charCodeAt(i);
if (code > 0x7f && code <= 0x7ff) s++;
else if (code > 0x7ff && code <= 0xffff) s += 2;
if (code >= 0xdc00 && code <= 0xdfff) i--;
}
return s;
}
/**
* @param {Array} actual
* @returns {Array}
*/
export function cleanArray(actual) {
const newArray = [];
for (let i = 0; i < actual.length; i++) {
if (actual[i]) {
newArray.push(actual[i]);
}
}
return newArray;
}
/**
* @param {Object} json
* @returns {Array}
*/
export function param(json) {
if (!json) return '';
return cleanArray(
Object.keys(json).map((key) => {
if (json[key] === undefined) return '';
return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]);
})
).join('&');
}
/**
* @param {string} url
* @returns {Object}
*/
export function param2Obj(url) {
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ');
if (!search) {
return {};
}
const obj = {};
const searchArr = search.split('&');
searchArr.forEach((v) => {
const index = v.indexOf('=');
if (index !== -1) {
const name = v.substring(0, index);
const val = v.substring(index + 1, v.length);
obj[name] = val;
}
});
return obj;
}
/**
* @param {string} val
* @returns {string}
*/
export function html2Text(val) {
const div = document.createElement('div');
div.innerHTML = val;
return div.textContent || div.innerText;
}
/**
* Merges two objects, giving the last one precedence
* @param {Object} target
* @param {(Object|Array)} source
* @returns {Object}
*/
export function objectMerge(target, source) {
if (typeof target !== 'object') {
target = {};
}
if (Array.isArray(source)) {
return source.slice();
}
Object.keys(source).forEach((property) => {
const sourceProperty = source[property];
if (typeof sourceProperty === 'object') {
target[property] = objectMerge(target[property], sourceProperty);
} else {
target[property] = sourceProperty;
}
});
return target;
}
/**
* @param {HTMLElement} element
* @param {string} className
*/
export function toggleClass(element, className) {
if (!element || !className) {
return;
}
let classString = element.className;
const nameIndex = classString.indexOf(className);
if (nameIndex === -1) {
classString += '' + className;
} else {
classString =
classString.substr(0, nameIndex) +
classString.substr(nameIndex + className.length);
}
element.className = classString;
}
/**
* @param {string} type
* @returns {Date}
*/
export function getTime(type) {
if (type === 'start') {
return new Date().getTime() - 3600 * 1000 * 24 * 90;
} else {
return new Date(new Date().toDateString());
export { debounce } from 'lodash-es';
export { throttle } from 'lodash-es';
export { cloneDeep } from 'lodash-es';
export function formatDate(date, fmt = 'YYYY-MM-DD') {
if (!date) {
return '';
}
}
/**
* @param {Function} func
* @param {number} wait
* @param {boolean} immediate
* @return {*}
*/
export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result;
const later = function () {
// 据上一次触发时间间隔
const last = +new Date() - timestamp;
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};
return function (...args) {
context = this;
timestamp = +new Date();
const callNow = immediate && !timeout;
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}
return result;
};
}
/**
* This is just a simple version of deep copy
* Has a lot of edge cases bug
* If you want to use a perfect deep copy, use lodash's _.cloneDeep
* @param {Object} source
* @returns {Object}
*/
export function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone');
}
const targetObj = source.constructor === Array ? [] : {};
Object.keys(source).forEach((keys) => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys]);
} else {
targetObj[keys] = source[keys];
}
});
return targetObj;
}
/**
* @param {Array} arr
* @returns {Array}
*/
export function uniqueArr(arr) {
return Array.from(new Set(arr));
}
/**
* @returns {string}
*/
export function createUniqueString() {
const timestamp = +new Date() + '';
const randomNum = parseInt((1 + Math.random()) * 65536) + '';
return (+(randomNum + timestamp)).toString(32);
}
/**
* Check if an element has a class
* @param {HTMLElement} elm
* @param {string} cls
* @returns {boolean}
*/
export function hasClass(ele, cls) {
return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}
/**
* Add class to element
* @param {HTMLElement} elm
* @param {string} cls
*/
export function addClass(ele, cls) {
if (!hasClass(ele, cls)) ele.className += ' ' + cls;
}
/**
* Remove class from element
* @param {HTMLElement} elm
* @param {string} cls
*/
export function removeClass(ele, cls) {
if (hasClass(ele, cls)) {
const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
ele.className = ele.className.replace(reg, ' ');
}
}
export function makeMap(str, expectsLowerCase) {
const map = Object.create(null);
const list = str.split(',');
for (let i = 0; i < list.length; i++) {
map[list[i]] = true;
}
return expectsLowerCase ? (val) => map[val.toLowerCase()] : (val) => map[val];
}
export const exportDefault = 'export default ';
export const beautifierConf = {
html: {
indent_size: '2',
indent_char: ' ',
max_preserve_newlines: '-1',
preserve_newlines: false,
keep_array_indentation: false,
break_chained_methods: false,
indent_scripts: 'separate',
brace_style: 'end-expand',
space_before_conditional: true,
unescape_strings: false,
jslint_happy: false,
end_with_newline: true,
wrap_line_length: '110',
indent_inner_html: true,
comma_first: false,
e4x: true,
indent_empty_lines: true
},
js: {
indent_size: '2',
indent_char: ' ',
max_preserve_newlines: '-1',
preserve_newlines: false,
keep_array_indentation: false,
break_chained_methods: false,
indent_scripts: 'normal',
brace_style: 'end-expand',
space_before_conditional: true,
unescape_strings: false,
jslint_happy: true,
end_with_newline: true,
wrap_line_length: '110',
indent_inner_html: true,
comma_first: false,
e4x: true,
indent_empty_lines: true
}
};
// 首字母大小
export function titleCase(str) {
return str.replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
}
// 下划转驼峰
export function camelCase(str) {
return str.replace(/_[a-z]/g, (str1) => str1.substr(-1).toUpperCase());
}
export function isNumberStr(str) {
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str);
return dayjs(date).format(fmt);
}
<template>
<div>
<Tinymce v-model="TinymceContent" />
</div>
</template>
<script>
import Tinymce from '@/components/Tinymce';
export default {
name: 'MenuEditor',
components: {
Tinymce
},
data() {
return {
TinymceContent: `<h1 style="text-align: center;">如果我是孙悟空</h1>
<p class="">如果我是孙悟空穿越到现代,我会尽量保持低调并适应现代生活。以下是我可能会采取的一些策略:</p>
<ol>
<li><strong>学习现代知识</strong>:首先,我会努力学习现代的语言、文化、科技和生活方式。这可以通过阅读书籍、观看电视节目和互联网资源来实现。</li>
<li><strong>运用隐身术</strong>:如果可能的话,我会使用我的隐身术来避免引起不必要的注意。这样,我就可以在不被人发现的情况下观察和学习现代社会的运作方式。</li>
<li><strong>利用智慧和技能</strong>:虽然现代科技与我所在的时代大不相同,但我的智慧和技能仍然可以派上用场。例如,我可以利用我的变化能力来帮助人们解决一些难题,或者利用我的快速移动能力来帮助救援人员迅速到达现场。</li>
<li><strong>保护隐私</strong>:为了避免被现代社会的监控设备发现,我会尽量避免使用电子设备,如手机、电脑等。同时,我也会注意保护自己的隐私,避免暴露自己的身份。</li>
<li><strong>融入社区</strong>:我会尝试融入当地社区,与人们建立联系。我可以扮演一个普通的市民,参与社区活动,了解当地的文化和生活方式。</li>
<li><strong>保持谦逊</strong>:虽然我有强大的能力,但我会保持谦逊和低调,避免引起不必要的注意。我会尊重现代社会的规则和习惯,尽量不干涉他人的生活。</li>
</ol>
<p class="">总之,如果我是孙悟空穿越到现代,我会尽力适应现代生活,保持低调并尊重当地的文化和习惯。同时,我也会利用我的智慧和技能来帮助人们解决问题,为社会做出贡献。</p>`
};
},
mounted() {},
methods: {}
};
</script>
<template>
<div>
<el-dialog
v-bind="$attrs"
width="500px"
:close-on-click-modal="false"
:modal-append-to-body="false"
v-on="$listeners"
@open="onOpen"
@close="onClose"
>
<el-row :gutter="15">
<el-form
ref="elForm"
:model="formData"
:rules="rules"
size="medium"
label-width="100px"
>
<el-col :span="24">
<el-form-item label="生成类型" prop="type">
<el-radio-group v-model="formData.type">
<el-radio-button
v-for="(item, index) in typeOptions"
:key="index"
:label="item.value"
:disabled="item.disabled"
>
{{ item.label }}
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="showFileName" label="文件名" prop="fileName">
<el-input
v-model="formData.fileName"
placeholder="请输入文件名"
clearable
/>
</el-form-item>
</el-col>
</el-form>
</el-row>
<div slot="footer">
<el-button @click="close"> 取消 </el-button>
<el-button type="primary" @click="handleConfirm"> 确定 </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
inheritAttrs: false,
props: ['showFileName'],
data() {
return {
formData: {
fileName: undefined,
type: 'file'
},
rules: {
fileName: [
{
required: true,
message: '请输入文件名',
trigger: 'blur'
}
],
type: [
{
required: true,
message: '生成类型不能为空',
trigger: 'change'
}
]
},
typeOptions: [
{
label: '页面',
value: 'file'
},
{
label: '弹窗',
value: 'dialog'
}
]
};
},
computed: {},
watch: {},
mounted() {},
methods: {
onOpen() {
if (this.showFileName) {
this.formData.fileName = `${+new Date()}.vue`;
}
},
onClose() {},
close(e) {
this.$emit('update:visible', false);
},
handleConfirm() {
this.$refs.elForm.validate((valid) => {
if (!valid) return;
this.$emit('confirm', { ...this.formData });
this.close();
});
}
}
};
</script>
<script>
import draggable from 'vuedraggable';
import render from '@/utils/generator/render';
const components = {
itemBtns(h, element, index, parent) {
const { copyItem, deleteItem } = this.$listeners;
return [
<span
class="drawing-item-copy"
title="复制"
onClick={(event) => {
copyItem(element, parent);
event.stopPropagation();
}}
>
<i class="el-icon-copy-document" />
</span>,
<span
class="drawing-item-delete"
title="删除"
onClick={(event) => {
deleteItem(index, parent);
event.stopPropagation();
}}
>
<i class="el-icon-delete" />
</span>
];
}
};
const layouts = {
colFormItem(h, element, index, parent) {
const { activeItem } = this.$listeners;
let className =
this.activeId === element.formId
? 'drawing-item active-from-item'
: 'drawing-item';
if (this.formConf.unFocusedComponentBorder) { className += ' unfocus-bordered'; }
return (
<el-col
span={element.span}
class={className}
nativeOnClick={(event) => {
activeItem(element);
event.stopPropagation();
}}
>
<el-form-item
label-width={element.labelWidth ? `${element.labelWidth}px` : null}
label={element.label}
required={element.required}
>
<render
key={element.renderKey}
conf={element}
onInput={(event) => {
this.$set(element, 'defaultValue', event);
}}
/>
</el-form-item>
{components.itemBtns.apply(this, arguments)}
</el-col>
);
},
rowFormItem(h, element, index, parent) {
const { activeItem } = this.$listeners;
const className =
this.activeId === element.formId
? 'drawing-row-item active-from-item'
: 'drawing-row-item';
let child = renderChildren.apply(this, arguments);
if (element.type === 'flex') {
child = (
<el-row
type={element.type}
justify={element.justify}
align={element.align}
>
{child}
</el-row>
);
}
return (
<el-col span={element.span}>
<el-row
gutter={element.gutter}
class={className}
nativeOnClick={(event) => {
activeItem(element);
event.stopPropagation();
}}
>
<span class="component-name">{element.componentName}</span>
<draggable
list={element.children}
animation={340}
group="componentsGroup"
class="drag-wrapper"
>
{child}
</draggable>
{components.itemBtns.apply(this, arguments)}
</el-row>
</el-col>
);
}
};
function renderChildren(h, element, index, parent) {
if (!Array.isArray(element.children)) return null;
return element.children.map((el, i) => {
const layout = layouts[el.layout];
if (layout) {
return layout.call(this, h, el, i, element.children);
}
return layoutIsNotFound();
});
}
function layoutIsNotFound() {
throw new Error(`没有与${this.element.layout}匹配的layout`);
}
export default {
components: {
render,
draggable
},
props: ['element', 'index', 'drawingList', 'activeId', 'formConf'],
render(h) {
const layout = layouts[this.element.layout];
if (layout) {
return layout.call(this, h, this.element, this.index, this.drawingList);
}
return layoutIsNotFound();
}
};
</script>
<template>
<div class="icon-dialog">
<el-dialog
v-bind="$attrs"
width="980px"
:modal-append-to-body="false"
v-on="$listeners"
@open="onOpen"
@close="onClose"
>
<div slot="title">
选择图标
<el-input
v-model="key"
:style="{ width: '260px' }"
placeholder="请输入图标名称"
prefix-icon="el-icon-search"
clearable
/>
</div>
<ul class="icon-ul">
<li
v-for="icon in iconList"
:key="icon"
:class="active === icon ? 'active-item' : ''"
@click="onSelect(icon)"
>
<i :class="icon" />
<div>{{ icon }}</div>
</li>
</ul>
</el-dialog>
</div>
</template>
<script>
import iconList from '@/utils/generator/icon.json';
const originList = iconList.map((name) => `el-icon-${name}`);
export default {
inheritAttrs: false,
props: ['current'],
data() {
return {
iconList: originList,
active: null,
key: ''
};
},
watch: {
key(val) {
if (val) {
this.iconList = originList.filter((name) => name.indexOf(val) > -1);
} else {
this.iconList = originList;
}
}
},
methods: {
onOpen() {
this.active = this.current;
this.key = '';
},
onClose() {},
onSelect(icon) {
this.active = icon;
this.$emit('select', icon);
this.$emit('update:visible', false);
}
}
};
</script>
<style lang="scss" scoped>
.icon-ul {
margin: 0;
padding: 0;
font-size: 0;
li {
list-style-type: none;
text-align: center;
font-size: 14px;
display: inline-block;
width: 16.66%;
box-sizing: border-box;
height: 108px;
padding: 15px 6px 6px 6px;
cursor: pointer;
overflow: hidden;
&:hover {
background: #f2f2f2;
}
&.active-item {
background: #e1f3fb;
color: #7a6df0;
}
> i {
font-size: 30px;
line-height: 50px;
}
}
}
.icon-dialog {
::v-deep .el-dialog {
border-radius: 8px;
margin-bottom: 0;
margin-top: 4vh !important;
display: flex;
flex-direction: column;
max-height: 92vh;
overflow: hidden;
box-sizing: border-box;
.el-dialog__header {
padding-top: 14px;
}
.el-dialog__body {
margin: 0 20px 20px 20px;
padding: 0;
overflow: auto;
}
}
}
</style>
差异被折叠。
<template>
<div>
<el-dialog
v-bind="$attrs"
:close-on-click-modal="false"
:modal-append-to-body="false"
v-on="$listeners"
@open="onOpen"
@close="onClose"
>
<el-row :gutter="0">
<el-form
ref="elForm"
:model="formData"
:rules="rules"
size="small"
label-width="100px"
>
<el-col :span="24">
<el-form-item label="选项名" prop="label">
<el-input
v-model="formData.label"
placeholder="请输入选项名"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="选项值" prop="value">
<el-input
v-model="formData.value"
placeholder="请输入选项值"
clearable
>
<el-select
slot="append"
v-model="dataType"
:style="{ width: '100px' }"
>
<el-option
v-for="(item, index) in dataTypeOptions"
:key="index"
:label="item.label"
:value="item.value"
:disabled="item.disabled"
/>
</el-select>
</el-input>
</el-form-item>
</el-col>
</el-form>
</el-row>
<div slot="footer">
<el-button type="primary" @click="handleConfirm"> 确定 </el-button>
<el-button @click="close"> 取消 </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { isNumberStr } from '@/utils/index';
export default {
components: {},
inheritAttrs: false,
props: [],
data() {
return {
id: 100,
formData: {
label: undefined,
value: undefined
},
rules: {
label: [
{
required: true,
message: '请输入选项名',
trigger: 'blur'
}
],
value: [
{
required: true,
message: '请输入选项值',
trigger: 'blur'
}
]
},
dataType: 'string',
dataTypeOptions: [
{
label: '字符串',
value: 'string'
},
{
label: '数字',
value: 'number'
}
]
};
},
computed: {},
watch: {
// eslint-disable-next-line func-names
'formData.value': function (val) {
this.dataType = isNumberStr(val) ? 'number' : 'string';
}
},
created() {},
mounted() {},
methods: {
onOpen() {
this.formData = {
label: undefined,
value: undefined
};
},
onClose() {},
close() {
this.$emit('update:visible', false);
},
handleConfirm() {
this.$refs.elForm.validate((valid) => {
if (!valid) return;
if (this.dataType === 'number') {
this.formData.value = parseFloat(this.formData.value);
}
this.formData.id = this.id++;
this.$emit('commit', this.formData);
this.close();
});
}
}
};
</script>
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论