@yxhl/specter-pui-vtk 1.0.0
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.
- package/README.md +122 -0
- package/dist/specter-pui-vtk.css +1 -0
- package/dist/specter-pui.es.js +3289 -0
- package/dist/specter-pui.es.js.map +1 -0
- package/dist/specter-pui.umd.js +2 -0
- package/dist/specter-pui.umd.js.map +1 -0
- package/package.json +65 -0
- package/src/assets/css/globals.scss +250 -0
- package/src/assets/css/index.scss +271 -0
- package/src/assets/css/settings.scss +10 -0
- package/src/assets/css/variables.scss +0 -0
- package/src/assets/icon/logo.svg +9 -0
- package/src/assets/img/background.png +0 -0
- package/src/assets/img/dtx.png +0 -0
- package/src/commons/filters/dictionary.js +75 -0
- package/src/commons/filters/format.js +112 -0
- package/src/commons/filters/mask.js +25 -0
- package/src/commons/index.js +17 -0
- package/src/commons/request.js +89 -0
- package/src/commons/storage.js +41 -0
- package/src/commons/themes.js +153 -0
- package/src/commons/validation.js +72 -0
- package/src/components/README.md +35 -0
- package/src/components/assembly/VtkArea.vue +259 -0
- package/src/components/assembly/VtkCheckbox.vue +168 -0
- package/src/components/assembly/VtkCount.vue +403 -0
- package/src/components/assembly/VtkDatePicker.vue +326 -0
- package/src/components/assembly/VtkEmpty.vue +107 -0
- package/src/components/assembly/VtkFab.vue +78 -0
- package/src/components/assembly/VtkFormItem.vue +166 -0
- package/src/components/assembly/VtkImg.vue +372 -0
- package/src/components/assembly/VtkPage.vue +156 -0
- package/src/components/assembly/VtkPdf.vue +424 -0
- package/src/components/assembly/VtkProj.vue +539 -0
- package/src/components/assembly/VtkRadio.vue +82 -0
- package/src/components/assembly/VtkSearch.vue +145 -0
- package/src/components/assembly/VtkSelect.vue +104 -0
- package/src/components/assembly/VtkStepper.vue +160 -0
- package/src/components/message/alert.vue +31 -0
- package/src/components/message/confirm.vue +44 -0
- package/src/components/message/index.js +55 -0
- package/src/components/message/loading.vue +33 -0
- package/src/components/message/prompt.vue +57 -0
- package/src/components/message/toast.vue +45 -0
- package/src/components/message/vtkMessage.vue +27 -0
- package/src/composables/useMixins.js +2 -0
- package/src/composables/usePage.js +311 -0
- package/src/index.js +109 -0
- package/src/stores/message.js +79 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="search">
|
|
3
|
+
<VMenu v-model="menu" @update:model-value="obtain" location="bottom start" :close-on-content-click="false">
|
|
4
|
+
<template v-slot:activator="{ props }">
|
|
5
|
+
<VTextField v-model="queryParam.condition" :placeholder="$attrs.placeholder || '请输入查询内容'"
|
|
6
|
+
:style="$attrs.styles" class="box" density="compact" variant="outlined" hide-details
|
|
7
|
+
@click:append="search" @keyup.enter="search" @click:clear="(queryParam.condition = ''), search()"
|
|
8
|
+
clearable>
|
|
9
|
+
<template v-slot:append-inner>
|
|
10
|
+
<VBadge dot :content="initialIndex" :model-value="initialIndex > 0" color="error"
|
|
11
|
+
class="advanced-badge">
|
|
12
|
+
<span v-bind="props"
|
|
13
|
+
class="text-blue vtk-cursor-pointer d-inline-flex align-center text-body-2">
|
|
14
|
+
高级
|
|
15
|
+
</span>
|
|
16
|
+
</VBadge>
|
|
17
|
+
</template>
|
|
18
|
+
</VTextField>
|
|
19
|
+
</template>
|
|
20
|
+
<VCard style="width: 380px;margin-top: 25px;">
|
|
21
|
+
<VCardTitle class="pr-3 d-flex justify-space-between align-center pb-5">
|
|
22
|
+
高级搜索
|
|
23
|
+
<VBtn class="mx-0" variant="text" icon @click="close" small>
|
|
24
|
+
<VIcon>mdi-close</VIcon>
|
|
25
|
+
</VBtn>
|
|
26
|
+
</VCardTitle>
|
|
27
|
+
<VCardText>
|
|
28
|
+
<slot></slot>
|
|
29
|
+
</VCardText>
|
|
30
|
+
<VCardActions class="pt-0 px-4 pb-3">
|
|
31
|
+
<slot name="actions"></slot>
|
|
32
|
+
<VSpacer />
|
|
33
|
+
<VBtn @click="search" variant="flat" color="primary">
|
|
34
|
+
<VIcon class="mr-1">mdi-magnify</VIcon>搜索
|
|
35
|
+
</VBtn>
|
|
36
|
+
<VBtn @click="reset" variant="flat" color="error">
|
|
37
|
+
<VIcon class="mr-1">mdi-sync</VIcon>重置
|
|
38
|
+
</VBtn>
|
|
39
|
+
</VCardActions>
|
|
40
|
+
</VCard>
|
|
41
|
+
</VMenu>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script setup>
|
|
46
|
+
import { ref, onMounted, watch } from 'vue';
|
|
47
|
+
|
|
48
|
+
defineOptions({
|
|
49
|
+
name: "VtkSearch"
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const props = defineProps({
|
|
53
|
+
value: {
|
|
54
|
+
type: Object,
|
|
55
|
+
default: () => ({})
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const emit = defineEmits(['update:value', 'search']);
|
|
60
|
+
|
|
61
|
+
// 响应式数据
|
|
62
|
+
const user = ref({});
|
|
63
|
+
const menu = ref(false);
|
|
64
|
+
const queryParam = ref({ ...props.value });
|
|
65
|
+
const initialIndex = ref(0);
|
|
66
|
+
|
|
67
|
+
// 监听 props.value 的变化
|
|
68
|
+
watch(
|
|
69
|
+
() => props.value,
|
|
70
|
+
(newVal) => {
|
|
71
|
+
queryParam.value = { ...newVal };
|
|
72
|
+
},
|
|
73
|
+
{ deep: true }
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
onMounted(() => {
|
|
77
|
+
user.value = JSON.parse(localStorage.getItem("user") || "{}");
|
|
78
|
+
initialIndex.value = 0;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// 方法
|
|
82
|
+
const obtain = () => {
|
|
83
|
+
if (!menu.value) {
|
|
84
|
+
initialIndex.value = 0;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const close = () => {
|
|
89
|
+
menu.value = false;
|
|
90
|
+
obtain();
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const search = () => {
|
|
94
|
+
close();
|
|
95
|
+
emit('update:value', queryParam.value);
|
|
96
|
+
emit("search");
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// 重置
|
|
100
|
+
const reset = () => {
|
|
101
|
+
// 简化版重置逻辑
|
|
102
|
+
Object.keys(queryParam.value).forEach(key => {
|
|
103
|
+
if (key !== 'condition') {
|
|
104
|
+
delete queryParam.value[key];
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
delete queryParam.value.condition;
|
|
109
|
+
initialIndex.value = 0;
|
|
110
|
+
emit('update:value', queryParam.value);
|
|
111
|
+
emit("search");
|
|
112
|
+
menu.value = false;
|
|
113
|
+
};
|
|
114
|
+
</script>
|
|
115
|
+
|
|
116
|
+
<style lang="scss" scoped>
|
|
117
|
+
.search {
|
|
118
|
+
position: relative;
|
|
119
|
+
min-width: 380px;
|
|
120
|
+
min-height: 40px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.box {
|
|
124
|
+
min-width: 380px;
|
|
125
|
+
min-height: 40px;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
:deep(.box .v-field__append-inner) {
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
padding-left: 16px !important;
|
|
132
|
+
padding-right: 4px !important;
|
|
133
|
+
border-left: 1px #cccccc88 solid;
|
|
134
|
+
min-width: 50px;
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
:deep(.v-overlay__content) {
|
|
140
|
+
top: 285px !important;
|
|
141
|
+
left: unset !important;
|
|
142
|
+
right: 60px !important;
|
|
143
|
+
min-width: 380px;
|
|
144
|
+
}
|
|
145
|
+
</style>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VSelect
|
|
3
|
+
v-bind="filteredAttrs"
|
|
4
|
+
:items="items"
|
|
5
|
+
item-title="codeValue"
|
|
6
|
+
item-value="code"
|
|
7
|
+
:multiple="multi"
|
|
8
|
+
:menu-props="{ offsetY: true }"
|
|
9
|
+
@update:model-value="$emit('update:modelValue', $event)"
|
|
10
|
+
/>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup>
|
|
14
|
+
import { ref, onMounted, useAttrs, computed } from 'vue'
|
|
15
|
+
import Request from "../../commons/request";
|
|
16
|
+
|
|
17
|
+
// 定义组件名称和选项
|
|
18
|
+
defineOptions({
|
|
19
|
+
name: "VtkSelect",
|
|
20
|
+
inheritAttrs: false
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// 定义 props
|
|
24
|
+
const props = defineProps({
|
|
25
|
+
// 数据库字段名字(DISABLE_TYPE) 或 静态的字段(0:否/1:是)
|
|
26
|
+
list: {
|
|
27
|
+
type: String,
|
|
28
|
+
default: null,
|
|
29
|
+
},
|
|
30
|
+
multi: {
|
|
31
|
+
type: Boolean,
|
|
32
|
+
default: false,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// 定义 emits
|
|
37
|
+
const emit = defineEmits(['update:modelValue']);
|
|
38
|
+
|
|
39
|
+
// 获取所有传递的属性
|
|
40
|
+
const attrs = useAttrs();
|
|
41
|
+
|
|
42
|
+
// 过滤属性,排除组件内部使用的属性
|
|
43
|
+
const filteredAttrs = computed(() => {
|
|
44
|
+
const { list, multi, ...rest } = attrs;
|
|
45
|
+
return rest;
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// 响应式数据
|
|
49
|
+
const items = ref([]);
|
|
50
|
+
|
|
51
|
+
// 方法定义
|
|
52
|
+
const miscs = () => {
|
|
53
|
+
Request.getForm(`dict/misc/list/${props.list}`).then((res) => {
|
|
54
|
+
items.value = res.data;
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const statc = () => {
|
|
59
|
+
if (!props.list) return;
|
|
60
|
+
|
|
61
|
+
props.list.split("/").forEach((it) => {
|
|
62
|
+
const its = it.split(":");
|
|
63
|
+
items.value.push({ code: its[0], codeValue: its[1] });
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// 生命周期钩子
|
|
68
|
+
onMounted(() => {
|
|
69
|
+
if (props.list) {
|
|
70
|
+
if (props.list.includes(":")) {
|
|
71
|
+
statc();
|
|
72
|
+
} else {
|
|
73
|
+
miscs();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// 使用方式
|
|
79
|
+
// <vtk-select
|
|
80
|
+
// v-model="value"
|
|
81
|
+
// list="YOUR_LIST"
|
|
82
|
+
// variant="outlined" <!-- 样式变体 -->
|
|
83
|
+
// density="compact" <!-- 密度 'default' | 'comfortable' | 'compact' -->
|
|
84
|
+
// clearable <!-- 可清除 -->
|
|
85
|
+
// placeholder="请选择" <!-- 占位符 -->
|
|
86
|
+
// :rules="rules" <!-- 验证规则 -->
|
|
87
|
+
// disabled <!-- 禁用状态 -->
|
|
88
|
+
// readonly <!-- 只读状态 -->
|
|
89
|
+
// hide-details <!-- 隐藏详情信息 -->
|
|
90
|
+
// />
|
|
91
|
+
|
|
92
|
+
</script>
|
|
93
|
+
|
|
94
|
+
<style>
|
|
95
|
+
::-webkit-scrollbar {
|
|
96
|
+
width: 6px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
::-webkit-scrollbar-thumb {
|
|
100
|
+
border-radius: 3px;
|
|
101
|
+
height: 100px;
|
|
102
|
+
background-color: #007acc;
|
|
103
|
+
}
|
|
104
|
+
</style>
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VStepper class="elevation-0" v-model="stepIndex">
|
|
3
|
+
<VStepperHeader class="elevation-0" style="overflow: hidden;">
|
|
4
|
+
<VRow class="stepList">
|
|
5
|
+
<VCol class="pl-0 colItem" v-for="(item, index) in step" :key="index" style="">
|
|
6
|
+
<div class="first-box1 last-box pl-10 py-5 stepItem" :class="stepIndex > index? 'selected' : ''"
|
|
7
|
+
:complete="stepIndex > index" :step="index + 1">
|
|
8
|
+
{{ item }}
|
|
9
|
+
</div>
|
|
10
|
+
</VCol>
|
|
11
|
+
</VRow>
|
|
12
|
+
</VStepperHeader>
|
|
13
|
+
|
|
14
|
+
<VStepperWindow>
|
|
15
|
+
<VStepperWindowItem v-for="(item, index) in list" :key="index" :value="index + 1">
|
|
16
|
+
<slot :name="index + 1"></slot>
|
|
17
|
+
</VStepperWindowItem>
|
|
18
|
+
<slot></slot>
|
|
19
|
+
</VStepperWindow>
|
|
20
|
+
</VStepper>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
import { ref, watch, onMounted } from 'vue';
|
|
25
|
+
|
|
26
|
+
// 定义组件名称
|
|
27
|
+
defineOptions({
|
|
28
|
+
name: "VtkStepper",
|
|
29
|
+
inheritAttrs: false,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// 定义props
|
|
33
|
+
const props = defineProps({
|
|
34
|
+
list: {
|
|
35
|
+
type: String,
|
|
36
|
+
default: null,
|
|
37
|
+
},
|
|
38
|
+
el: {
|
|
39
|
+
type: Number,
|
|
40
|
+
default: 1,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// 响应式数据
|
|
45
|
+
const stepIndex = ref(props.el);
|
|
46
|
+
const step = ref([]);
|
|
47
|
+
|
|
48
|
+
// 监听el属性变化
|
|
49
|
+
watch(() => props.el, (val) => {
|
|
50
|
+
stepIndex.value = val;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// 处理内容
|
|
54
|
+
const content = () => {
|
|
55
|
+
if (props.list) {
|
|
56
|
+
step.value = props.list.split(",");
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// 组件挂载时执行
|
|
61
|
+
onMounted(() => {
|
|
62
|
+
content();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// 监听list变化
|
|
66
|
+
watch(() => props.list, () => {
|
|
67
|
+
content();
|
|
68
|
+
});
|
|
69
|
+
</script>
|
|
70
|
+
|
|
71
|
+
<style lang="scss" scoped>
|
|
72
|
+
// 颜色变量定义
|
|
73
|
+
$color-background: #c7ccd538;
|
|
74
|
+
$color-selected: #165dff;
|
|
75
|
+
$color-white: #fff;
|
|
76
|
+
$color-light-bg: #f2f3f5;
|
|
77
|
+
$color-dark-bg: #1e1e1e;
|
|
78
|
+
|
|
79
|
+
.v-stepper__step {
|
|
80
|
+
background: $color-background;
|
|
81
|
+
position: relative;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 隐藏步骤数字
|
|
85
|
+
:deep(.v-stepper__step__step) {
|
|
86
|
+
display: none !important;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.stepItem {
|
|
90
|
+
align-items: center;
|
|
91
|
+
display: flex;
|
|
92
|
+
flex-direction: row;
|
|
93
|
+
padding: 24px;
|
|
94
|
+
position: relative;
|
|
95
|
+
background: $color-background;
|
|
96
|
+
|
|
97
|
+
// 暗色主题样式
|
|
98
|
+
.v-theme--dark & {
|
|
99
|
+
color: rgba(255, 255, 255, 0.5);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 选中状态
|
|
103
|
+
&.selected {
|
|
104
|
+
background: $color-selected;
|
|
105
|
+
color: $color-white !important;
|
|
106
|
+
|
|
107
|
+
&.last-box::after {
|
|
108
|
+
border-color: transparent transparent transparent $color-selected;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
:deep(.v-stepper__label) {
|
|
112
|
+
color: $color-white !important;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.colItem {
|
|
118
|
+
&:first-child .first-box1::before {
|
|
119
|
+
border-color: transparent !important;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
&:last-child .last-box::after {
|
|
123
|
+
border-color: transparent !important;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.first-box1::before {
|
|
128
|
+
position: absolute;
|
|
129
|
+
left: 0;
|
|
130
|
+
content: "";
|
|
131
|
+
width: 0;
|
|
132
|
+
height: 0;
|
|
133
|
+
z-index: 0;
|
|
134
|
+
border: 30px solid;
|
|
135
|
+
border-color: transparent transparent transparent $color-white;
|
|
136
|
+
|
|
137
|
+
.v-theme--dark & {
|
|
138
|
+
border-color: transparent transparent transparent $color-dark-bg;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.last-box::after {
|
|
143
|
+
position: absolute;
|
|
144
|
+
right: -70px;
|
|
145
|
+
content: "";
|
|
146
|
+
z-index: 1;
|
|
147
|
+
width: 0;
|
|
148
|
+
height: 0;
|
|
149
|
+
border: 35px solid;
|
|
150
|
+
border-color: transparent transparent transparent $color-light-bg;
|
|
151
|
+
|
|
152
|
+
.v-theme--dark & {
|
|
153
|
+
border-color: transparent transparent transparent $color-background;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.theme--dark.v-stepper {
|
|
158
|
+
background: transparent;
|
|
159
|
+
}
|
|
160
|
+
</style>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VDialog v-model="isActive" persistent :width="options.width">
|
|
3
|
+
<VCard :color="options.color">
|
|
4
|
+
<VCardTitle>{{ options.title }}</VCardTitle>
|
|
5
|
+
<VCardText v-if="options.text">
|
|
6
|
+
{{ options.text }}
|
|
7
|
+
</VCardText>
|
|
8
|
+
<VCardActions>
|
|
9
|
+
<VSpacer />
|
|
10
|
+
<VBtn text @click="close_modal">确定</VBtn>
|
|
11
|
+
</VCardActions>
|
|
12
|
+
</VCard>
|
|
13
|
+
</VDialog>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup>
|
|
17
|
+
import { computed } from 'vue'
|
|
18
|
+
import { useMessageStore } from '../../stores/message.js' // 根据实际路径调整
|
|
19
|
+
|
|
20
|
+
const messageStore = useMessageStore()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
// 使用 computed 获取响应式数据
|
|
24
|
+
const isActive = computed(() => messageStore.alert?.isActive || false)
|
|
25
|
+
const options = computed(() => messageStore.alert?.options || {})
|
|
26
|
+
|
|
27
|
+
// 关闭模态框方法
|
|
28
|
+
const close_modal = () => {
|
|
29
|
+
messageStore.hide('alert')
|
|
30
|
+
}
|
|
31
|
+
</script>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VDialog v-model="isActive" persistent :width="options.width">
|
|
3
|
+
<VCard :color="options.color">
|
|
4
|
+
<VCardTitle>{{ options.title }}</VCardTitle>
|
|
5
|
+
<VCardText v-if="options.text">
|
|
6
|
+
{{ options.text }}
|
|
7
|
+
</VCardText>
|
|
8
|
+
<VCardActions>
|
|
9
|
+
<VSpacer />
|
|
10
|
+
<VBtn text @click="cancel">{{ options.cancelText || '取消' }}</VBtn>
|
|
11
|
+
<VBtn text @click="confirm">{{ options.confirmText || '确定' }}</VBtn>
|
|
12
|
+
</VCardActions>
|
|
13
|
+
</VCard>
|
|
14
|
+
</VDialog>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script setup>
|
|
18
|
+
import { computed } from 'vue'
|
|
19
|
+
import { useMessageStore } from '../../stores/message.js'
|
|
20
|
+
|
|
21
|
+
const messageStore = useMessageStore()
|
|
22
|
+
|
|
23
|
+
// 使用 computed 获取响应式数据
|
|
24
|
+
const isActive = computed(() => messageStore.alert?.isActive || false)
|
|
25
|
+
const options = computed(() => messageStore.alert?.options || {})
|
|
26
|
+
|
|
27
|
+
// 确认操作
|
|
28
|
+
const confirm = () => {
|
|
29
|
+
// 如果 options.onConfirm 存在则执行回调
|
|
30
|
+
if (typeof options.value.onConfirm === 'function') {
|
|
31
|
+
options.value.onConfirm()
|
|
32
|
+
}
|
|
33
|
+
messageStore.hide('alert')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 取消操作
|
|
37
|
+
const cancel = () => {
|
|
38
|
+
// 如果 options.onCancel 存在则执行回调
|
|
39
|
+
if (typeof options.value.onCancel === 'function') {
|
|
40
|
+
options.value.onCancel()
|
|
41
|
+
}
|
|
42
|
+
messageStore.hide('alert')
|
|
43
|
+
}
|
|
44
|
+
</script>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// components/message/index.js
|
|
2
|
+
import { useMessageStore } from '../../stores/message.js'
|
|
3
|
+
|
|
4
|
+
const Message = {
|
|
5
|
+
// 显示 alert
|
|
6
|
+
alert(options) {
|
|
7
|
+
const messageStore = useMessageStore()
|
|
8
|
+
messageStore.show('alert', options)
|
|
9
|
+
},
|
|
10
|
+
|
|
11
|
+
// 显示 confirm
|
|
12
|
+
confirm(options) {
|
|
13
|
+
const messageStore = useMessageStore()
|
|
14
|
+
messageStore.show('confirm', options)
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
// 显示 loading
|
|
18
|
+
loading(options) {
|
|
19
|
+
const messageStore = useMessageStore()
|
|
20
|
+
const defaultOptions = {
|
|
21
|
+
title: '加载中...',
|
|
22
|
+
text: '',
|
|
23
|
+
color: '',
|
|
24
|
+
width: 300,
|
|
25
|
+
indeterminate: true,
|
|
26
|
+
progressColor: 'primary'
|
|
27
|
+
}
|
|
28
|
+
messageStore.show('loading', { ...defaultOptions, ...options })
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
// 显示 prompt
|
|
32
|
+
prompt(options) {
|
|
33
|
+
const messageStore = useMessageStore()
|
|
34
|
+
messageStore.show('prompt', options)
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// 显示 toast
|
|
38
|
+
toast(text, options = {}) {
|
|
39
|
+
|
|
40
|
+
const messageStore = useMessageStore()
|
|
41
|
+
// 确保传入的是字符串时正确处理
|
|
42
|
+
const toastOptions = typeof text === 'string'
|
|
43
|
+
? { text, ...options }
|
|
44
|
+
: text
|
|
45
|
+
messageStore.show('toast', toastOptions)
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// 隐藏指定类型的消息
|
|
49
|
+
hide(type) {
|
|
50
|
+
const messageStore = useMessageStore()
|
|
51
|
+
messageStore.hide(type)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default Message
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VDialog v-model="isActive" persistent :width="options.width" hide-overlay>
|
|
3
|
+
<VCard :color="options.color">
|
|
4
|
+
<VCardTitle>{{ options.title }}</VCardTitle>
|
|
5
|
+
<VCardText>
|
|
6
|
+
<VProgressLinear
|
|
7
|
+
v-if="options.indeterminate !== false"
|
|
8
|
+
indeterminate
|
|
9
|
+
:color="options.progressColor || 'primary'"
|
|
10
|
+
/>
|
|
11
|
+
<VProgressLinear
|
|
12
|
+
v-else
|
|
13
|
+
:value="options.value || 0"
|
|
14
|
+
:color="options.progressColor || 'primary'"
|
|
15
|
+
/>
|
|
16
|
+
<div v-if="options.text" class="mt-2">
|
|
17
|
+
{{ options.text }}
|
|
18
|
+
</div>
|
|
19
|
+
</VCardText>
|
|
20
|
+
</VCard>
|
|
21
|
+
</VDialog>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<script setup>
|
|
25
|
+
import { computed } from 'vue'
|
|
26
|
+
import { useMessageStore } from '../../stores/message.js'
|
|
27
|
+
|
|
28
|
+
const messageStore = useMessageStore()
|
|
29
|
+
|
|
30
|
+
// 使用 computed 获取响应式数据
|
|
31
|
+
const isActive = computed(() => messageStore.loading?.isActive || false)
|
|
32
|
+
const options = computed(() => messageStore.loading?.options || {})
|
|
33
|
+
</script>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VDialog v-model="isActive" persistent :width="options.width">
|
|
3
|
+
<VCard :color="options.color">
|
|
4
|
+
<VCardTitle>{{ options.title }}</VCardTitle>
|
|
5
|
+
<VCardText>
|
|
6
|
+
<VTextField
|
|
7
|
+
v-model="inputValue"
|
|
8
|
+
:label="options.label"
|
|
9
|
+
:placeholder="options.placeholder"
|
|
10
|
+
:type="options.inputType || 'text'"
|
|
11
|
+
outlined
|
|
12
|
+
dense
|
|
13
|
+
/>
|
|
14
|
+
<div v-if="options.text" class="mt-2">
|
|
15
|
+
{{ options.text }}
|
|
16
|
+
</div>
|
|
17
|
+
</VCardText>
|
|
18
|
+
<VCardActions>
|
|
19
|
+
<VSpacer />
|
|
20
|
+
<VBtn text @click="cancel">{{ options.cancelText || '取消' }}</VBtn>
|
|
21
|
+
<VBtn text @click="confirm">{{ options.confirmText || '确定' }}</VBtn>
|
|
22
|
+
</VCardActions>
|
|
23
|
+
</VCard>
|
|
24
|
+
</VDialog>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script setup>
|
|
28
|
+
import { ref, computed } from 'vue'
|
|
29
|
+
import { useMessageStore } from '../../stores/message.js'
|
|
30
|
+
|
|
31
|
+
const messageStore = useMessageStore()
|
|
32
|
+
const inputValue = ref('')
|
|
33
|
+
|
|
34
|
+
// 使用 computed 获取响应式数据
|
|
35
|
+
const isActive = computed(() => messageStore.prompt?.isActive || false)
|
|
36
|
+
const options = computed(() => messageStore.prompt?.options || {})
|
|
37
|
+
|
|
38
|
+
// 确认操作
|
|
39
|
+
const confirm = () => {
|
|
40
|
+
// 如果 options.onConfirm 存在则执行回调
|
|
41
|
+
if (typeof options.value.onConfirm === 'function') {
|
|
42
|
+
options.value.onConfirm(inputValue.value)
|
|
43
|
+
}
|
|
44
|
+
messageStore.hide('prompt')
|
|
45
|
+
inputValue.value = '' // 清空输入值
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 取消操作
|
|
49
|
+
const cancel = () => {
|
|
50
|
+
// 如果 options.onCancel 存在则执行回调
|
|
51
|
+
if (typeof options.value.onCancel === 'function') {
|
|
52
|
+
options.value.onCancel()
|
|
53
|
+
}
|
|
54
|
+
messageStore.hide('prompt')
|
|
55
|
+
inputValue.value = '' // 清空输入值
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<VSnackbar v-model="isActive" :timeout="options.timeout > 0 ? options.timeout : 3000" :color="options.color" centered @update:modelValue="onModelUpdate">
|
|
3
|
+
{{ options.text }}
|
|
4
|
+
<template v-slot:actions>
|
|
5
|
+
<VBtn text icon @click="close_modal()">
|
|
6
|
+
<VIcon>mdi-close</VIcon>
|
|
7
|
+
</VBtn>
|
|
8
|
+
</template>
|
|
9
|
+
</VSnackbar>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup>
|
|
13
|
+
import { computed } from "vue";
|
|
14
|
+
import { useMessageStore } from "../../stores/message.js";
|
|
15
|
+
|
|
16
|
+
const messageStore = useMessageStore();
|
|
17
|
+
|
|
18
|
+
const isActive = computed({
|
|
19
|
+
get: () => messageStore.toast?.isActive || false,
|
|
20
|
+
set: (value) => {
|
|
21
|
+
if (messageStore.toast) {
|
|
22
|
+
messageStore.toast.isActive = value;
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const options = computed(() => messageStore.toast?.options || {});
|
|
28
|
+
|
|
29
|
+
const close_modal = () => {
|
|
30
|
+
messageStore.hide("toast");
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// 监听模型值更新
|
|
34
|
+
const onModelUpdate = (value) => {
|
|
35
|
+
if (!value) {
|
|
36
|
+
// Snackbar 关闭时确保 store 状态同步
|
|
37
|
+
messageStore.hide("toast");
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
</script>
|
|
41
|
+
<style lang="scss" scoped>
|
|
42
|
+
::v-deep .v-snackbar__wrapper {
|
|
43
|
+
top: 24px;
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="text-center">
|
|
3
|
+
<vtk-alert />
|
|
4
|
+
<vtk-confirm />
|
|
5
|
+
<vtk-loading />
|
|
6
|
+
<vtk-prompt />
|
|
7
|
+
<vtk-toast />
|
|
8
|
+
</div>
|
|
9
|
+
</template>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
import vtkAlert from "./alert";
|
|
13
|
+
import vtkConfirm from "./confirm";
|
|
14
|
+
import vtkLoading from "./loading";
|
|
15
|
+
import vtkPrompt from "./prompt";
|
|
16
|
+
import vtkToast from "./toast";
|
|
17
|
+
export default {
|
|
18
|
+
name: "vtkMessage",
|
|
19
|
+
components: {
|
|
20
|
+
vtkAlert,
|
|
21
|
+
vtkConfirm,
|
|
22
|
+
vtkLoading,
|
|
23
|
+
vtkPrompt,
|
|
24
|
+
vtkToast,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
</script>
|