@xilonglab/vue-main 0.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/page/app.vue +86 -0
  2. package/dist/page/login.vue +185 -0
  3. package/dist/page/setting.vue +72 -0
  4. package/dist/style/app.less +58 -0
  5. package/dist/style/reset.css +32 -0
  6. package/package.json +15 -0
  7. package/packages/XlBreadcrumb.vue +85 -0
  8. package/packages/XlControlBar.vue +64 -0
  9. package/packages/XlSideBar.vue +135 -0
  10. package/packages/button/XlAsyncButton.vue +67 -0
  11. package/packages/button/XlButton.vue +25 -0
  12. package/packages/button/XlDeleteButton.vue +22 -0
  13. package/packages/button/XlEditButton.vue +22 -0
  14. package/packages/button/XlIconButton.vue +22 -0
  15. package/packages/button/XlUploadButton.vue +109 -0
  16. package/packages/dialog/XlDialog.vue +116 -0
  17. package/packages/dialog/XlEditReviewDialog.vue +81 -0
  18. package/packages/dialog/XlFormDialog.vue +79 -0
  19. package/packages/dialog/XlImagePreviewDialog.vue +40 -0
  20. package/packages/dialog/XlMessageDialog.vue +74 -0
  21. package/packages/dialog/XlReviewDialog.vue +115 -0
  22. package/packages/dialog/XlStateDialog.vue +21 -0
  23. package/packages/form/XlCascader.vue +46 -0
  24. package/packages/form/XlCheckbox.vue +45 -0
  25. package/packages/form/XlDate.vue +54 -0
  26. package/packages/form/XlFormCol.vue +19 -0
  27. package/packages/form/XlFormRow.vue +20 -0
  28. package/packages/form/XlImageInput.vue +127 -0
  29. package/packages/form/XlInput.vue +53 -0
  30. package/packages/form/XlMapSelect.vue +72 -0
  31. package/packages/form/XlNumber.vue +11 -0
  32. package/packages/form/XlRadio.vue +42 -0
  33. package/packages/form/XlRawSelect.vue +71 -0
  34. package/packages/form/XlRegion.vue +51 -0
  35. package/packages/form/XlSearchSelect.vue +85 -0
  36. package/packages/form/XlSelect.vue +77 -0
  37. package/packages/form/XlSwitch.vue +33 -0
  38. package/packages/form/XlTabRadio.vue +43 -0
  39. package/packages/form/XlTags.vue +105 -0
  40. package/packages/form/XlTextarea.vue +48 -0
  41. package/packages/form/XlTime.vue +50 -0
  42. package/packages/form/data/areas.json +1 -0
  43. package/packages/index.js +130 -0
  44. package/packages/main/XlAutoSaver.vue +75 -0
  45. package/packages/main/XlDataView.vue +212 -0
  46. package/packages/main/XlFormDialog2.vue +80 -0
  47. package/packages/main/XlLoginForm.vue +192 -0
  48. package/packages/main/XlNavBar.vue +89 -0
  49. package/packages/main/XlStatusIndicator.vue +36 -0
  50. package/packages/main/XlTabView.vue +81 -0
  51. package/packages/main/XlToolBar.vue +132 -0
  52. package/packages/main/XlUpdateIndicator.vue +40 -0
  53. package/packages/main/XlVerticalMenu.vue +72 -0
