保存进度!
This commit is contained in:
21
企业级管理系统/web/项目源码/src/components/HelloWorld.vue
Normal file
21
企业级管理系统/web/项目源码/src/components/HelloWorld.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<div class="home">
|
||||
<h1>这里是测试文字</h1>
|
||||
<ul>
|
||||
<li>无序列表LI</li>
|
||||
<li>无序列表LI</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "HelloWorld",
|
||||
props: {
|
||||
msg: String,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss"></style>
|
12
企业级管理系统/web/项目源码/src/components/cd-form/Input.js
Normal file
12
企业级管理系统/web/项目源码/src/components/cd-form/Input.js
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
import { h } from 'vue';
|
||||
const Input = (props, context) => {
|
||||
return () => {
|
||||
return (
|
||||
<div>sdfdsf</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Input.props = ['level'];
|
||||
export default Input;
|
34
企业级管理系统/web/项目源码/src/components/cd-form/hook/relationHook.js
Normal file
34
企业级管理系统/web/项目源码/src/components/cd-form/hook/relationHook.js
Normal file
@@ -0,0 +1,34 @@
|
||||
export function relationHook(){
|
||||
/**
|
||||
* @param { String } value 控制方的选项 value
|
||||
* @param { Array } data 关联关系的数据配置 relation_hidden
|
||||
* @param { Object } props 显示/隐藏对象集保
|
||||
*/
|
||||
const HiddenItem = (value, data, props) => {
|
||||
if(data && Array.isArray(data) && data.length > 0) {
|
||||
data.forEach(item => {
|
||||
const field = item[0];
|
||||
const objValue = item[1];
|
||||
props[field] = objValue[value]
|
||||
// 选项为 1 时
|
||||
// props["title"] = objValue["1"] => true
|
||||
// props["iamge_url"] = objValue["1"] => true
|
||||
// 选项为 0 时
|
||||
// props["title"] = objValue["0"] => true
|
||||
// props["iamge_url"] = objValue["0"] => undefined
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const DisabledItem = (value, data, props) => {
|
||||
if(data && Array.isArray(data) && data.length > 0) {
|
||||
data.forEach(item => {
|
||||
const field = item[0];
|
||||
const objValue = item[1];
|
||||
props[field] = objValue[value]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return { HiddenItem, DisabledItem };
|
||||
}
|
75
企业级管理系统/web/项目源码/src/components/cd-form/hook/rulesHook.js
Normal file
75
企业级管理系统/web/项目源码/src/components/cd-form/hook/rulesHook.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import { moneyNValid } from "@/utils/amountFormat";
|
||||
/**
|
||||
* @returns BasisForm组件创建校验规则
|
||||
*/
|
||||
export function rulesHook() {
|
||||
/**
|
||||
* @param {*} data 配置额外组件
|
||||
*/
|
||||
const InitRules = (data = []) => {
|
||||
if (data.length === 0) {
|
||||
return false;
|
||||
}
|
||||
// 判断是否有required属性
|
||||
data.forEach((item) => {
|
||||
// 初始化规则数组
|
||||
let rulesArr = [];
|
||||
if (item.required) {
|
||||
const json = {
|
||||
required: true,
|
||||
message: item.required_msg || messageType(item).msg,
|
||||
trigger: "blur",
|
||||
};
|
||||
rulesArr.push(json);
|
||||
}
|
||||
// 生成placeholder
|
||||
item.placeholder = item.placeholder || messageType(item).placeholder;
|
||||
// 是否有其他的校验规则
|
||||
const rule = item.rule;
|
||||
if (rule && Array.isArray(rule) && rule.length > 0) {
|
||||
rulesArr = rulesArr.concat(rule);
|
||||
}
|
||||
// price
|
||||
if (item.type === "price" && !item.rule) {
|
||||
const json = { validator: moneyNValid, trigger: "blur" };
|
||||
rulesArr.push(json);
|
||||
}
|
||||
// 定义rules属性赋值
|
||||
item.rules = rulesArr;
|
||||
});
|
||||
return data;
|
||||
};
|
||||
/**
|
||||
*
|
||||
* @description 提示文本
|
||||
*/
|
||||
const messageType = (data) => {
|
||||
let msg = "";
|
||||
switch (data.type) {
|
||||
case "input":
|
||||
case "wangeditor":
|
||||
case "price":
|
||||
case "range":
|
||||
case "textarea":
|
||||
msg = "请输入";
|
||||
break;
|
||||
case "upload":
|
||||
msg = "请上传";
|
||||
break;
|
||||
case "radio":
|
||||
case "checkbox":
|
||||
case "select":
|
||||
case "date":
|
||||
case "cascader":
|
||||
msg = "请选择";
|
||||
break;
|
||||
default:
|
||||
msg = "未定义";
|
||||
}
|
||||
return {
|
||||
msg: `${msg}${data.label}`,
|
||||
placeholder: `${msg}${data.label}`,
|
||||
};
|
||||
};
|
||||
return { InitRules };
|
||||
}
|
180
企业级管理系统/web/项目源码/src/components/cd-form/index.vue
Normal file
180
企业级管理系统/web/项目源码/src/components/cd-form/index.vue
Normal file
@@ -0,0 +1,180 @@
|
||||
<template>
|
||||
<el-form ref="formDom" :model="field" :class="[{'label-gray': labelGray}]" :label-position="labelPosition" element-loading-text="加载中,请稍候" :label-width="label_width" >
|
||||
<el-row :gutter="gutter">
|
||||
<template v-for="item in form_item" :key="item.prop">
|
||||
<el-col v-if="!form_hidden[item.prop]" :span="item.col || 24">
|
||||
<component :is="'htmlComponent'" v-if="item.type === 'html'" :prop="item" />
|
||||
<el-form-item v-else :label="item.label" :prop="item.prop" :rules="item.rules">
|
||||
<!--自定义label-->
|
||||
<template v-if="item.label_html" #label>
|
||||
<span class="custom-label">
|
||||
<div>
|
||||
<span style="position: relative;">
|
||||
<label class="form-center" v-html="item.label_html.label || ''" />
|
||||
<em v-if="item.label_html.spot" class="spot"></em>
|
||||
</span>
|
||||
</div>
|
||||
<span :class="item.label_html.suffix_class" @click="item.label_html.suffix_callback && item.label_html.suffix_callback(item)" v-html="item.label_html.suffix_text || ''" />
|
||||
</span>
|
||||
</template>
|
||||
<!--动态组件-->
|
||||
<div v-show="control" style="width:100%">
|
||||
<component :is="item.type + 'Component'" v-if="item.type !== 'slot'" v-model:value="field[item.prop]" v-model:second-value="field[item.secondprop]" v-model:select-value="field[item.selProp]" :data="item" :header="item" :disabled="disabled[item.prop]" @callback="componentCallback" />
|
||||
<!--插槽-->
|
||||
<template v-else>
|
||||
<slot :name="item.slot_name" />
|
||||
<span v-if="item.tip" class="tip">{{ item.tip }}</span>
|
||||
</template>
|
||||
</div>
|
||||
<div v-show="!control">
|
||||
<slot v-if="item.slot_text" :name="item.slot_text" />
|
||||
<span v-else>{{ fieldText[item.prop] || '--' }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
<!-- button -->
|
||||
<div :class="['form-button', {'dialog-footer': dialog}]">
|
||||
<template v-if="form_button && form_button.length > 0">
|
||||
<template v-for="button in form_button" :key="button.key">
|
||||
<template v-if="!button.hidden">
|
||||
<CdButton v-if="button.key === 'submit'" :loading="load || loading" margin="0 0 0 16px" :type="button.type" @click="button.callback ? button.callback() : handlerFormValidate()">
|
||||
{{ button.label }}
|
||||
</CdButton>
|
||||
<CdButton v-else-if="button.key === 'cancel'" margin="0 0 0 16px" border @click="button.callback ? button.callback() : handlerFormCancel()">
|
||||
{{ button.label }}
|
||||
</CdButton>
|
||||
<CdButton v-else :type="button.type" margin="0 0 0 16px" @click="button.callback && button.callback()">{{ button.label }}</CdButton>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineAsyncComponent, onBeforeUnmount, reactive, ref, watch } from "vue";
|
||||
import { checkDataType } from "../common";
|
||||
// hook
|
||||
import { rulesHook } from "./hook/rulesHook";
|
||||
import { relationHook } from "./hook/relationHook";
|
||||
// props
|
||||
import { props } from "./props";
|
||||
// require import components
|
||||
const files = require.context("@/cd-components/cd-control", true, /\index.vue$/);
|
||||
const modules = {};
|
||||
files.keys().forEach((key) => {
|
||||
const name = key.split("/");
|
||||
modules[name[1] + "Component"] = files(key).default || files(key);
|
||||
});
|
||||
export default {
|
||||
name: "BasisForm",
|
||||
components: {
|
||||
...modules,
|
||||
CdButton: defineAsyncComponent(() => import("../cd-button")),
|
||||
},
|
||||
props,
|
||||
emits: ["callback", "cancel"],
|
||||
setup(props, { emit }) {
|
||||
const { InitRules } = rulesHook();
|
||||
const { HiddenItem, DisabledItem } = relationHook();
|
||||
// 校验规则处理
|
||||
const form_item = reactive(InitRules(props.item));
|
||||
const label_width = ref(props.labelWidth);
|
||||
const form_button = reactive(props.button);
|
||||
const form_disabled = reactive(props.disabled);
|
||||
const load = ref(false)
|
||||
let form_hidden = ref({});
|
||||
watch(() => props.hidden, (value) => {
|
||||
form_hidden.value = value
|
||||
})
|
||||
// 表单提交验证
|
||||
const formDom = ref(null);
|
||||
const handlerFormValidate = () => {
|
||||
formDom.value.validate((valid) => {
|
||||
if(valid) {
|
||||
if (checkDataType().isFunction(props.beforeChange)) {
|
||||
load.value = true
|
||||
props.beforeChange().then(() => {
|
||||
load.value = false
|
||||
}).catch(() => {
|
||||
load.value = false
|
||||
})
|
||||
return false
|
||||
}
|
||||
emit("callback")
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
const handlerFormCancel = () => {
|
||||
handlerFormReset()
|
||||
emit("cancel");
|
||||
};
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const handlerFormReset = () => {
|
||||
formDom.value.resetFields();
|
||||
};
|
||||
// change 事件
|
||||
const componentCallback = (params) => {};
|
||||
|
||||
/**
|
||||
* 生命周期
|
||||
*/
|
||||
onBeforeUnmount(() => {
|
||||
form_hidden.value = {}
|
||||
handlerFormReset()
|
||||
})
|
||||
|
||||
return {
|
||||
form_item,
|
||||
label_width,
|
||||
form_button,
|
||||
form_hidden,
|
||||
form_disabled,
|
||||
formDom,
|
||||
load,
|
||||
handlerFormValidate,
|
||||
handlerFormCancel,
|
||||
handlerFormReset,
|
||||
componentCallback,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.form-button {
|
||||
width: 100%;
|
||||
}
|
||||
.form-left {
|
||||
text-align: left;
|
||||
}
|
||||
.form-center {
|
||||
text-align: center;
|
||||
}
|
||||
.form-right {
|
||||
text-align: right;
|
||||
}
|
||||
.custom-label {
|
||||
position: relative;
|
||||
> span {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
::v-deep .color-lable-danger {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: #ff6060;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
right: -7px;
|
||||
top: 7px;
|
||||
}
|
||||
:deep(.el-input__wrapper) {
|
||||
border-radius: 0;
|
||||
}
|
||||
</style>
|
57
企业级管理系统/web/项目源码/src/components/cd-form/props.js
Normal file
57
企业级管理系统/web/项目源码/src/components/cd-form/props.js
Normal file
@@ -0,0 +1,57 @@
|
||||
export const props = {
|
||||
item: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
button: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
labelWidth: {
|
||||
type: [String, Number],
|
||||
default: "100px",
|
||||
},
|
||||
field: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
fieldText: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
hidden: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
disabled: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
position: {
|
||||
type: String,
|
||||
default: "left",
|
||||
},
|
||||
labelPosition: {
|
||||
type: String,
|
||||
default: "right",
|
||||
},
|
||||
gutter: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
beforeChange: Function,
|
||||
dialog: Boolean,
|
||||
labelGray: Boolean,
|
||||
control: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
fieldData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
};
|
86
企业级管理系统/web/项目源码/src/components/control/cascader/index.vue
Normal file
86
企业级管理系统/web/项目源码/src/components/control/cascader/index.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<el-cascader :style="{width}" :disabled="disabled" v-model="data.value" :options="data.options" :props="data.props" @change="handlerChange"></el-cascader>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, onBeforeMount, watch } from 'vue';
|
||||
// API
|
||||
import { CommonApi } from "@/api/common";
|
||||
// requestUrl
|
||||
import ApiUrl from "@/api/requestUrl";
|
||||
export default {
|
||||
name: 'BasisCascader',
|
||||
components: {},
|
||||
props: {
|
||||
cascaderProps: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
method: {
|
||||
type: String,
|
||||
default: "post"
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: "100%"
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ["update:value", 'callback'],
|
||||
setup(props, { emit }){
|
||||
const data = reactive({
|
||||
props: props.data.props,
|
||||
options: [],
|
||||
value: 0
|
||||
})
|
||||
const handlerChange = (value) => {
|
||||
// 获取最后一项
|
||||
const val = value[value.length - 1];
|
||||
// 返回
|
||||
emit("update:value", val);
|
||||
}
|
||||
/** 获取列表 */
|
||||
const getData = () => {
|
||||
const url = ApiUrl?.cascader?.[props.url || props?.data?.url]?.url;
|
||||
const method = ApiUrl?.cascader?.[props.url]?.method || "post";
|
||||
if(!url) {
|
||||
throw new Error("url地址不存在");
|
||||
}
|
||||
// 参数
|
||||
const request_data = {
|
||||
url,
|
||||
method,
|
||||
data: props.data,
|
||||
}
|
||||
CommonApi(request_data).then(response => {
|
||||
data.options = response.data;
|
||||
})
|
||||
}
|
||||
/** 生命周期挂载之前 */
|
||||
onBeforeMount(() => {
|
||||
getData();
|
||||
})
|
||||
/** 监听 */
|
||||
watch(() => props.value, (newValue) => {
|
||||
data.value = newValue
|
||||
} )
|
||||
|
||||
return { data, handlerChange }
|
||||
}
|
||||
}
|
||||
</script>
|
43
企业级管理系统/web/项目源码/src/components/control/checkbox/index.vue
Normal file
43
企业级管理系统/web/项目源码/src/components/control/checkbox/index.vue
Normal file
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<el-checkbox-group v-model="value" :disabled="form_disabled[data.prop]" @change="handlerChange">
|
||||
<el-checkbox v-for="checkbox in data.options" :label="checkbox.value" :key="checkbox.value">{{ checkbox.label }}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs } from 'vue';
|
||||
export default {
|
||||
name: "CheckboxComponent",
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
value: {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
}
|
||||
},
|
||||
emits: ['update:value', 'callback'],
|
||||
setup(props, { emit }){
|
||||
const data = reactive({
|
||||
value: '',
|
||||
data: props.data
|
||||
})
|
||||
|
||||
const handlerChange = (val) => {
|
||||
emit("update:value", val)
|
||||
emit("callback", {
|
||||
type: 'checkbox',
|
||||
value: val,
|
||||
data: props.data
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(data),
|
||||
handlerChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
52
企业级管理系统/web/项目源码/src/components/control/date/index.vue
Normal file
52
企业级管理系统/web/项目源码/src/components/control/date/index.vue
Normal file
@@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<el-date-picker :style="`width: ${data.width}`"
|
||||
v-model="value"
|
||||
:disabled="disabled"
|
||||
:type="data.date_type || 'datetime'"
|
||||
:format="data.date_format || 'YYYY-MM-DD HH:mm:ss'"
|
||||
:placeholder="data.placeholder || '选择日期时间'"
|
||||
:start-placeholder="data.start_placeholder || '请选择开始日期'"
|
||||
:end-placeholder="data.end_placeholder || '请选择结束日期'"
|
||||
:range-separator="data.range_placeholder || '-'"
|
||||
@change="handlerChange"
|
||||
>
|
||||
</el-date-picker>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs } from 'vue';
|
||||
export default {
|
||||
name: "DateComponent",
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
value: {
|
||||
type: [Array, String],
|
||||
default: ''
|
||||
},
|
||||
disabled: Boolean
|
||||
},
|
||||
emits: ['update:value', 'callback'],
|
||||
setup(props, { emit }){
|
||||
const data = reactive({
|
||||
value: '',
|
||||
data: props.data
|
||||
})
|
||||
|
||||
const handlerChange = (val) => {
|
||||
emit("update:value", val)
|
||||
emit("callback", {
|
||||
type: 'date',
|
||||
value: val,
|
||||
data: props.data
|
||||
})
|
||||
}
|
||||
return {
|
||||
...toRefs(data),
|
||||
handlerChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
49
企业级管理系统/web/项目源码/src/components/control/input/index.vue
Normal file
49
企业级管理系统/web/项目源码/src/components/control/input/index.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<el-input
|
||||
v-model="value"
|
||||
:type="data.value_type || 'text'"
|
||||
v-on:input="handlerEnter"
|
||||
debounce
|
||||
:placeholder="placeholder"
|
||||
:maxlength="prop.maxlength"
|
||||
:minlength="prop.minlength || 0"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs, watchEffect } from 'vue';
|
||||
export default {
|
||||
name: "InputComponent",
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
value: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
emits: ['update:value', 'callback'],
|
||||
setup(props, { emit }){
|
||||
const data = reactive({
|
||||
value: '',
|
||||
prop: props.data,
|
||||
placeholder: props.data.placeholder
|
||||
})
|
||||
|
||||
const handlerEnter = (val) => {
|
||||
emit("update:value", val)
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(data),
|
||||
handlerEnter
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<el-input-number v-model="value" :min="data.min || 0" :max="data.max || 99999999" @change="handleChange" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs, watchEffect } from 'vue';
|
||||
export default {
|
||||
name: "InputComponent",
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
value: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
emits: ['update:value', 'callback'],
|
||||
setup(props, { emit }){
|
||||
const data = reactive({
|
||||
value: '',
|
||||
data: props.data
|
||||
})
|
||||
|
||||
const handleChange = (val) => {
|
||||
console.log(val)
|
||||
emit("update:value", val)
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(data),
|
||||
handleChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
74
企业级管理系统/web/项目源码/src/components/control/keyword/index.vue
Normal file
74
企业级管理系统/web/项目源码/src/components/control/keyword/index.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<el-select v-model="key" placeholder="请选择" class="key-word-select" @change="handlerChange">
|
||||
<el-option v-for="item in options" :key="item.value" :value="item.value" :label="item.label"></el-option>
|
||||
</el-select>
|
||||
<el-input v-model="value" class="width-200" :placeholder="placeholder" v-on:input="callback"></el-input>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs, watch } from "vue";
|
||||
export default {
|
||||
name: "KeyWord",
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
},
|
||||
emits: ["callback"],
|
||||
setup(props, { emit }){
|
||||
const data = reactive({
|
||||
key: "",
|
||||
value: "",
|
||||
placeholder: "请输入搜索的关键字",
|
||||
options: props.data.options
|
||||
})
|
||||
|
||||
/** 下拉事件 */
|
||||
const handlerChange = (value) => {
|
||||
// 清除input输入框文本
|
||||
data.value = "";
|
||||
// 更新input输入框占位文本
|
||||
updatePlaceholder();
|
||||
// 回调
|
||||
callback()
|
||||
}
|
||||
|
||||
/** 事件回调 */
|
||||
const callback = () => {
|
||||
emit("callback", {
|
||||
type: 'keyword',
|
||||
value: { key: data.key, value: data.value },
|
||||
formItem: props.data
|
||||
})
|
||||
}
|
||||
|
||||
/** update Placeholder */
|
||||
const updatePlaceholder =() => {
|
||||
const item = data.options.filter(item => item.value === data.key)[0];
|
||||
data.placeholder = `请输入${item.label}`;
|
||||
}
|
||||
|
||||
/** 清除 */
|
||||
const handlerClear = () => {
|
||||
data.key = "";
|
||||
data.value = "";
|
||||
}
|
||||
|
||||
return {
|
||||
...toRefs(data),
|
||||
handlerChange,
|
||||
handlerClear,
|
||||
callback
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.key-word-select {
|
||||
width: 100px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.width-200 { width: 200px; }
|
||||
</style>
|
57
企业级管理系统/web/项目源码/src/components/control/radio/index.vue
Normal file
57
企业级管理系统/web/项目源码/src/components/control/radio/index.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<template v-if="!data.options && data.callback && data.callback(data)"></template>
|
||||
<el-radio-group v-else v-model="value" :disabled="disabled" @change="handlerChange">
|
||||
<el-radio
|
||||
v-for="radio in data.options"
|
||||
:key="radio[data.key_value] || radio.value"
|
||||
:label="radio[data.key_value] || radio.value">
|
||||
{{ radio[data.key_label] || radio.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs, watch } from 'vue';
|
||||
// API
|
||||
import { RoleListAll } from "@/api/role";
|
||||
export default {
|
||||
name: "DateComponent",
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
value: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
disabled: Boolean
|
||||
},
|
||||
emits: ['update:value', 'callback'],
|
||||
setup(props, { emit }){
|
||||
const dataa = reactive({
|
||||
value: '',
|
||||
data: props.data
|
||||
})
|
||||
watch(() => props.data, () => {
|
||||
RoleListAll().then(response => {
|
||||
console.log(111)
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
})
|
||||
const handlerChange = (val) => {
|
||||
emit("update:value", val)
|
||||
emit("callback", {
|
||||
type: 'radio',
|
||||
value: val,
|
||||
formItem: props.data
|
||||
})
|
||||
}
|
||||
return {
|
||||
handlerChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
41
企业级管理系统/web/项目源码/src/components/control/select/index.vue
Normal file
41
企业级管理系统/web/项目源码/src/components/control/select/index.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<el-select v-model="value" :disabled="disabled" :style="`width: ${data.width || '100%'}`" @change="handlerChange">
|
||||
<el-option v-for="select in data.options" :key="select.value" :label="select.label" :value="select.value"></el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs } from 'vue';
|
||||
export default {
|
||||
name: "SelectComponent",
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
value: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
emits: ['update:value', 'callback'],
|
||||
setup(props, { emit }){
|
||||
const data = reactive({
|
||||
value: '',
|
||||
data: props.data
|
||||
})
|
||||
|
||||
const handlerChange = (val) => {
|
||||
emit("update:value", val)
|
||||
}
|
||||
return {
|
||||
...toRefs(data),
|
||||
handlerChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
80
企业级管理系统/web/项目源码/src/components/control/switch/index.vue
Normal file
80
企业级管理系统/web/项目源码/src/components/control/switch/index.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<el-switch
|
||||
v-model="init_data.value"
|
||||
:loading="init_data.loading"
|
||||
:before-change="handlerSwitch"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, getCurrentInstance, watch } from 'vue';
|
||||
// requestUrl
|
||||
import ApiUrl from "@/api/requestUrl";
|
||||
//API
|
||||
import { SwitchStatus } from "@/api/common";
|
||||
export default {
|
||||
name: 'SwitchComponent',
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
emits: ['update:value', 'callback'],
|
||||
setup(props){
|
||||
// 配置信息
|
||||
const config = reactive(props.config);
|
||||
// 数据
|
||||
const data = reactive(props.data);
|
||||
// 初始值
|
||||
const init_data = reactive({
|
||||
value: data[config.prop],
|
||||
loading: false
|
||||
});
|
||||
// 监听数据
|
||||
watch(() => props.data, (newValue, oldValue) => {
|
||||
init_data.value = newValue[config.prop]
|
||||
})
|
||||
// 获取实例上下文
|
||||
const { proxy } = getCurrentInstance();
|
||||
// 事件
|
||||
const handlerSwitch = (value) => {
|
||||
init_data.loading = true;
|
||||
// 请求参数
|
||||
const url = config.api_url || ApiUrl?.[config.api_module]?.[config.api_key]?.url;
|
||||
const method = config.method || ApiUrl?.[config.api_module]?.[config.api_key]?.method || "post";
|
||||
if(!url) {
|
||||
console.log("请求接口不存在");
|
||||
return false
|
||||
}
|
||||
// 请求参数
|
||||
const key_id = config.key_id || 'id'
|
||||
const request_data = {
|
||||
url,
|
||||
method,
|
||||
data: {
|
||||
[key_id]: data[key_id], // 等价于["id"]: data["id"]
|
||||
[config.prop]: !init_data.value // 等价于["status"]: value
|
||||
}
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
SwitchStatus(request_data).then(response => {
|
||||
proxy.$message.success(response.message);
|
||||
data.status = value;
|
||||
init_data.loading = false;
|
||||
resolve(true)
|
||||
}).catch(error => {
|
||||
init_data.loading = false;
|
||||
reject(false)
|
||||
})
|
||||
})
|
||||
}
|
||||
return { config, init_data, handlerSwitch }
|
||||
}
|
||||
}
|
||||
</script>
|
44
企业级管理系统/web/项目源码/src/components/control/textarea/index.vue
Normal file
44
企业级管理系统/web/项目源码/src/components/control/textarea/index.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<el-input
|
||||
v-model="value"
|
||||
type="textarea"
|
||||
debounce
|
||||
:rows="data.rows || 5"
|
||||
:disabled="form_disabled[data.prop]"
|
||||
:style="`width: ${data.width || '100%'}`"
|
||||
:placeholder="data.placeholder"
|
||||
@change="handlerChange"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, toRefs } from 'vue';
|
||||
export default {
|
||||
name: "TextareaComponent",
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
emits: ['update:value', 'callback'],
|
||||
setup(props, { emit }){
|
||||
const data = reactive({
|
||||
value: '',
|
||||
data: props.data
|
||||
})
|
||||
|
||||
const handlerChange = (val) => {
|
||||
emit("update:value", val)
|
||||
}
|
||||
return {
|
||||
...toRefs(data),
|
||||
handlerChange
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
86
企业级管理系统/web/项目源码/src/components/control/upload/index.vue
Normal file
86
企业级管理系统/web/项目源码/src/components/control/upload/index.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action="#"
|
||||
:http-request="handlerUpload"
|
||||
:before-upload="handlerBeforeOnUpload"
|
||||
:on-error="handlerOnError"
|
||||
:show-file-list="false"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<img v-if="data.image_url" :src="data.image_url" class="avatar" />
|
||||
<span v-else>+</span>
|
||||
</el-upload>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, getCurrentInstance, watch } from 'vue';
|
||||
import { UploadFile } from "@/api/common";
|
||||
export default {
|
||||
name: "BasisUpload",
|
||||
components: {},
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ["update:value", 'callback'],
|
||||
setup(props, { emit }){
|
||||
// 获取实例上下文
|
||||
const { proxy } = getCurrentInstance();
|
||||
const data = reactive({
|
||||
image_url: ""
|
||||
})
|
||||
const handlerOnError = (res, file) => {}
|
||||
const handlerBeforeOnUpload = async (file) => {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2; // 限制文件大小不能大于 2M
|
||||
if (!isLt2M) {
|
||||
proxy.$message.error("上传图片大小不能超过 2MB!");
|
||||
return false;
|
||||
}
|
||||
return isJPG && isLt2M;
|
||||
}
|
||||
const handlerUpload = async (params) => {
|
||||
const file = params.file;
|
||||
// 实例化表单对象
|
||||
const form = new FormData();
|
||||
// 表单添加 files 字段
|
||||
form.append("files", file);
|
||||
// 上传接口
|
||||
try{
|
||||
const url = await startUpload(form)
|
||||
data.image_url = url;
|
||||
emit("update:imageUrl", url)
|
||||
}catch{
|
||||
console.log("上传失败")
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 开始文件上传
|
||||
*/
|
||||
const startUpload = (form) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
UploadFile(form).then(response => {
|
||||
resolve(response.data.files_path);
|
||||
})
|
||||
})
|
||||
}
|
||||
watch(() => props.value, (newValue, oldValue) => {
|
||||
data.image_url = newValue
|
||||
})
|
||||
return {
|
||||
data,
|
||||
handlerUpload,
|
||||
handlerOnError,
|
||||
handlerBeforeOnUpload
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
</style>
|
69
企业级管理系统/web/项目源码/src/components/control/wangeditor/index.vue
Normal file
69
企业级管理系统/web/项目源码/src/components/control/wangeditor/index.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div ref="editor"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, watch, nextTick } from 'vue';
|
||||
import WangEditor from 'wangeditor';
|
||||
// cookies
|
||||
import { getToken } from "@/utils/cookies"; // 这是封装好的方法
|
||||
export default {
|
||||
name: 'Wangeditor',
|
||||
components: {},
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
emits: ["update:value", 'callback'],
|
||||
setup(props, { emit }){
|
||||
let html = ref(null)
|
||||
// 内容
|
||||
let content = ref('');
|
||||
// 富文本DOM元素
|
||||
const editor = ref(null);
|
||||
// 富文本对象
|
||||
let editor_instance = null;
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
// 创建富文本对象
|
||||
editor_instance = new WangEditor(editor.value);
|
||||
// 图片上传配置
|
||||
editor_instance.config.uploadImgServer = process.env.VUE_APP_DEV_TARGET + '/upload' // 上传图片的接口地址
|
||||
editor_instance.config.uploadFileName = 'files' // formdata中的name属性
|
||||
editor_instance.config.uploadImgHeaders = {
|
||||
Token: getToken() // 设置请求头
|
||||
}
|
||||
editor_instance.config.uploadImgHooks = {
|
||||
// 图片上传并返回结果,但图片插入错误时触发
|
||||
fail: function (xhr, editor, result) {
|
||||
console.log(result)
|
||||
},
|
||||
// 例如服务器端返回的不是 { errno: 0, data: [...] } 这种格式,可使用 customInsert
|
||||
customInsert: function(insertImgFn, result) {
|
||||
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
|
||||
insertImgFn(result.data.files_path)
|
||||
}
|
||||
}
|
||||
// 配置change事件
|
||||
Object.assign(editor_instance.config, {
|
||||
onchange(value) {
|
||||
content.value = value;
|
||||
emit("update:value", value);
|
||||
},
|
||||
});
|
||||
// 创建
|
||||
editor_instance.create();
|
||||
})
|
||||
})
|
||||
watch(() => props.value, (newContent, oldContent) => {
|
||||
editor_instance.txt.html(newContent);
|
||||
})
|
||||
return { editor }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
</style>
|
34
企业级管理系统/web/项目源码/src/components/form/hook/relationHook.js
Normal file
34
企业级管理系统/web/项目源码/src/components/form/hook/relationHook.js
Normal file
@@ -0,0 +1,34 @@
|
||||
export function relationHook(){
|
||||
/**
|
||||
* @param { String } value 控制方的选项 value
|
||||
* @param { Array } data 关联关系的数据配置 relation_hidden
|
||||
* @param { Object } props 显示/隐藏对象集保
|
||||
*/
|
||||
const HiddenItem = (value, data, props) => {
|
||||
if(data && Array.isArray(data) && data.length > 0) {
|
||||
data.forEach(item => {
|
||||
const field = item[0];
|
||||
const objValue = item[1];
|
||||
props[field] = objValue[value]
|
||||
// 选项为 1 时
|
||||
// props["title"] = objValue["1"] => true
|
||||
// props["iamge_url"] = objValue["1"] => true
|
||||
// 选项为 0 时
|
||||
// props["title"] = objValue["0"] => true
|
||||
// props["iamge_url"] = objValue["0"] => undefined
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const DisabledItem = (value, data, props) => {
|
||||
if(data && Array.isArray(data) && data.length > 0) {
|
||||
data.forEach(item => {
|
||||
const field = item[0];
|
||||
const objValue = item[1];
|
||||
props[field] = objValue[value]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return { HiddenItem, DisabledItem };
|
||||
}
|
88
企业级管理系统/web/项目源码/src/components/form/hook/rulesHook.js
Normal file
88
企业级管理系统/web/项目源码/src/components/form/hook/rulesHook.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import { reactive } from "vue";
|
||||
// 验证
|
||||
import { validate_email, validate_password } from "@/utils/validate";
|
||||
/**
|
||||
* @returns BasisForm组件创建校验规则
|
||||
*/
|
||||
export function rulesHook(){
|
||||
/**
|
||||
* @param {*} data 配置额外组件
|
||||
*/
|
||||
const InitRules = (data = []) => {
|
||||
if(data.length === 0) { return false; }
|
||||
// 判断是否有required属性
|
||||
data.forEach(item => {
|
||||
//初始化规则数组
|
||||
let rulesArr = [];
|
||||
if(item.required) {
|
||||
let json = { required: true, message: item.message || messageType(item), trigger: 'change' }
|
||||
rulesArr.push(json)
|
||||
}
|
||||
// 是否有其他的校验规则
|
||||
const rule = item.rule;
|
||||
if(rule && Array.isArray(rule) && rule.length > 0) {
|
||||
rulesArr = rulesArr.concat(rule);
|
||||
}
|
||||
// 用户名
|
||||
if(item.value_type === 'username') {
|
||||
const rule = {
|
||||
validator(rule, value, callback, source, options) {
|
||||
if(!value || value === ""){
|
||||
callback(new Error("请输入用户名"));
|
||||
}else if(!validate_email(value)) {
|
||||
callback(new Error("邮箱格式不正确"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
rulesArr = rulesArr.concat(rule);
|
||||
}
|
||||
// 密码
|
||||
if(item.value_type === 'password') {
|
||||
const rule = {
|
||||
validator(rule, value, callback, source, options) {
|
||||
if(!value || value === ""){
|
||||
callback(new Error("请输入用密码"));
|
||||
}else if(!validate_password(value)) {
|
||||
callback(new Error("请输入>=6并且<=20位的密码,包含数字、字母"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
rulesArr = rulesArr.concat(rule);
|
||||
}
|
||||
// 定义rules属性赋值
|
||||
item.rules = rulesArr;
|
||||
});
|
||||
return data;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @description 提示文本
|
||||
*/
|
||||
const messageType = (data) => {
|
||||
let msg = "";
|
||||
switch(data.type){
|
||||
case "input":
|
||||
case "wangeditor":
|
||||
msg = "请输入";
|
||||
break;
|
||||
case "upload":
|
||||
msg = "请上传";
|
||||
break;
|
||||
case "radio":
|
||||
case "checkbox":
|
||||
case "select":
|
||||
case "date":
|
||||
case "cascader":
|
||||
msg = "请选择";
|
||||
break;
|
||||
default:
|
||||
msg = "未定义";
|
||||
}
|
||||
return `${msg}${data.label}`;
|
||||
}
|
||||
return { InitRules };
|
||||
}
|
128
企业级管理系统/web/项目源码/src/components/form/index.vue
Normal file
128
企业级管理系统/web/项目源码/src/components/form/index.vue
Normal file
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<el-form ref="formDom" v-loading="loading" element-loading-text="加载中,请稍候" :label-width="label_width" :model="field">
|
||||
<el-row>
|
||||
<template v-for="item in form_item" :key="item.prop">
|
||||
<el-col v-if="!form_hidden[item.prop]" :span="item.col || 24">
|
||||
<el-form-item v-if="item.type !== 'slot'" :label="item.label" :prop="item.prop" :rules="item.rules">
|
||||
<component
|
||||
v-model:value="field[item.prop]"
|
||||
:is="item.type + 'Component'"
|
||||
:data="item"
|
||||
:disabled="disabled[item.prop]"
|
||||
@callback="componentCallback"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item v-else :label="item.label" :prop="item.prop" :rules="item.rules">
|
||||
<slot :name="item.slot_name"></slot>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
<!-- button -->
|
||||
<el-form-item v-if="form_button && form_button.length > 0">
|
||||
<el-button
|
||||
v-for="item in form_button"
|
||||
:key="item.key"
|
||||
:type="item.type"
|
||||
@click="item.callback ? item.callback() : handlerFormActive(item)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref } from 'vue';
|
||||
// hook
|
||||
import { rulesHook } from "./hook/rulesHook";
|
||||
import { relationHook } from "./hook/relationHook";
|
||||
// require import components
|
||||
const files = require.context('@c/control', true, /\index.vue$/);
|
||||
const modules = {}
|
||||
files.keys().forEach(key => {
|
||||
const name = key.split("/")
|
||||
modules[name[1]+'Component'] = files(key).default || files(key)
|
||||
})
|
||||
export default {
|
||||
name: 'BasisForm',
|
||||
components: modules,
|
||||
props: {
|
||||
item: {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
},
|
||||
button: {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
},
|
||||
labelWidth: {
|
||||
type: [String, Number],
|
||||
default: "100px"
|
||||
},
|
||||
field: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
hidden: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
disabled: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hidden: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
disabled: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
emits: ["callback"],
|
||||
setup(props, { emit }){
|
||||
const { InitRules } = rulesHook();
|
||||
const { HiddenItem, DisabledItem } = relationHook();
|
||||
// 校验规则处理
|
||||
const form_item = reactive(InitRules(props.item));
|
||||
const label_width = ref(props.labelWidth);
|
||||
const form_button = reactive(props.button);
|
||||
const form_hidden = reactive(props.hidden);
|
||||
const form_disabled = reactive(props.disabled);
|
||||
// 表单提交验证
|
||||
const formDom = ref(null);
|
||||
// form表单动作
|
||||
const handlerFormActive = (data) => {
|
||||
// 提交表单事件
|
||||
if(data.key === 'submit') {
|
||||
formDom.value.validate((valid) => valid && emit("callback"));
|
||||
}
|
||||
// 重置表单事件
|
||||
if(data.key === 'reset') { handlerFormReset(); }
|
||||
}
|
||||
/**
|
||||
* 重置表单
|
||||
*/
|
||||
const handlerFormReset = () => {
|
||||
formDom.value.resetFields();
|
||||
}
|
||||
// change 事件
|
||||
const componentCallback = (params) => {
|
||||
if(params.formItem.relation_hidden) {
|
||||
HiddenItem(params.value, params.formItem.relation_hidden, form_hidden)
|
||||
}
|
||||
if(params.formItem.relation_disabled) {
|
||||
DisabledItem(params.value, params.formItem.relation_hidden, form_disabled)
|
||||
}
|
||||
}
|
||||
return { formDom, form_item, label_width, form_button, form_hidden, form_disabled, formDom, handlerFormActive, componentCallback, handlerFormReset }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
69
企业级管理系统/web/项目源码/src/components/pagination/index.vue
Normal file
69
企业级管理系统/web/项目源码/src/components/pagination/index.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<el-pagination
|
||||
class="pull-right"
|
||||
sizs="small"
|
||||
background
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
v-model:current-page="current_page"
|
||||
:page-size="10"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, watchEffect, watch } from 'vue';
|
||||
export default {
|
||||
name: 'Pagination',
|
||||
props: {
|
||||
total: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
current: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
flag: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
emits: ["sizeChange", "currentChange", "update:flag"],
|
||||
setup(props, { emit }){
|
||||
// 当前页码
|
||||
const current_page = ref(1);
|
||||
// 总条数统计
|
||||
const total = ref(props.total);
|
||||
const page_status = ref(false);
|
||||
// 监听props.total发生变化时更新total
|
||||
watchEffect(() => {
|
||||
total.value = props.total;
|
||||
current_page.value = props.current;
|
||||
})
|
||||
watch(() => props.flag, (newValue) => {
|
||||
page_status.value = newValue
|
||||
})
|
||||
// 页码事件
|
||||
const handleSizeChange = (val) => {
|
||||
page_status.value = true
|
||||
emit("update:flag", true)
|
||||
const params = {
|
||||
pageNumber: 1,
|
||||
pageSize: val
|
||||
}
|
||||
emit("sizeChange", params, 'page')
|
||||
}
|
||||
const handleCurrentChange = (val) => {
|
||||
if(page_status.value) { return false }
|
||||
const params = {
|
||||
pageNumber: val
|
||||
}
|
||||
emit("currentChange", params, 'page')
|
||||
}
|
||||
return { total, current_page, handleSizeChange, handleCurrentChange }
|
||||
}
|
||||
}
|
||||
</script>
|
130
企业级管理系统/web/项目源码/src/components/search/index.vue
Normal file
130
企业级管理系统/web/项目源码/src/components/search/index.vue
Normal file
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<div v-if="button_group.length > 0" class="form-search-button-group">
|
||||
<el-button v-for="item in button_group" :key="item.id" :type="item.type" @click="item.callback && item.callback()">{{ item.label }}</el-button>
|
||||
</div>
|
||||
<el-form ref="searchForm" inline :label-width="label_width" :model="field">
|
||||
<template v-if="form_item && form_item.length > 0">
|
||||
<el-form-item v-for="item in form_item" :key="item.prop" :label="item.label" :prop="item.prop" :label-width="item.label_width || label_width">
|
||||
<component :ref="componentDom" :key="item.type" v-model:value="field[item.prop]" :is="item.type + 'Component'" :data="item" @callback="componentCallback" />
|
||||
</el-form-item>
|
||||
<!-- button -->
|
||||
<el-form-item>
|
||||
<div class="pull-right">
|
||||
<el-button type="danger" @click="handlerSearch">搜索</el-button>
|
||||
<el-button v-if="button.reset_button" @click="handlerReset">重置</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, ref, inject, toRefs, nextTick } from 'vue';
|
||||
// require import components
|
||||
const files = require.context('@c/control', true, /\index.vue$/);
|
||||
const modules = {}
|
||||
files.keys().forEach(key => {
|
||||
const name = key.split("/")
|
||||
modules[name[1]+'Component'] = files(key).default || files(key)
|
||||
})
|
||||
export default {
|
||||
name: 'BasisForm',
|
||||
components: modules,
|
||||
props: {
|
||||
item: {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
},
|
||||
labelWidth: {
|
||||
type: [String, Number],
|
||||
default: "100px"
|
||||
},
|
||||
field: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
button: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
button_group: {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
},
|
||||
button_col: {
|
||||
type: Number,
|
||||
default: 24
|
||||
}
|
||||
},
|
||||
emits: ["callbackSearch"],
|
||||
setup(props, { emit }){
|
||||
const data = reactive({ key: "", value: "" });
|
||||
// 获取父组件provide数据
|
||||
const search_config = inject("search_config");
|
||||
// label占位宽度
|
||||
const label_width = ref(search_config?.label_width || props.labelWidth);
|
||||
// 组件元素配置
|
||||
const form_item = reactive(search_config?.form_item || props.item);
|
||||
// 字段配置
|
||||
const field = reactive(search_config?.form_data || props.field);
|
||||
// 按钮配置
|
||||
const button = reactive(search_config?.form_button || props.button);
|
||||
// 按钮组配置
|
||||
const button_group = reactive(search_config?.form_button_group || props.button_group);
|
||||
// 按钮占位 col
|
||||
const button_col = reactive(search_config?.button_col || props.button_col);
|
||||
/**
|
||||
* 获取动态组件的dom
|
||||
*/
|
||||
const keyword = ref(null)
|
||||
const componentDom = el => {
|
||||
console.log(el)
|
||||
if(el && el.data.type === 'keyword') {
|
||||
keyword.value = el
|
||||
}
|
||||
}
|
||||
// 搜索
|
||||
const handlerSearch = () => {
|
||||
const data = formatRequest();
|
||||
// 回调父组件方法
|
||||
emit("callbackSearch", data, "search");
|
||||
}
|
||||
// 重置
|
||||
const searchForm = ref(null);
|
||||
const handlerReset = () => {
|
||||
searchForm.value.resetFields();
|
||||
// 调用关键字组件的clear方法
|
||||
keyword.value && keyword.value.handlerClear()
|
||||
emit("callbackSearch", {}, "search");
|
||||
}
|
||||
/** 参数格式化 */
|
||||
const formatRequest = () => {
|
||||
// 声明空的JSON对象临时存储数据
|
||||
const request_data = {};
|
||||
// 过滤在值存在的数据
|
||||
for(let key in field) {
|
||||
if(field[key] !== "") { request_data[key] = field[key]; }
|
||||
}
|
||||
// 判断关键字下拉选择是否有值存在
|
||||
if(data.key && data.value) { request_data[data.key] = data.value; }
|
||||
// 返回参数
|
||||
return request_data;
|
||||
}
|
||||
// 回调
|
||||
const componentCallback = (params) => {
|
||||
if(params.type === 'keyword') {
|
||||
data.key = params.value.key
|
||||
data.value = params.value.value
|
||||
}
|
||||
}
|
||||
return {
|
||||
...toRefs(data),
|
||||
form_item, field, label_width, button, componentCallback, handlerSearch, handlerReset, componentDom, searchForm, button_group, button_col
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.form-search-button-group { margin-bottom: 20px; }
|
||||
</style>
|
38
企业级管理系统/web/项目源码/src/components/svgIcon/Index.vue
Normal file
38
企业级管理系统/web/项目源码/src/components/svgIcon/Index.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<svg class="svg-class" :class="svgClassName">
|
||||
<use :href="svgIcon"></use>
|
||||
</svg>
|
||||
</template>
|
||||
<script>
|
||||
import { ref, computed } from "vue";
|
||||
export default {
|
||||
name: "SvgIcon",
|
||||
props: {
|
||||
iconName: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
setup(props){
|
||||
// className
|
||||
const svgClassName = ref(props.className);
|
||||
// svg 图标
|
||||
const svgIcon = computed(() => `#icon-${props.iconName}`);
|
||||
return {
|
||||
svgClassName,
|
||||
svgIcon
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.svg-class {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
fill: currentColor;
|
||||
}
|
||||
</style>
|
1
企业级管理系统/web/项目源码/src/components/svgIcon/icon/home.svg
Normal file
1
企业级管理系统/web/项目源码/src/components/svgIcon/icon/home.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1608734152787" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1160" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M959.390493 527.761985c0 23.127743-18.419512 41.87369-41.138956 41.87369-12.335956 0-23.276123-5.640464-30.817889-14.393825L541.089525 202.729238c-16.065907-16.353456-42.113143-16.353456-58.179051 0L237.802034 452.204126c2.877537 5.636371 4.653997 11.926634 4.653997 18.690688l0 165.475775c0 0.328481-0.089028 0.635473-0.097214 0.961908l0.297782 0 0 163.003468c0 23.125697 18.506493 41.871643 41.337477 41.871643l82.568531 0L366.562607 677.738765c0-22.850427 18.520819-41.3692 41.3692-41.3692L614.775758 636.369565c22.848381 0 41.3692 18.518772 41.3692 41.3692 0 22.846334-18.520819 41.3692-41.3692 41.3692L449.299983 719.107965l0 165.473729c0 22.427802-17.875113 40.583301-40.142256 41.246403l0 0.121773L263.148305 925.94987c-57.115835 0-103.418394-46.864354-103.418394-104.678084L159.729911 637.331473l0.084934 0c-0.00614-0.326435-0.097214-0.633427-0.097214-0.961908L159.717631 531.680225l-23.162536 23.575952c-7.541767 8.745175-18.475793 14.379499-30.807656 14.379499-22.719444 0-41.138956-18.745946-41.138956-41.87369 0-11.862165 4.895497-22.520923 12.687974-30.141484l-0.237407-0.2415 362.215602-368.668571c40.164768-40.881083 105.285928-40.881083 145.450696 0l361.569896 368.010585-0.299829 0.305969C954.175725 504.680291 959.390493 515.563152 959.390493 527.761985zM614.733802 842.206584c0.443092 0 0.854461 0.119727 1.294482 0.132006l0-0.132006 122.683157 0c22.828938 0 41.337477-18.745946 41.337477-41.871643L780.048919 637.331473l0.534166 0c-0.016373-0.496304-0.145309-0.961908-0.145309-1.464351 0-23.125697 18.417465-41.87369 41.138956-41.87369 22.719444 0 41.136909 18.747993 41.136909 41.87369 0 0.502443-0.125867 0.968048-0.145309 1.464351l0.405229 0 0 183.940312c0 57.812707-46.299489 104.678084-103.418394 104.678084l-143.528927 0 0-0.132006c-0.441045 0.014326-0.852414 0.132006-1.294482 0.132006-22.719444 0-41.138956-18.7439-41.138956-41.869596C573.594847 860.9556 592.014358 842.206584 614.733802 842.206584z" p-id="1161"></path></svg>
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1608736466130" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="791" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M782.27531852 936.77037037H241.72468148c-60.19602963 0-109.22666667-49.03063703-109.22666666-109.22666667V196.4562963c0-60.19602963 49.03063703-109.22666667 109.22666666-109.22666667h540.55063704c60.19602963 0 109.22666667 49.03063703 109.22666666 109.22666667v631.0874074c0 60.19602963-49.03063703 109.22666667-109.22666666 109.22666667zM241.72468148 160.04740741c-20.02488889 0-36.40888889 16.384-36.40888889 36.40888889v631.0874074c0 20.02488889 16.384 36.40888889 36.40888889 36.40888889h540.55063704c20.02488889 0 36.40888889-16.384 36.40888889-36.40888889V196.4562963c0-20.02488889-16.384-36.40888889-36.40888889-36.40888889H241.72468148z" p-id="792"></path><path d="M747.44414815 343.30548148H271.70133333c-20.14625185 0-36.40888889-16.26263703-36.40888888-36.40888889s16.26263703-36.40888889 36.40888888-36.40888889h475.74281482c20.14625185 0 36.40888889 16.26263703 36.40888888 36.40888889s-16.26263703 36.40888889-36.40888888 36.40888889zM747.44414815 497.43644445H271.70133333c-20.14625185 0-36.40888889-16.26263703-36.40888888-36.4088889s16.26263703-36.40888889 36.40888888-36.40888888h475.74281482c20.14625185 0 36.40888889 16.26263703 36.40888888 36.40888888s-16.26263703 36.40888889-36.40888888 36.4088889zM554.47703703 653.99466667H271.70133333c-20.14625185 0-36.40888889-16.26263703-36.40888888-36.40888889s16.26263703-36.40888889 36.40888888-36.40888889h282.7757037c20.14625185 0 36.40888889 16.26263703 36.40888889 36.40888889s-16.26263703 36.40888889-36.40888889 36.40888889z" p-id="793"></path></svg>
|
After Width: | Height: | Size: 1.9 KiB |
1
企业级管理系统/web/项目源码/src/components/svgIcon/icon/logout.svg
Normal file
1
企业级管理系统/web/项目源码/src/components/svgIcon/icon/logout.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1621589152962" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2857" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M706.432 195.136c-14.656-9.536-34.56-5.44-44.224 9.408-9.536 14.848-5.376 34.688 9.472 44.288C772.032 314.048 832 424.448 832 544.192c0 193.92-157.504 351.68-351.04 351.68s-351.04-157.76-351.04-351.68c0-119.68 60.032-230.144 160.448-295.296 14.848-9.6 19.072-29.504 9.472-44.352C290.112 189.632 270.336 185.408 255.552 195.072 136.768 272.192 65.856 402.688 65.856 544.192 65.856 773.504 252.032 960 480.96 960S896 773.504 896 544.192C896 402.624 825.152 272.128 706.432 195.136zM480.96 572.16c17.664 0 32-14.656 32-32.832l0-380.8c0-18.112-14.336-32.768-32-32.768s-32 14.656-32 32.768l0 380.8C448.96 557.504 463.232 572.16 480.96 572.16z" p-id="2858"></path></svg>
|
After Width: | Height: | Size: 1.0 KiB |
1
企业级管理系统/web/项目源码/src/components/svgIcon/icon/menuBtn.svg
Normal file
1
企业级管理系统/web/项目源码/src/components/svgIcon/icon/menuBtn.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1621586114074" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2473" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.1953125" height="200"><defs><style type="text/css"></style></defs><path d="M980.8 468.8H43.2C17.6 468.8 0 486.4 0 512s17.6 43.2 43.2 43.2h939.2c25.6 0 43.2-17.6 43.2-43.2-1.6-25.6-19.2-43.2-44.8-43.2zM980.8 768H43.2C17.6 768 0 785.6 0 811.2s17.6 43.2 43.2 43.2h939.2c25.6 0 43.2-17.6 43.2-43.2-1.6-25.6-19.2-43.2-44.8-43.2zM43.2 256h939.2c25.6 0 43.2-17.6 43.2-43.2s-17.6-43.2-43.2-43.2H43.2c-25.6 0-43.2 17.6-43.2 43.2S17.6 256 43.2 256z" p-id="2474"></path></svg>
|
After Width: | Height: | Size: 775 B |
2
企业级管理系统/web/项目源码/src/components/svgIcon/icon/system.svg
Normal file
2
企业级管理系统/web/项目源码/src/components/svgIcon/icon/system.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1627108347577" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4935" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_1uhr8ri0pk5.eot?#iefix") format("embedded-opentype"), url("//at.alicdn.com/t/font_1031158_1uhr8ri0pk5.woff2") format("woff2"), url("//at.alicdn.com/t/font_1031158_1uhr8ri0pk5.woff") format("woff"), url("//at.alicdn.com/t/font_1031158_1uhr8ri0pk5.ttf") format("truetype"), url("//at.alicdn.com/t/font_1031158_1uhr8ri0pk5.svg#iconfont") format("svg"); }
|
||||
</style></defs><path d="M660.750044 997.266537c-14.811783 0-29.804198-5.418945-40.461457-15.173046-15.714941-14.45052-69.181866-55.995766-107.114482-55.995767-38.293879 0-91.580173 41.545246-107.114482 55.995767-16.256835 15.173046-42.809667 19.688834-63.221027 10.657259l-3.070736-1.445052-153.898042-89.231964c-17.701887-13.1861-27.094726-38.47451-22.217675-59.969659 4.696419-20.772623 13.908626-87.786911-5.057682-120.661845-18.966308-32.874934-81.64544-58.343976-102.0568-64.846711-20.41136-6.322103-37.932616-26.191568-41.545246-47.325454-0.361263-2.167578-9.212207-54.370083-9.212207-92.663962 0-38.293879 8.850944-90.315752 9.212207-92.663962 3.61263-21.133886 21.133886-41.003352 41.545246-47.325454s83.090492-31.791145 102.0568-64.84671c19.146939-33.055565 9.934733-99.889222 5.057682-120.661845-4.877051-21.675781 4.335156-46.78356 22.217675-59.96966l2.890104-1.986946 153.898042-88.8707c20.41136-9.031575 46.964191-4.515788 63.221027 10.657258 15.714941 14.45052 69.181866 55.995766 107.114482 55.995767 38.293879 0 91.580173-41.545246 107.114483-55.995767 16.256835-15.173046 42.809667-19.688834 63.221026-10.657258l3.070736 1.445052 153.898042 89.231963c17.701887 13.1861 27.094726 38.47451 22.217675 59.969659-4.696419 20.772623-13.908626 87.786911 5.057682 120.661846 18.966308 32.874934 81.64544 58.343976 102.0568 64.84671 20.41136 6.322103 37.932616 26.191568 41.545246 47.325454 0.361263 2.167578 9.212207 54.370083 9.212207 92.663962 0 38.293879-8.850944 90.315752-9.212207 92.663962-3.61263 21.133886-21.133886 41.003352-41.545246 47.325454s-83.090492 31.791145-102.0568 64.84671c-19.146939 33.055565-9.934733 99.889222-5.057682 120.661845 4.877051 21.495149-4.335156 46.78356-22.217675 59.96966l-2.890104 1.986946-153.898042 88.870701c-7.22526 2.890104-14.992415 4.515788-22.75957 4.515787zM225.247486 852.580702l140.531311 81.284177c15.353678-13.727994 82.548598-70.626918 147.214676-70.626918s131.860998 56.718292 147.214677 70.626918l140.53131-81.284177c-4.154525-19.869466-19.869466-106.572588 12.644206-162.748986 33.416828-57.982713 120.661845-87.786911 136.376786-92.844593 1.445052-8.489681 8.128418-50.938084 8.128417-80.561651 0-29.623567-6.683366-72.07197-8.128417-80.561651-15.714941-5.057682-102.959958-34.86188-136.376786-92.844594-32.333039-56.176398-16.79873-142.87952-12.644206-162.748985l-140.53131-81.284177c-15.353678 13.727994-82.548598 70.626918-147.214677 70.626918-64.84671 0-131.860998-56.718292-147.214676-70.626918l-140.531311 81.284177c4.154525 19.869466 19.869466 106.572588-12.644205 162.748985-33.416828 57.982713-120.661845 87.786911-136.376786 92.844594-1.445052 8.489681-8.128418 50.938084-8.128418 80.561651 0 29.623567 6.683366 72.07197 8.128418 80.561651 15.714941 5.057682 102.959958 34.86188 136.376786 92.844593 32.333039 56.176398 16.79873 142.87952 12.644205 162.748986z" p-id="4936"></path><path d="M512.993473 729.751279c-117.59111 0-213.145176-95.734697-213.145175-213.325807s95.734697-213.325807 213.325807-213.325807 213.145176 95.734697 213.145175 213.325807S630.584583 729.751279 512.993473 729.751279z m0-363.972482c-83.090492 0-150.646675 67.556183-150.646675 150.646675s67.556183 150.646675 150.646675 150.646675c83.090492 0 150.646675-67.556183 150.646675-150.646675S596.083965 365.778797 512.993473 365.778797z" p-id="4937"></path></svg>
|
After Width: | Height: | Size: 4.0 KiB |
1
企业级管理系统/web/项目源码/src/components/svgIcon/icon/user.svg
Normal file
1
企业级管理系统/web/项目源码/src/components/svgIcon/icon/user.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1608814595533" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="809" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M512 962C263.4875 962 62 760.5125 62 512S263.4875 62 512 62s450 201.4875 450 450-201.4875 450-450 450z m0-825.00000029C304.8875 136.99999971 136.99999971 304.8875 136.99999971 512s167.88750029 375.00000029 375.00000029 375.00000029 375.00000029-167.88750029 375.00000029-375.00000029S719.1125 136.99999971 512 136.99999971z m0 675a299.40000029 299.40000029 0 0 1-234-112.5A299.40000029 299.40000029 0 0 1 512 586.99999971a299.25 299.25 0 0 1 233.96249971 112.5A299.25 299.25 0 0 1 512 811.99999971z m0-262.49999942a150.00000029 150.00000029 0 1 1 0-300.00000058 150.00000029 150.00000029 0 0 1 0 300.00000058z" p-id="810"></path></svg>
|
After Width: | Height: | Size: 1011 B |
7
企业级管理系统/web/项目源码/src/components/svgIcon/svg.js
Normal file
7
企业级管理系统/web/项目源码/src/components/svgIcon/svg.js
Normal file
@@ -0,0 +1,7 @@
|
||||
// 获取当前svg目录所有为.svg结尾的文件
|
||||
const context = require.context('./icon', false, /\.svg$/);
|
||||
// 解析获取的.svg文件的文件名称,并返回
|
||||
const requireAll = (requireContext) => {
|
||||
return requireContext.keys().map(requireContext);
|
||||
};
|
||||
requireAll(context);
|
67
企业级管理系统/web/项目源码/src/components/switch/index.vue
Normal file
67
企业级管理系统/web/项目源码/src/components/switch/index.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<el-switch
|
||||
v-model="init_data.value"
|
||||
:loading="init_data.loading"
|
||||
@change="handlerSwitch($event)"
|
||||
>
|
||||
</el-switch>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, getCurrentInstance } from 'vue';
|
||||
// requestUrl
|
||||
import ApiUrl from "@/api/requestUrl";
|
||||
//API
|
||||
import { SwitchStatus } from "@/api/common";
|
||||
export default {
|
||||
name: 'SwitchComponent',
|
||||
props: {
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup(props){
|
||||
// 配置信息
|
||||
const config = reactive(props.config);
|
||||
// 数据
|
||||
const data = reactive(props.data);
|
||||
// 初始值
|
||||
const init_data = reactive({
|
||||
value: data[config.prop],
|
||||
loading: false
|
||||
});
|
||||
// 获取实例上下文
|
||||
const { proxy } = getCurrentInstance();
|
||||
// 事件
|
||||
const handlerSwitch = (value) => {
|
||||
// 请求参数
|
||||
const key_id = config.key_id;
|
||||
if(!key_id) { return false; }
|
||||
init_data.loading = true;
|
||||
// 参数
|
||||
const request_data = {
|
||||
url: config.api_url || ApiUrl[config.api_module][config.api_module_key],
|
||||
method: config.method || "post",
|
||||
data: {
|
||||
[key_id]: data[key_id], // 等价于["id"]: data["id"]
|
||||
[config.prop]: value // 等价于["status"]: value
|
||||
}
|
||||
}
|
||||
// 接口请求
|
||||
SwitchStatus(request_data).then(response => {
|
||||
proxy.$message.success(response.message);
|
||||
init_data.value = value;
|
||||
init_data.loading = false;
|
||||
}).catch(error => {
|
||||
init_data.loading = false;
|
||||
})
|
||||
}
|
||||
return { config, init_data, handlerSwitch }
|
||||
}
|
||||
}
|
||||
</script>
|
39
企业级管理系统/web/项目源码/src/components/table/configHook.js
Normal file
39
企业级管理系统/web/项目源码/src/components/table/configHook.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import { reactive } from "vue";
|
||||
/**
|
||||
* BasisTable组件默认配置
|
||||
* @param { Boolean } selection 多选项配置
|
||||
* @param { Boolean } batch_delete 指量删除按钮
|
||||
* @param { Boolean } pagination 分页
|
||||
*/
|
||||
export function configHook(){
|
||||
const config = reactive({
|
||||
selection: true,
|
||||
batch_delete: true,
|
||||
pagination: true,
|
||||
request: true,
|
||||
search: true,
|
||||
action_request: false,
|
||||
row_key: "id",
|
||||
expand_all: true,
|
||||
has_button_delete: "",
|
||||
has_button_batch_delete: ""
|
||||
})
|
||||
/**
|
||||
*
|
||||
* @param {*} data 配置额外组件,true显示,false不显示
|
||||
*/
|
||||
const configInit = (data = {}) => {
|
||||
// 无数据时不执行
|
||||
if(JSON.stringify(data) === "{}") { return false; }
|
||||
// 获取默认配置项的所有key
|
||||
const keys = Object.keys(config);
|
||||
// 循环传入的配置项
|
||||
for(let key in data) {
|
||||
// 过滤原型链的对象
|
||||
if (!data.hasOwnProperty(key)) { continue; }
|
||||
// ES6语法判断传入的key和默认配置的key相同时,则直接更新默认配置项的值
|
||||
if(keys.includes(key)) { config[key] = data[key]; }
|
||||
}
|
||||
}
|
||||
return { config, configInit };
|
||||
}
|
121
企业级管理系统/web/项目源码/src/components/table/index.vue
Normal file
121
企业级管理系统/web/项目源码/src/components/table/index.vue
Normal file
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<SearchForm v-if="config.search" @callbackSearch="getList" />
|
||||
<el-table :row-key="config.row_key" :default-expand-all="config.expand_all" :data="table_data.data" v-loading="table_data.loading" element-loading-text="加载中,请稍候" border style="width: 100%" @selection-change="handleSelectionChange">
|
||||
<el-table-column v-if="config.selection" type="selection" width="40"></el-table-column>
|
||||
<template v-for="header in data.render_header" :key="header.prop">
|
||||
<!-- switch -->
|
||||
<el-table-column v-if="header.type === 'switch'" :label="header.label" :width="header.width">
|
||||
<template #default="scope">
|
||||
<Switch :data="scope.row" :config="header" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- function -->
|
||||
<el-table-column v-else-if="header.type === 'function'" :label="header.label" :width="header.width">
|
||||
<template #default="scope">
|
||||
<div v-html="header.callback && header.callback(scope.row)"></div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- slot -->
|
||||
<el-table-column v-else-if="header.type === 'slot'" :label="header.label" :width="header.width">
|
||||
<template #default="scope">
|
||||
<slot :name="header.slot_name" :data="scope.row"></slot>
|
||||
<el-button v-if="header.delete_elem" @click="handlerDelete('delete', scope.row)" v-has-button="config.has_button_delete">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- text -->
|
||||
<el-table-column v-else :prop="header.prop" :label="header.label" :width="header.width"></el-table-column>
|
||||
</template>
|
||||
</el-table>
|
||||
<el-row class="margin-top-20">
|
||||
<el-col :span="6">
|
||||
<el-button v-if="config.batch_delete" :disabled="!table_data.data_id" @click="handlerDelete('batch')" v-has-button="config.has_button_batch_delete">批量删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="18">
|
||||
<Pagination
|
||||
v-if="config.pagination"
|
||||
@sizeChange="getList"
|
||||
@currentChange="getList"
|
||||
:total="table_data.total"
|
||||
:current="table_data.current_page" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive, getCurrentInstance, onBeforeMount, watch } from 'vue';
|
||||
// store
|
||||
import { useStore } from "vuex";
|
||||
// components
|
||||
import SearchForm from "@c/search";
|
||||
import Pagination from "@c/pagination";
|
||||
import Switch from "@c/control/switch";
|
||||
// hook
|
||||
import { configHook } from "./configHook";
|
||||
import { requestHook } from "./requestHook";
|
||||
export default {
|
||||
name: 'TableComponents',
|
||||
components: { Pagination, Switch, SearchForm },
|
||||
props: {
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => ([])
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
request: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
},
|
||||
search: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
emits: ["onload"],
|
||||
setup(props, { emit }){
|
||||
// store
|
||||
const store = useStore();
|
||||
// 获取实例上下文
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { config, configInit } = configHook();
|
||||
const { requestData, table_data, handlerDeleteComfirm, saveDataId } = requestHook();
|
||||
const data = reactive({
|
||||
table_data: [],
|
||||
render_header: props.columns,
|
||||
row_data_id: [],
|
||||
currentPage: 0,
|
||||
total: 0
|
||||
})
|
||||
onBeforeMount(() => {
|
||||
// 默认配置项处理
|
||||
configInit(props.config);
|
||||
// 请求数据
|
||||
getList(props.request)
|
||||
})
|
||||
|
||||
const getList = (params, type) => {
|
||||
requestData(params, type).then(response => {
|
||||
emit("onload", table_data);
|
||||
});
|
||||
}
|
||||
/** 删除动作 */
|
||||
const handlerDelete = (type, val) => {
|
||||
if(type === "delete") { saveDataId(val); }
|
||||
handlerDeleteComfirm();
|
||||
}
|
||||
/** 复选框事件 */
|
||||
const handleSelectionChange = (val) => {
|
||||
saveDataId(val);
|
||||
}
|
||||
watch(() => store.state.app.table_action_request, () => {
|
||||
config.action_request && getList();
|
||||
})
|
||||
return { data, config, table_data, requestData, getList, handlerDelete, handleSelectionChange }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
.margin-top-20 { margin-top: 20px; }
|
||||
</style>
|
154
企业级管理系统/web/项目源码/src/components/table/requestHook.js
Normal file
154
企业级管理系统/web/项目源码/src/components/table/requestHook.js
Normal file
@@ -0,0 +1,154 @@
|
||||
import { reactive, getCurrentInstance } from "vue";
|
||||
// requestUrl
|
||||
import ApiUrl from "@/api/requestUrl";
|
||||
// API
|
||||
import { TableData, CommonApi } from "@/api/common";
|
||||
import { configHook } from "./configHook";
|
||||
import { ElMessage } from "element-plus"
|
||||
export function requestHook(){
|
||||
const { config, configInit } = configHook();
|
||||
|
||||
// 获取实例上下文
|
||||
const { proxy } = getCurrentInstance();
|
||||
let request_config = {
|
||||
has: true, // 是否请求
|
||||
url: "", // 请求模块
|
||||
method: "post", // 请求类型
|
||||
data: {}, // 请求参数
|
||||
delete_key: '', // 删除接口的KEY
|
||||
search_params: {}
|
||||
}
|
||||
const table_data = reactive({
|
||||
data: [],
|
||||
data_id: "",
|
||||
current_page: 0,
|
||||
total: 0,
|
||||
loading: false
|
||||
})
|
||||
/**
|
||||
* @returns 列表数据请求
|
||||
*/
|
||||
const loadData = () => {
|
||||
// 判断条件是否请求接口
|
||||
if(!request_config.has) { return false; }
|
||||
if(!request_config.url) { return false; }
|
||||
// 参数
|
||||
const url = ApiUrl[request_config.url]?.list?.url;
|
||||
const method = ApiUrl[request_config.url]?.list?.method || 'post';
|
||||
const data = { ...request_config.data, ...request_config.search_params };
|
||||
if(!url) {
|
||||
console.log("请求地址不存在");
|
||||
return Promise.reject();
|
||||
}
|
||||
const request_data = {
|
||||
url,
|
||||
method,
|
||||
data
|
||||
}
|
||||
// 加载状态
|
||||
table_data.loading = true;
|
||||
return new Promise((resolve, reject) => {
|
||||
TableData(request_data).then(response => {
|
||||
|
||||
let response_data = response.data.data;
|
||||
// 是否格式化数据
|
||||
if(request_config.format_data && Object.prototype.toString.call(request_config.format_data) === "[object Function]") {
|
||||
response_data = request_config.format_data(response.data.data);
|
||||
}
|
||||
|
||||
console.log(response_data)
|
||||
|
||||
table_data.data = response_data;
|
||||
table_data.total = response.data.total;
|
||||
table_data.current_page = response.data.current_page;
|
||||
// 取消加载状态
|
||||
table_data.loading = false;
|
||||
resolve(response.data);
|
||||
}).catch(error => {
|
||||
reject()
|
||||
// 取消加载状态
|
||||
table_data.loading = false;
|
||||
})
|
||||
})
|
||||
}
|
||||
const requestData = (data = {}, type = 'init') => {
|
||||
// 初始化逻辑
|
||||
if(type === "init") {
|
||||
request_config = {...request_config, ...data};
|
||||
}
|
||||
// 分页逻辑
|
||||
if(type === 'page') {
|
||||
request_config.data = {...request_config.data, ...data};
|
||||
}
|
||||
// 搜索
|
||||
if(type === "search"){
|
||||
request_config.data.pageNumber = 1;
|
||||
request_config.data.pageSize = 10;
|
||||
request_config.search_params = data;
|
||||
}
|
||||
// 请求数据
|
||||
return loadData();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {Object} data
|
||||
* @description 手动请求
|
||||
*/
|
||||
const handlerRequestData = (data = {}) => {
|
||||
table_data.params_data = data;
|
||||
loadData();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param { String、Array } value
|
||||
* @description 存储数据ID,作用于删除接口使用
|
||||
* 删除接口
|
||||
*/
|
||||
const saveDataId = (value) => {
|
||||
const isArray = Array.isArray(value);
|
||||
if(!isArray) {
|
||||
table_data.data_id = value[request_config.delete_key];
|
||||
}else{
|
||||
table_data.data_id = value.length > 0 ? value.map(item => item[request_config.delete_key]).join() : "";
|
||||
}
|
||||
console.log(table_data.data_id)
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @description 删除动作的确认弹窗
|
||||
*/
|
||||
const handlerDeleteComfirm = () => {
|
||||
proxy.deleteConfirm({
|
||||
title: "删除",
|
||||
message: "确认删除当前数据吗?",
|
||||
thenFun: () => { handlerDelete(); }
|
||||
});
|
||||
}
|
||||
const handlerDelete = () => {
|
||||
const url = ApiUrl?.[request_config.url]?.delete?.url
|
||||
const method = ApiUrl?.[request_config.url]?.delete?.method || "post"
|
||||
if(!url) {
|
||||
console.log("未配置删除接口参数");
|
||||
return false;
|
||||
}
|
||||
// 参数
|
||||
const request_data = {
|
||||
url,
|
||||
method: method,
|
||||
data: { [request_config.delete_key]: table_data.data_id },
|
||||
}
|
||||
CommonApi(request_data).then(response => {
|
||||
// 成功提示
|
||||
proxy.$message({
|
||||
message: response.message,
|
||||
type: "success"
|
||||
})
|
||||
loadData();
|
||||
table_data.data_id = "";
|
||||
proxy.deleteConfirmClose();
|
||||
}).catch(error => {
|
||||
proxy.confirmButtonLoading(false);
|
||||
})
|
||||
}
|
||||
return { table_data, requestData, handlerDelete, saveDataId, handlerDeleteComfirm };
|
||||
}
|
67
企业级管理系统/web/项目源码/src/components/wangeditor/index.vue
Normal file
67
企业级管理系统/web/项目源码/src/components/wangeditor/index.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div ref="editor"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import WangEditor from 'wangeditor';
|
||||
// cookies
|
||||
import { getToken } from "@/utils/cookies"; // 这是封装好的方法
|
||||
export default {
|
||||
name: 'Wangeditor',
|
||||
components: {},
|
||||
props: {
|
||||
content: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
},
|
||||
emits: ["update:content"],
|
||||
setup(props, { emit }){
|
||||
let html = ref(null)
|
||||
// 内容
|
||||
let content = ref();
|
||||
// 富文本DOM元素
|
||||
const editor = ref();
|
||||
// 富文本对象
|
||||
let editor_instance = null;
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
// 创建富文本对象
|
||||
editor_instance = new WangEditor(editor.value);
|
||||
// 图片上传配置
|
||||
editor_instance.config.uploadImgServer = process.env.VUE_APP_DEV_TARGET + '/upload' // 上传图片的接口地址
|
||||
editor_instance.config.uploadFileName = 'files' // formdata中的name属性
|
||||
editor_instance.config.uploadImgHeaders = {
|
||||
Token: getToken() // 设置请求头
|
||||
}
|
||||
editor_instance.config.uploadImgHooks = {
|
||||
// 图片上传并返回结果,但图片插入错误时触发
|
||||
fail: function (xhr, editor, result) {
|
||||
console.log(result)
|
||||
},
|
||||
// 例如服务器端返回的不是 { errno: 0, data: [...] } 这种格式,可使用 customInsert
|
||||
customInsert: function(insertImgFn, result) {
|
||||
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
|
||||
insertImgFn(result.data.files_path)
|
||||
}
|
||||
}
|
||||
// 配置change事件
|
||||
Object.assign(editor_instance.config, {
|
||||
onchange(value) {
|
||||
content.value = value;
|
||||
emit("update:content", value);
|
||||
},
|
||||
});
|
||||
// 创建
|
||||
editor_instance.create();
|
||||
})
|
||||
watch(() => props.content, (newContent, oldContent) => {
|
||||
editor_instance.txt.html(newContent);
|
||||
})
|
||||
return { editor }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang='scss' scoped>
|
||||
</style>
|
Reference in New Issue
Block a user