@@ -0,0 +1,130 @@
1
+ import XlSideBar from './XlSideBar.vue'
2
+ import XlControlBar from './XlControlBar.vue'
3
+ import XlBreadcrumb from './XlBreadcrumb.vue'
4
+
5
+ // Button Components
6
+ import XlAsyncButton from './button/XlAsyncButton.vue'
7
+ import XlButton from './button/XlButton.vue'
8
+ import XlDeleteButton from './button/XlDeleteButton.vue'
9
+ import XlEditButton from './button/XlEditButton.vue'
10
+ import XlIconButton from './button/XlIconButton.vue'
11
+ import XlUploadButton from './button/XlUploadButton.vue'
12
+
13
+ // Form Components
14
+ import XlCascader from './form/XlCascader.vue'
15
+ import XlCheckbox from './form/XlCheckbox.vue'
16
+ import XlDate from './form/XlDate.vue'
17
+ import XlFormCol from './form/XlFormCol.vue'
18
+ import XlFormRow from './form/XlFormRow.vue'
19
+ import XlImageInput from './form/XlImageInput.vue'
20
+ import XlInput from './form/XlInput.vue'
21
+ import XlMapSelect from './form/XlMapSelect.vue'
22
+ import XlNumber from './form/XlNumber.vue'
23
+ import XlRadio from './form/XlRadio.vue'
24
+ import XlRawSelect from './form/XlRawSelect.vue'
25
+ import XlRegion from './form/XlRegion.vue'
26
+ import XlSearchSelect from './form/XlSearchSelect.vue'
27
+ import XlSelect from './form/XlSelect.vue'
28
+ import XlSwitch from './form/XlSwitch.vue'
29
+ import XlTabRadio from './form/XlTabRadio.vue'
30
+ import XlTags from './form/XlTags.vue'
31
+ import XlTextarea from './form/XlTextarea.vue'
32
+ import XlTime from './form/XlTime.vue'
33
+
34
+ // Dialog Components
35
+ import XlDialog from './dialog/XlDialog.vue'
36
+ import XlFormDialog from './dialog/XlFormDialog.vue'
37
+ import XlStateDialog from './dialog/XlStateDialog.vue'
38
+ import XlEditReviewDialog from './dialog/XlEditReviewDialog.vue'
39
+ import XlImagePreviewDialog from './dialog/XlImagePreviewDialog.vue'
40
+ import XlMessageDialog from './dialog/XlMessageDialog.vue'
41
+ import XlReviewDialog from './dialog/XlReviewDialog.vue'
42
+
43
+ // Main Components
44
+ import XlDataView from './main/XlDataView.vue'
45
+ import XlFormDialog2 from './main/XlFormDialog2.vue'
46
+ import XlNavBar from './main/XlNavBar.vue'
47
+ import XlTabView from './main/XlTabView.vue'
48
+ import XlToolBar from './main/XlToolBar.vue'
49
+ import XlVerticalMenu from './main/XlVerticalMenu.vue'
50
+ import XlStatusIndicator from './main/XlStatusIndicator.vue'
51
+ import XlUpdateIndicator from './main/XlUpdateIndicator.vue'
52
+ import XlAutoSaver from './main/XlAutoSaver.vue'
53
+ import XlLoginForm from './main/XlLoginForm.vue'
54
+
55
+ const components = [
56
+ XlSideBar,
57
+ XlControlBar,
58
+ XlBreadcrumb,
59
+ // Buttons
60
+ XlAsyncButton,
61
+ XlButton,
62
+ XlDeleteButton,
63
+ XlEditButton,
64
+ XlIconButton,
65
+ XlUploadButton,
66
+ // Forms
67
+ XlCascader,
68
+ XlCheckbox,
69
+ XlDate,
70
+ XlFormCol,
71
+ XlFormRow,
72
+ XlImageInput,
73
+ XlInput,
74
+ XlMapSelect,
75
+ XlNumber,
76
+ XlRadio,
77
+ XlRawSelect,
78
+ XlRegion,
79
+ XlSearchSelect,
80
+ XlSelect,
81
+ XlSwitch,
82
+ XlTabRadio,
83
+ XlTags,
84
+ XlTextarea,
85
+ XlTime,
86
+ // Dialogs
87
+ XlDialog,
88
+ XlFormDialog,
89
+ XlStateDialog,
90
+ XlEditReviewDialog,
91
+ XlImagePreviewDialog,
92
+ XlMessageDialog,
93
+ XlReviewDialog,
94
+ // Main Components
95
+ XlDataView,
96
+ XlFormDialog2,
97
+ XlNavBar,
98
+ XlTabView,
99
+ XlToolBar,
100
+ XlVerticalMenu,
101
+ XlStatusIndicator,
102
+ XlUpdateIndicator,
103
+ XlAutoSaver,
104
+ XlLoginForm
105
+ ];
106
+
107
+ const install = (app) => {
108
+ components.forEach((component) => {
109
+ app.component(component.name, component);
110
+ });
111
+ };
112
+
113
+ let componentsJson = {}
114
+ components.forEach(component => {
115
+ const componentName = component.name
116
+ component.install = function (app) {
117
+ app.component(componentName, component)
118
+ }
119
+ componentsJson[componentName] = component
120
+ })
121
+
122
+
123
+ if (typeof window !== 'undefined' && window.Vue) {
124
+ install(window.Vue)
125
+ }
126
+
127
+ export default {
128
+ install,
129
+ ...componentsJson
130
+ }
@@ -0,0 +1,75 @@
1
+ <script setup>
2
+ defineOptions({ name: "XlAutoSaver" })
3
+
4
+ import { reactive } from 'vue'
5
+
6
+
7
+ const props = defineProps({
8
+ api: {
9
+ type: Function,
10
+ default: async () => { }
11
+ },
12
+ disabled: {
13
+ type: Boolean,
14
+ default: false,
15
+ },
16
+ })
17
+
18
+ const state = reactive({
19
+ saving: false,
20
+ lastUpdateTime: null
21
+ })
22
+
23
+ async function onBlur() {
24
+ let { api, disabled } = props;
25
+ if (disabled) {
26
+ return;
27
+ }
28
+ state.saving = true;
29
+ const code = await api();
30
+ state.saving = false;
31
+ if (code == 1) {
32
+ state.lastUpdateTime = new Date();
33
+ }
34
+ }
35
+
36
+ async function onClick() {
37
+ const { api, disabled } = props;
38
+ if (disabled) {
39
+ return;
40
+ }
41
+ let now = new Date();
42
+ let lapse = state.lastUpdateTime ? now - state.lastUpdateTime : 3500;
43
+ if (lapse > 3000 && !state.saving) {
44
+ state.saving = true;
45
+ try {
46
+ const code = await api();
47
+ if (code == 1) {
48
+ state.lastUpdateTime = new Date();
49
+ }
50
+ } catch (error) {
51
+ console.error('Auto save failed:', error);
52
+ } finally {
53
+ state.saving = false;
54
+ }
55
+ }
56
+ }
57
+
58
+
59
+ defineExpose({
60
+ state
61
+ })
62
+ </script>
63
+
64
+ <template>
65
+ <div class="xl-auto-saver" @mouseleave="onBlur" @click="onClick">
66
+ <slot />
67
+ </div>
68
+ </template>
69
+
70
+ <style lang="less">
71
+ .xl-auto-saver {
72
+ display: flex;
73
+ flex-flow: column;
74
+ }
75
+ </style>
@@ -0,0 +1,212 @@
1
+ <script setup>
2
+ defineOptions({ name: "XlDataView" })
3
+
4
+ import { inject, computed } from 'vue'
5
+
6
+ const props = defineProps({
7
+ selectable: {
8
+ type: Boolean,
9
+ default: false,
10
+ },
11
+ columns: {
12
+ type: Array,
13
+ default: () => [],
14
+ },
15
+ showSummary: {
16
+ type: Boolean,
17
+ default: true,
18
+ },
19
+ rowClick: {
20
+ type: Function,
21
+ default: () => { },
22
+ },
23
+ summaryMethod: {
24
+ type: Function,
25
+ },
26
+ showIndex: {
27
+ type: Boolean,
28
+ default: false,
29
+ },
30
+ disableAdd: {
31
+ type: Boolean,
32
+ default: false,
33
+ },
34
+ pagination: {
35
+ type: Object,
36
+ default() {
37
+ return {
38
+ pageNum: 1,
39
+ pageSize: 20,
40
+ total: 0,
41
+ };
42
+ },
43
+ },
44
+ spanMethod: {
45
+ type: Function,
46
+ default: () => { },
47
+ },
48
+ headerCellStyle: {
49
+ type: Function,
50
+ default: () => { },
51
+ },
52
+ rowClassName: {
53
+ type: Function,
54
+ default: () => { },
55
+ },
56
+ rowKey: {
57
+ type: Function,
58
+ default: () => { },
59
+ },
60
+ rowDblClick: {
61
+ type: Function,
62
+ default: () => { },
63
+ },
64
+ selectionChange: {
65
+ type: Function,
66
+ default: () => { },
67
+ },
68
+ layout: {
69
+ type: String,
70
+ default: 'prev, pager, next, jumper'
71
+ },
72
+ small: {
73
+ type: Boolean,
74
+ default: false
75
+ },
76
+ chinese: {
77
+ type: String,
78
+ default: ''
79
+ },
80
+ english: {},
81
+ type: {
82
+ type: String,
83
+ default: ''
84
+ },
85
+ width: {
86
+ default: 70
87
+ },
88
+ labelWidth: {
89
+ default: 90
90
+ },
91
+ callback: {
92
+ type: Function,
93
+ default: () => { },
94
+ },
95
+ });
96
+
97
+ const { refs, api, params, obj, chartOptions, total } = inject('injections')
98
+ </script>
99
+
100
+
101
+ <template>
102
+ <div :class="['xl-data-view', english]">
103
+ <xl-tool-bar :type="type" :table="refs.table" :params="params" @query="() => api.stat()">
104
+ <template #inputs>
105
+ <template v-for="col in columns" :key="col.prop">
106
+ <template v-if="col.search">
107
+ <component
108
+ :is="`xl-${col.search.type || 'input'}`"
109
+ :placeholder="col.label"
110
+ v-model="params[col.prop]"
111
+ v-bind="col.search || {}"
112
+ />
113
+ </template>
114
+ </template>
115
+ <slot name="inputs" />
116
+ </template>
117
+ <template #buttons>
118
+ <slot name="buttons" />
119
+ <el-button class="add-btn" v-if="!disableAdd" type="success" @click="() => api.onAdd()">新增</el-button>
120
+ </template>
121
+ </xl-tool-bar>
122
+ <xl-query-page-table v-show="params.view != 'chart'" :ref="refs.table" :api="api" :params="params"
123
+ v-bind="$props" :summary-method="summaryMethod?summaryMethod:()=>({0:total})" :sort-change="(data) => api.sort(data)">
124
+ <template v-for="col in columns" :key="col.prop">
125
+ <template v-if="!col.hidden">
126
+ <xl-datetime-col
127
+ v-if="col.type === 'datetime'"
128
+ :l="col.label"
129
+ :p="col.prop"
130
+ />
131
+ <xl-map-col
132
+ v-else-if="col.type === 'map'"
133
+ :l="col.label"
134
+ :p="col.prop"
135
+ :width="col.width"
136
+ :map="col.map"
137
+ />
138
+ <xl-status-col
139
+ v-else-if="col.type === 'status'"
140
+ :l="col.label"
141
+ :p="col.prop"
142
+ :map="col.map"
143
+ />
144
+ <xl-review-col
145
+ v-else-if="col.type === 'review'"
146
+ :l="col.label"
147
+ :p="col.prop"
148
+ />
149
+ <xl-clamp-col
150
+ v-else-if="col.type === 'clamp'"
151
+ :l="col.label"
152
+ :p="col.prop"
153
+ :width="col.width"
154
+ />
155
+ <xl-bool-col
156
+ v-else-if="col.type === 'bool'"
157
+ :l="col.label"
158
+ :p="col.prop"
159
+ :width="col.width"
160
+ />
161
+ <xl-col
162
+ v-else
163
+ :l="col.label"
164
+ :p="col.prop"
165
+ :width="col.width"
166
+ />
167
+ </template>
168
+ </template>
169
+ <slot name="columns" />
170
+ </xl-query-page-table>
171
+ <xl-chart v-show="params.view == 'chart'" :options="chartOptions" />
172
+ <xl-form-dialog-2
173
+ :ref="refs.editDialog"
174
+ :title="chinese"
175
+ :width="width"
176
+ :label-width="labelWidth"
177
+ :data="obj"
178
+ :columns="columns"
179
+ :callback="callback"
180
+ >
181
+ <el-row>
182
+ <template v-for="col in columns" :key="col.prop">
183
+ <xl-form-col
184
+ v-if="col.form"
185
+ :span="col.form.span"
186
+ :l="col.label"
187
+ :p="col.prop"
188
+ >
189
+ <component
190
+ :is="`xl-${col.form.type || 'input'}`"
191
+ v-model="obj[col.prop]"
192
+ v-bind="col.form || {}"
193
+ />
194
+ </xl-form-col>
195
+ </template>
196
+ </el-row>
197
+ <slot name="items" />
198
+ </xl-form-dialog-2>
199
+ <slot name="others" />
200
+ <xl-message-dialog :ref="refs.deleteDialog" message="确认删除?" @confirm="() => api.delete()" />
201
+ </div>
202
+ </template>
203
+
204
+
205
+ <style lang="less">
206
+ .xl-data-view {
207
+ div.cell {
208
+ padding: 0 !important;
209
+
210
+ }
211
+ }
212
+ </style>
@@ -0,0 +1,80 @@
1
+ <script setup>
2
+ defineOptions({ name: "XlFormDialog2" })
3
+
4
+ import { ref, computed } from 'vue'
5
+
6
+
7
+ const emits = defineEmits(['confirm', 'finish'])
8
+
9
+ const props = defineProps({
10
+ title: {},
11
+ width: {},
12
+ data: {},
13
+ columns: {
14
+ default() {
15
+ return []
16
+ }
17
+ },
18
+ labelWidth: {
19
+ default: 70
20
+ },
21
+ callback: {
22
+ type: Function,
23
+ default: () => { },
24
+ }
25
+ })
26
+
27
+ const refs = {
28
+ dialog: ref(null),
29
+ form: ref(null),
30
+ }
31
+
32
+ const convertColumnsToRules = (columns) => {
33
+ const rules = {};
34
+ columns.forEach(col => {
35
+ if (col.form?.required) {
36
+ rules[col.prop] = [{
37
+ required: true,
38
+ message: `请输入${col.label}`,
39
+ trigger: "blur"
40
+ }];
41
+ }
42
+ });
43
+ return rules;
44
+ };
45
+
46
+ const rules = computed(() => convertColumnsToRules(props.columns));
47
+
48
+ async function validate() {
49
+ let flag = 0
50
+ await refs.form.value.validate(function (valid) {
51
+ flag = valid
52
+ })
53
+ return flag
54
+ }
55
+
56
+ defineExpose({
57
+ show() {
58
+ refs.dialog.value.show()
59
+ }
60
+ })
61
+ </script>
62
+
63
+
64
+ <template>
65
+ <xl-dialog class="xl-edit-dialog" :ref="refs.dialog" :title="title" :width="width" :validate="validate"
66
+ :callback="callback" @finish="emits('finish')">
67
+ <el-form :ref="refs.form" :model="data" :rules="rules" :label-width="`${labelWidth}px`">
68
+ <slot />
69
+ </el-form>
70
+ </xl-dialog>
71
+ </template>
72
+
73
+
74
+ <style lang="less">
75
+ .xl-edit-dialog {
76
+ .xl-form-item {
77
+ width: 100% !important;
78
+ }
79
+ }
80
+ </style>
@@ -0,0 +1,192 @@
1
+ <script setup>
2
+ defineOptions({ name: "XlLoginForm" })
3
+
4
+ import { ref, reactive, computed, onMounted } from 'vue'
5
+
6
+
7
+ const props = defineProps({
8
+ scope: {
9
+ type: Object,
10
+ default() {
11
+ return {}
12
+ },
13
+ }
14
+ });
15
+
16
+ const emits = defineEmits(['login', 'keyEnter'])
17
+
18
+
19
+ const rules = {
20
+ name: [
21
+ { required: true, message: '请输入用户名', trigger: 'blur' }
22
+ ],
23
+ password: [
24
+ { required: true, message: '请输入密码', trigger: 'blur' }
25
+ ],
26
+ captcha: [
27
+ { required: true, message: "请输入验证码", trigger: "blur" },
28
+ ],
29
+ };
30
+
31
+
32
+ const loginForm = ref(null)
33
+
34
+ const form = reactive({
35
+ name: "",
36
+ password: "",
37
+ captcha: "",
38
+ uuid: "",
39
+ })
40
+ const nameError = ref('')
41
+ const passwordError = ref('')
42
+ const captchaError = ref('')
43
+ const captchaUrl = computed(() => {
44
+ return `/api/system/captcha?uuid=${form.uuid}`
45
+ })
46
+
47
+ function getUUID() {
48
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
49
+ return (c === 'x' ? (Math.random() * 16 | 0) : ('r&0x3' | '0x8')).toString(16)
50
+ })
51
+ }
52
+
53
+ async function validate() {
54
+ let flag = true
55
+ await loginForm.value.validate(valid => {
56
+ flag = valid
57
+ })
58
+ return flag
59
+ }
60
+
61
+ const Captcha = {
62
+ refresh() {
63
+ form.uuid = getUUID();
64
+ }
65
+ }
66
+
67
+ const Cookie = {
68
+ get() {
69
+ if (document.cookie.length > 0) {
70
+ let arr = document.cookie.split("; ");
71
+ for (let i = 0; i < arr.length; i++) {
72
+ let arr2 = arr[i].split("=");
73
+ if (arr2[0] == "name") {
74
+ form.name = arr2[1];
75
+ } else if (arr2[0] == "password") {
76
+ form.password = arr2[1];
77
+ props.scope.isRemember = true;
78
+ }
79
+ }
80
+ }
81
+ },
82
+ delete(cookiename) {
83
+ let d = new Date();
84
+ d.setDate(d.getDate() - 1);
85
+ let expires = ";expires=" + d;
86
+ let name = cookiename;
87
+ let value = "";
88
+ document.cookie = name + "=" + value + expires + "; ";
89
+ },
90
+ set() {
91
+ let { name, password } = form;
92
+ if (props.scope.isRemember) {
93
+ document.cookie = `name=${name}`;
94
+ document.cookie = `password=${password}`;
95
+ } else {
96
+ Cookie.delete("password");
97
+ }
98
+ }
99
+ }
100
+
101
+
102
+ const Error = {
103
+ reset() {
104
+ nameError.value = "";
105
+ passwordError.value = "";
106
+ captchaError.value = "";
107
+ },
108
+ user() {
109
+ this.reset()
110
+ nameError.value = "用户不存在";
111
+ },
112
+ password() {
113
+ this.reset()
114
+ passwordError.value = "密码错误";
115
+ },
116
+ captcha() {
117
+ this.reset()
118
+ captchaError.value = "验证码错误";
119
+ },
120
+ }
121
+
122
+ onMounted(() => {
123
+ Cookie.get()
124
+ Captcha.refresh()
125
+ })
126
+
127
+ defineExpose({ form, Captcha, Cookie, Error, validate })
128
+ </script>
129
+
130
+
131
+ <template>
132
+ <el-form class="xl-login-form" ref="loginForm" :model="form" :rules="rules" @keyup.enter="emits('keyEnter')">
133
+ <el-form-item prop="name" :error="nameError">
134
+ <el-input v-model="form.name" placeholder="用户名">
135
+ <template #prepend>
136
+ <el-icon>
137
+ <User />
138
+ </el-icon>
139
+ </template>
140
+ </el-input>
141
+ </el-form-item>
142
+ <el-form-item prop="password" :error="passwordError">
143
+ <el-input type="password" v-model="form.password" placeholder="密码">
144
+ <template #prepend>
145
+ <el-icon>
146
+ <Lock />
147
+ </el-icon>
148
+ </template>
149
+ </el-input>
150
+ </el-form-item>
151
+ <el-form-item class="captcha" prop="captcha" :error="captchaError">
152
+ <el-input v-model="form.captcha" type="number" size="large" placeholder="验证码">
153
+ <template #prepend>
154
+ <el-icon>
155
+ <CircleCheck />
156
+ </el-icon>
157
+ </template>
158
+ </el-input>
159
+ <img :src="captchaUrl" @click="Captcha.refresh" alt="验证码" />
160
+ </el-form-item>
161
+ </el-form>
162
+ </template>
163
+
164
+
165
+ <style lang="less">
166
+ .xl-login-form {
167
+ .el-input{
168
+ height:40px;
169
+ }
170
+ .captcha {
171
+ width: 100%;
172
+
173
+ .el-form-item__content {
174
+ width: 100%;
175
+ display: flex;
176
+
177
+ .el-input {
178
+ flex: 3;
179
+ }
180
+
181
+ img {
182
+ flex: 2;
183
+ border: 1px solid rgb(220, 220, 220);
184
+ width: 152px;
185
+ height: 40px;
186
+ margin-left: 10px;
187
+ }
188
+ }
189
+
190
+ }
191
+ }
192
+ </style>