wui-components-v2 1.0.24 → 1.0.25
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/api/core/index.ts +2 -2
- package/api/index.ts +1 -1
- package/api/page.ts +51 -0
- package/components/demo-card/demo-card.vue +38 -0
- package/components/edit-page/edit-page.vue +114 -0
- package/components/fold-card/fold-card.vue +132 -0
- package/components/form-control/form-control.vue +78 -0
- package/components/list/list.vue +113 -0
- package/components/list-top-buttons/list-top-buttons.vue +20 -0
- package/components/login-form/login-form.vue +8 -3
- package/components/menus/menus.vue +29 -24
- package/components/mulselect-picker/mulselect-picker.vue +82 -0
- package/components/search/search.vue +108 -0
- package/components/select-list/select-list.vue +178 -0
- package/index.ts +6 -0
- package/package.json +1 -1
- package/type.ts +59 -0
- package/utils/index.ts +35 -9
package/api/core/index.ts
CHANGED
|
@@ -16,11 +16,11 @@ interface RequestOptions {
|
|
|
16
16
|
timeout?: number
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function request(options: RequestOptions) {
|
|
19
|
+
function request(options: RequestOptions): Promise<any> {
|
|
20
20
|
const baseUrl = uni.getStorageSync('BASE_URL') || '/'
|
|
21
21
|
const hydrocarbonProgramToken = uni.getStorageSync('HYDROCARBON_PROGRAM_TOKEN') || ''
|
|
22
22
|
const token = uni.getStorageSync('TOKEN') || ''
|
|
23
|
-
const hydrocarbonClient = uni.getStorageSync('HYDROCARBON_CLIENT') || '
|
|
23
|
+
const hydrocarbonClient = uni.getStorageSync('HYDROCARBON_CLIENT') || ''
|
|
24
24
|
console.log('request', baseUrl + options.url, options.data)
|
|
25
25
|
return new Promise((resolve, reject) => {
|
|
26
26
|
// 设置默认值
|
package/api/index.ts
CHANGED
package/api/page.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { PageData } from '../type'
|
|
2
|
+
import req from './core/index'
|
|
3
|
+
|
|
4
|
+
interface PageConfig {
|
|
5
|
+
configName: string
|
|
6
|
+
ltmplConfig: any
|
|
7
|
+
sourceId: string
|
|
8
|
+
sourceName: string
|
|
9
|
+
}
|
|
10
|
+
// 列表页面配置
|
|
11
|
+
export function pageConfig(sourceId: string): Promise<PageConfig> {
|
|
12
|
+
return req({
|
|
13
|
+
url: `/v3/ltmpl/config?sourceId=${sourceId}`,
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// 获取列表页面数据key
|
|
18
|
+
export function pageKey(sourceId: string, mainCode: string = '', query: string = '') {
|
|
19
|
+
return req({
|
|
20
|
+
url: `/v3/ltmpl/query/key?sourceId=${sourceId}&mainCode=${mainCode}&menuId=${sourceId}${query}`,
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 获取列表页面数据
|
|
25
|
+
export function listData(queryKey: string, pageNo: number, pageSize: number): Promise<PageData> {
|
|
26
|
+
return req({
|
|
27
|
+
url: `/v3/ltmpl/query/data?queryKey=${queryKey}&pageNo=${pageNo}&pageSize=${pageSize}`,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 获取编辑页面配置
|
|
32
|
+
export function editPageConfig(sourceId: string, mianCode: string) {
|
|
33
|
+
return req({
|
|
34
|
+
url: `/v3/dtmpl/config?sourceId=${sourceId}&code=${mianCode}`,
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//
|
|
39
|
+
// 新增/编辑页面提交保存
|
|
40
|
+
export function editPageDataSave(sourceId: string, id: string = '', data: any, mainCode: string = '') {
|
|
41
|
+
return req({
|
|
42
|
+
url: `/v3/dtmpl/data`,
|
|
43
|
+
method: 'POST',
|
|
44
|
+
data: {
|
|
45
|
+
sourceId,
|
|
46
|
+
mainCode,
|
|
47
|
+
唯一编码: id,
|
|
48
|
+
...data,
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed, defineOptions, defineProps } from 'vue'
|
|
3
|
+
import { useManualTheme } from '../../composables/useManualTheme'
|
|
4
|
+
|
|
5
|
+
defineOptions({
|
|
6
|
+
name: 'DemoCard',
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
const props = defineProps({
|
|
10
|
+
// 标题
|
|
11
|
+
title: {
|
|
12
|
+
type: String,
|
|
13
|
+
default: '',
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const {
|
|
19
|
+
primary,
|
|
20
|
+
} = useManualTheme()
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<wd-card>
|
|
25
|
+
<template #title>
|
|
26
|
+
<view class="flex items-center gap-2">
|
|
27
|
+
<view class="h-3.5 w-1" :style="{ backgroundColor: primary }" />
|
|
28
|
+
<text class="font-bold">
|
|
29
|
+
{{ props.title }}
|
|
30
|
+
</text>
|
|
31
|
+
</view>
|
|
32
|
+
</template>
|
|
33
|
+
<slot name="content" />
|
|
34
|
+
<template #footer>
|
|
35
|
+
<slot name="footer" />
|
|
36
|
+
</template>
|
|
37
|
+
</wd-card>
|
|
38
|
+
</template>
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed, defineOptions } from 'vue'
|
|
3
|
+
import { onLoad } from '@dcloudio/uni-app'
|
|
4
|
+
import { useRouter } from 'uni-mini-router'
|
|
5
|
+
import FormControl from '../form-control/form-control.vue'
|
|
6
|
+
import { editPageConfig, editPageDataSave } from '../../api/page'
|
|
7
|
+
import type { Groups, dtmplConfig } from '../../type'
|
|
8
|
+
import { useGlobalToast } from '../../composables/useGlobalToast'
|
|
9
|
+
import foldCard from '../fold-card/fold-card.vue'
|
|
10
|
+
|
|
11
|
+
defineOptions({
|
|
12
|
+
name: 'EditPage',
|
|
13
|
+
})
|
|
14
|
+
const pageConfig = ref<dtmplConfig>({
|
|
15
|
+
id: '',
|
|
16
|
+
title: '',
|
|
17
|
+
groups: [],
|
|
18
|
+
entity: {
|
|
19
|
+
arrayMap: {},
|
|
20
|
+
code: '',
|
|
21
|
+
fieldMap: {},
|
|
22
|
+
},
|
|
23
|
+
buttons: [],
|
|
24
|
+
})
|
|
25
|
+
const globalToast = useGlobalToast()
|
|
26
|
+
const router = useRouter()
|
|
27
|
+
const mainCode = ref('')
|
|
28
|
+
const id = ref('')
|
|
29
|
+
const sourceId = ref('')
|
|
30
|
+
const formControlRef = ref()
|
|
31
|
+
const subLoading = ref(false)
|
|
32
|
+
// 折叠面板
|
|
33
|
+
const collapses = ref()
|
|
34
|
+
onLoad((option: any) => {
|
|
35
|
+
sourceId.value = option.sourceId
|
|
36
|
+
mainCode.value = option.mainCode
|
|
37
|
+
id.value = option.id
|
|
38
|
+
uni.setNavigationBarTitle({
|
|
39
|
+
title: `编辑${option.title}`,
|
|
40
|
+
})
|
|
41
|
+
getEditPageConfig()
|
|
42
|
+
})
|
|
43
|
+
// const fieldGroup = computed(() => {
|
|
44
|
+
// return pageConfig.value.groups.find(item => item.type === 'fieldGroup')
|
|
45
|
+
// })
|
|
46
|
+
// 获取编辑页面配置
|
|
47
|
+
async function getEditPageConfig() {
|
|
48
|
+
try {
|
|
49
|
+
const res = await editPageConfig(sourceId.value, id.value)
|
|
50
|
+
if (res.dtmplConfig) {
|
|
51
|
+
pageConfig.value = res.dtmplConfig
|
|
52
|
+
collapses.value = pageConfig.value.groups.map((item: Groups) => {
|
|
53
|
+
return item.id
|
|
54
|
+
})
|
|
55
|
+
console.log('res.dtmplConfig:', res.dtmplConfig)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
console.log('error:', error)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// 保存
|
|
63
|
+
async function save() {
|
|
64
|
+
try {
|
|
65
|
+
const formArray: any[] = []
|
|
66
|
+
formControlRef.value.forEach((element: any) => {
|
|
67
|
+
formArray.push(element.submit())
|
|
68
|
+
})
|
|
69
|
+
const res = await Promise.all(formArray)
|
|
70
|
+
const data = res.reduce((acc, cur) => {
|
|
71
|
+
return { ...acc, ...cur }
|
|
72
|
+
}, {})
|
|
73
|
+
subLoading.value = true
|
|
74
|
+
editPageDataSave(sourceId.value, id.value, data, mainCode.value).then(() => {
|
|
75
|
+
subLoading.value = false
|
|
76
|
+
globalToast.success('保存成功')
|
|
77
|
+
router.back()
|
|
78
|
+
}).catch((error: any) => {
|
|
79
|
+
subLoading.value = false
|
|
80
|
+
globalToast.error(error.message)
|
|
81
|
+
})
|
|
82
|
+
console.log('res:', res)
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
console.log('error:', error)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// formControlRef.value.submit().then((data: any) => {
|
|
89
|
+
// console.log('保存成功', data)
|
|
90
|
+
// editPageDataSave(sourceId.value, id.value, data, mainCode.value)
|
|
91
|
+
// })
|
|
92
|
+
}
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<template>
|
|
96
|
+
<view class="relative h-[calc(100vh-44px)] w-100vw overflow-auto">
|
|
97
|
+
<wd-collapse v-model="collapses">
|
|
98
|
+
<wd-collapse-item v-for="group in pageConfig.groups" :key="group.id" :title="group.title" :name="group.id">
|
|
99
|
+
<FormControl v-if="group.type === 'fieldGroup'" ref="formControlRef" :field-group="group" :entity="pageConfig?.entity?.fieldMap" />
|
|
100
|
+
<view v-if="group.type === 'relation'">
|
|
101
|
+
<view v-for="field in pageConfig?.entity?.arrayMap[group.id]" :key="field.code">
|
|
102
|
+
<foldCard :columns="group.fields" model="complex" :data="field" />
|
|
103
|
+
</view>
|
|
104
|
+
</view>
|
|
105
|
+
</wd-collapse-item>
|
|
106
|
+
</wd-collapse>
|
|
107
|
+
<view class="h-12" />
|
|
108
|
+
<view class="fixed bottom-0 left-0 right-0 box-border w-100% flex p-2 .dark:bg-gray-900 .light:bg-white">
|
|
109
|
+
<wd-button class="flex-1" @click="save">
|
|
110
|
+
保存
|
|
111
|
+
</wd-button>
|
|
112
|
+
</view>
|
|
113
|
+
</view>
|
|
114
|
+
</template>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed, defineOptions, defineProps, ref } from 'vue'
|
|
3
|
+
import { useManualTheme } from '../../composables/useManualTheme'
|
|
4
|
+
import type { Columns, Entities } from '../../type'
|
|
5
|
+
import { formatItemData } from '../../utils'
|
|
6
|
+
|
|
7
|
+
defineOptions({
|
|
8
|
+
name: 'FoldCard',
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const props = defineProps<{
|
|
12
|
+
columns: Columns[]
|
|
13
|
+
collapseNum?: number
|
|
14
|
+
primaryColumn?: Columns
|
|
15
|
+
secondColumn?: Columns
|
|
16
|
+
data: Entities
|
|
17
|
+
model: 'simple' | 'complex'
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
// 展示内容
|
|
21
|
+
const exhibitData = computed(() => {
|
|
22
|
+
const { collapseNum } = props
|
|
23
|
+
const num = collapseNum || 2
|
|
24
|
+
const columns = props.columns.length >= num ? props.columns.slice(0, num) : props.columns
|
|
25
|
+
return columns.filter(item => item.title !== '操作')
|
|
26
|
+
})
|
|
27
|
+
// 折叠内容
|
|
28
|
+
const collapseData = computed(() => {
|
|
29
|
+
const { collapseNum } = props
|
|
30
|
+
const num = collapseNum || 2
|
|
31
|
+
const columns = props.columns.length >= num ? props.columns.slice(num) : []
|
|
32
|
+
return columns.filter(item => item.title !== '操作')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// 折叠图标
|
|
36
|
+
const collapseIcon = ref('arrow-down')
|
|
37
|
+
// 切换折叠内容
|
|
38
|
+
function toggleCollapse(contentId: string) {
|
|
39
|
+
const content = document.getElementById(contentId)
|
|
40
|
+
if (content?.classList.contains('max-h-0')) {
|
|
41
|
+
// 展开
|
|
42
|
+
content.classList.remove('max-h-0')
|
|
43
|
+
content.classList.add('max-h-[500px]')
|
|
44
|
+
collapseIcon.value = 'arrow-up'
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// 折叠
|
|
48
|
+
content?.classList.add('max-h-0')
|
|
49
|
+
content?.classList.remove('max-h-[500px]')
|
|
50
|
+
collapseIcon.value = 'arrow-down'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<template>
|
|
56
|
+
<!-- 订单卡片容器 -->
|
|
57
|
+
<view class="mx-auto max-w-md space-y-4">
|
|
58
|
+
<!-- 订单卡片2 -->
|
|
59
|
+
<view class="ma-2 overflow-hidden rounded-xl bg-white shadow-sm dark:bg-[var(--wot-dark-background2)]">
|
|
60
|
+
<!-- 订单头部 -->
|
|
61
|
+
<view class="flex items-center justify-between border-b border-gray-100 p-4">
|
|
62
|
+
<view class="flex items-center gap-1 text-base text-gray-800 font-medium dark:text-white">
|
|
63
|
+
<slot name="select" /> <view v-if="primaryColumn">
|
|
64
|
+
{{ formatItemData(data.fieldMap[primaryColumn.sourceId], primaryColumn.controlType) }}
|
|
65
|
+
</view>
|
|
66
|
+
</view>
|
|
67
|
+
<view v-if="props.secondColumn" class="rounded bg-yellow-50 px-2 py-1 text-sm text-yellow-600">
|
|
68
|
+
{{ props.secondColumn && formatItemData(data.fieldMap[props.secondColumn.sourceId], props.secondColumn.controlType) }}
|
|
69
|
+
</view>
|
|
70
|
+
</view>
|
|
71
|
+
|
|
72
|
+
<!-- 订单内容 -->
|
|
73
|
+
<view v-if="props.model === 'complex'" class="p-4">
|
|
74
|
+
<!-- 商品列表 -->
|
|
75
|
+
<view class="mb-3">
|
|
76
|
+
<!-- 订单信息 -->
|
|
77
|
+
<view class="text-sm space-y-3">
|
|
78
|
+
<view v-for="(item, index) in exhibitData" :key="index" class="flex">
|
|
79
|
+
<view class="mr-2 w-20 text-gray-500 dark:text-white">
|
|
80
|
+
{{ item.title }}:
|
|
81
|
+
</view>
|
|
82
|
+
<view class="flex-1 text-gray-800 dark:text-white">
|
|
83
|
+
{{ formatItemData(data.fieldMap[item.sourceId], item.controlType) }}
|
|
84
|
+
</view>
|
|
85
|
+
</view>
|
|
86
|
+
|
|
87
|
+
<!-- 可折叠内容 -->
|
|
88
|
+
<view :id="`${data.code}`" class="max-h-0 overflow-hidden transition-all duration-300">
|
|
89
|
+
<view class="pt-3 space-y-3">
|
|
90
|
+
<view v-for="(item, index) in collapseData" :key="index" class="flex">
|
|
91
|
+
<view class="mr-2 w-20 text-gray-500 dark:text-white">
|
|
92
|
+
{{ item.title }}:
|
|
93
|
+
</view>
|
|
94
|
+
<view class="flex-1 text-gray-800 dark:text-white">
|
|
95
|
+
{{ formatItemData(data.fieldMap[item.sourceId], item.controlType) }}
|
|
96
|
+
</view>
|
|
97
|
+
</view>
|
|
98
|
+
</view>
|
|
99
|
+
</view>
|
|
100
|
+
</view>
|
|
101
|
+
</view>
|
|
102
|
+
|
|
103
|
+
<!-- 订单底部 -->
|
|
104
|
+
<view class="flex items-center justify-between border-t border-gray-100">
|
|
105
|
+
<view>
|
|
106
|
+
<wd-button
|
|
107
|
+
v-if="collapseData.length > 0"
|
|
108
|
+
id="toggle-btn-2"
|
|
109
|
+
type="icon"
|
|
110
|
+
:icon="collapseIcon"
|
|
111
|
+
class="mr-auto flex items-center px-3 py-2 text-sm text-blue-600"
|
|
112
|
+
@click="toggleCollapse(data.code)"
|
|
113
|
+
/>
|
|
114
|
+
</view>
|
|
115
|
+
|
|
116
|
+
<view class="flex items-center">
|
|
117
|
+
<slot name="buttons" />
|
|
118
|
+
</view>
|
|
119
|
+
</view>
|
|
120
|
+
</view>
|
|
121
|
+
</view>
|
|
122
|
+
</view>
|
|
123
|
+
</template>
|
|
124
|
+
|
|
125
|
+
<style>
|
|
126
|
+
:deep(.wd-collapse-item__body){
|
|
127
|
+
background-color:#f9f9f9;
|
|
128
|
+
}
|
|
129
|
+
:deep(.wot-theme-dark .wd-collapse-item__body){
|
|
130
|
+
background-color:#222222;
|
|
131
|
+
}
|
|
132
|
+
</style>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed, defineEmits, defineExpose, defineOptions, defineProps, reactive, ref, toRaw } from 'vue'
|
|
3
|
+
import type { FormRules } from 'wot-design-uni/components/wd-form/types'
|
|
4
|
+
import type { Fields, Groups } from '../../type'
|
|
5
|
+
import mulselectPicker from '../mulselect-picker/mulselect-picker.vue'
|
|
6
|
+
|
|
7
|
+
defineOptions({
|
|
8
|
+
name: 'FormControl',
|
|
9
|
+
})
|
|
10
|
+
const props = defineProps<{
|
|
11
|
+
fieldGroup?: Groups
|
|
12
|
+
entity?: { [key: string]: string }
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const form = ref<any>(null)
|
|
16
|
+
const model = computed(() => {
|
|
17
|
+
const model: { [key: string]: any } = {}
|
|
18
|
+
props.fieldGroup?.fields.map((item: Fields) => {
|
|
19
|
+
return model[item.sourceId] = (props.entity && props.entity[item.sourceId]) || item.defaultValue || ''
|
|
20
|
+
})
|
|
21
|
+
return model
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const rules = computed((): FormRules => {
|
|
25
|
+
return props.fieldGroup?.fields.reduce((acc: any, item: Fields) => {
|
|
26
|
+
acc[item.sourceId] = [{ required: item.required, message: `请填写${item.title}` }]
|
|
27
|
+
return acc
|
|
28
|
+
}, {})
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
function submit() {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
form.value.validate().then(({ valid }: any) => {
|
|
34
|
+
if (valid) {
|
|
35
|
+
resolve(toRaw(model.value))
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
reject(valid)
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
.catch((error: any) => {
|
|
42
|
+
console.log(error, 'error')
|
|
43
|
+
reject(error)
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
// 暴露方法/变量给父组件
|
|
48
|
+
defineExpose({
|
|
49
|
+
submit,
|
|
50
|
+
})
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<template>
|
|
54
|
+
<view>
|
|
55
|
+
<wd-form ref="form" :model="model" :rules="rules" error-type="toast">
|
|
56
|
+
<wd-cell-group border>
|
|
57
|
+
<view v-for="item in props.fieldGroup?.fields" :key="item.sourceId">
|
|
58
|
+
<wd-input
|
|
59
|
+
v-if="item.extControlType === 'text'"
|
|
60
|
+
v-model="model[item.sourceId]"
|
|
61
|
+
:label="item.title"
|
|
62
|
+
label-width="100px"
|
|
63
|
+
:prop="item.sourceId"
|
|
64
|
+
:readonly="item.disabled"
|
|
65
|
+
:clearable="!item.disabled"
|
|
66
|
+
:placeholder="`请输入${item.title}`"
|
|
67
|
+
/>
|
|
68
|
+
<wd-cell v-if="item.extControlType === 'relselect'" :prop="item.sourceId" :title="item.title" title-width="100px">
|
|
69
|
+
<mulselectPicker v-model="model[item.sourceId]" :source-id="item.sourceId" :title="item.title" :ext-control-type="item.extControlType" :readonly="item.disabled" :clearable="!item.disabled" />
|
|
70
|
+
</wd-cell>
|
|
71
|
+
<wd-cell v-if="item.extControlType === 'relselectvalue'" :prop="item.sourceId" :title="item.title" title-width="100px">
|
|
72
|
+
<mulselectPicker v-model="model[item.sourceId]" :source-id="item.sourceId" :title="item.title" :ext-control-type="item.extControlType" :readonly="item.disabled" :clearable="!item.disabled" />
|
|
73
|
+
</wd-cell>
|
|
74
|
+
</view>
|
|
75
|
+
</wd-cell-group>
|
|
76
|
+
</wd-form>
|
|
77
|
+
</view>
|
|
78
|
+
</template>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed, defineOptions, defineProps, onMounted, reactive, ref } from 'vue'
|
|
3
|
+
import { onLoad, onShow } from '@dcloudio/uni-app'
|
|
4
|
+
import { useRouter } from 'uni-mini-router'
|
|
5
|
+
import { useManualTheme } from '../../composables/useManualTheme'
|
|
6
|
+
import { listData, pageConfig, pageKey } from '../../api/page'
|
|
7
|
+
import foldCard from '../fold-card/fold-card.vue'
|
|
8
|
+
import type { Config, Entities } from '../../type'
|
|
9
|
+
import Search from '../search/search.vue'
|
|
10
|
+
import ListTopButtons from '../list-top-buttons/list-top-buttons.vue'
|
|
11
|
+
|
|
12
|
+
defineOptions({
|
|
13
|
+
name: 'List',
|
|
14
|
+
})
|
|
15
|
+
const router = useRouter()
|
|
16
|
+
const Zpaging = ref<any>(null)
|
|
17
|
+
const config = ref<Config>({ buttons: [], columns: [], primaryColumn: { sourceId: '', controlType: '' }, primaryCriteria: { disabled: false, defaultValue: '', transDefaultValue: '', required: false, controlType: '', sourceId: '' }, secondColumn: { sourceId: '', controlType: '' }, criterias: [] })
|
|
18
|
+
const sourceId = ref('')
|
|
19
|
+
const datas = ref<Entities[]>([])
|
|
20
|
+
const pageTitle = ref('')
|
|
21
|
+
const searchData = ref('')
|
|
22
|
+
onLoad((option: any) => {
|
|
23
|
+
console.log(option)
|
|
24
|
+
sourceId.value = option.sourceId
|
|
25
|
+
pageTitle.value = option.title
|
|
26
|
+
uni.setNavigationBarTitle({
|
|
27
|
+
title: option.title,
|
|
28
|
+
})
|
|
29
|
+
getPageConfig()
|
|
30
|
+
})
|
|
31
|
+
onShow(() => {
|
|
32
|
+
if (Zpaging.value) {
|
|
33
|
+
Zpaging.value.reload()
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
async function getPageConfig() {
|
|
37
|
+
try {
|
|
38
|
+
const res = await pageConfig(sourceId.value)
|
|
39
|
+
if (res.ltmplConfig) {
|
|
40
|
+
config.value = res.ltmplConfig
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.log(error)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// @query所绑定的方法不要自己调用!!需要刷新列表数据时,只需要调用this.$refs.paging.reload()即可
|
|
49
|
+
async function queryList(pageNo: number, pageSize: number) {
|
|
50
|
+
// 此处请求仅为演示,请替换为自己项目中的请求
|
|
51
|
+
// request.queryList({ pageNo,pageSize }).then(res => {
|
|
52
|
+
// 将请求结果通过complete传给z-paging处理,同时也代表请求结束,这一行必须调用
|
|
53
|
+
// paging.value.complete(res.data.list);
|
|
54
|
+
// }).catch(res => {
|
|
55
|
+
// 如果请求失败写paging.value.complete(false);
|
|
56
|
+
// 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
|
57
|
+
// 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
|
58
|
+
// paging.value.complete(false);
|
|
59
|
+
// paging.value.reload() // 手动触发加载
|
|
60
|
+
// })
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
const res = await pageKey(sourceId.value, '', searchData.value)// 获取key
|
|
64
|
+
const data = await listData(res.key, pageNo, pageSize)// 获取数据
|
|
65
|
+
// const count = await getPageTotal(key.data?.key)// 获取总数
|
|
66
|
+
Zpaging.value.complete(data.entities)
|
|
67
|
+
|
|
68
|
+
// emits('loadData', data.data.entities)
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
Zpaging.value.complete(false)
|
|
72
|
+
console.error(error)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function submitSearch(data: any) {
|
|
77
|
+
searchData.value = ''
|
|
78
|
+
for (const key in data) {
|
|
79
|
+
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
80
|
+
const element = data[key]
|
|
81
|
+
searchData.value = `${searchData.value}&c_${key}=${element}`
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
Zpaging.value.reload()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 跳转编辑页面
|
|
88
|
+
function edit(item: Entities) {
|
|
89
|
+
router.push(`/pages/edit-page/edit-page?sourceId=${sourceId.value}&id=${item.code}&title=${pageTitle.value}&mainCode=''`)
|
|
90
|
+
}
|
|
91
|
+
</script>
|
|
92
|
+
|
|
93
|
+
<template>
|
|
94
|
+
<z-paging ref="Zpaging" v-model="datas" :show-loading-more-when-reload="true" @query="queryList">
|
|
95
|
+
<template #top>
|
|
96
|
+
<Search :criterias="config.criterias" :primary-criteria="config.primaryCriteria" @submit="submitSearch" />
|
|
97
|
+
<view>
|
|
98
|
+
<ListTopButtons :buttons="config.buttons" :source-id="sourceId" :page-title="pageTitle" />
|
|
99
|
+
</view>
|
|
100
|
+
<slot name="top" />
|
|
101
|
+
</template>
|
|
102
|
+
<foldCard v-for="item in datas" :key="item.code" :data="item" :columns="config.columns" :primary-column="config.primaryColumn" :second-column="config.secondColumn" model="complex">
|
|
103
|
+
<template #buttons>
|
|
104
|
+
<wd-button size="small" @click="edit(item)">
|
|
105
|
+
编辑
|
|
106
|
+
</wd-button>
|
|
107
|
+
</template>
|
|
108
|
+
</foldCard>
|
|
109
|
+
<template #bottom>
|
|
110
|
+
<slot name="bottom" />
|
|
111
|
+
</template>
|
|
112
|
+
</z-paging>
|
|
113
|
+
</template>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { defineOptions, defineProps } from 'vue'
|
|
3
|
+
import { useRouter } from 'uni-mini-router'
|
|
4
|
+
|
|
5
|
+
defineOptions({
|
|
6
|
+
name: 'ListTopButtons',
|
|
7
|
+
})
|
|
8
|
+
const props = defineProps<{ buttons: string[], sourceId: string, id?: string, pageTitle: string }>()
|
|
9
|
+
const router = useRouter()
|
|
10
|
+
// 跳转添加页面
|
|
11
|
+
function gotoAddPage() {
|
|
12
|
+
router.push(`/pages/edit-page/edit-page?sourceId=${props.sourceId}&id=${props.id}&title=${props.pageTitle}&mainCode=''`)
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<view class="flex justify-end gap-1 .light:bg-white">
|
|
18
|
+
<wd-button v-if="buttons.includes('dtmplAdd')" type="icon" icon="add" @click="gotoAddPage" />
|
|
19
|
+
</view>
|
|
20
|
+
</template>
|
|
@@ -9,7 +9,7 @@ import { useTabbar } from '../../composables/useTabbar'
|
|
|
9
9
|
defineOptions({
|
|
10
10
|
name: 'LoginForm',
|
|
11
11
|
})
|
|
12
|
-
|
|
12
|
+
const subloading = ref(false)
|
|
13
13
|
const router = useRouter()
|
|
14
14
|
const toast = useGlobalToast()
|
|
15
15
|
const { setUserInfo } = useUser()
|
|
@@ -31,6 +31,7 @@ function handleSubmit() {
|
|
|
31
31
|
.then(async ({ valid, errors }: any) => {
|
|
32
32
|
if (valid) {
|
|
33
33
|
try {
|
|
34
|
+
subloading.value = true
|
|
34
35
|
// 登录
|
|
35
36
|
const res = await login(model.name, model.password)
|
|
36
37
|
|
|
@@ -66,15 +67,19 @@ function handleSubmit() {
|
|
|
66
67
|
toast.error({ msg: res.message })
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
|
-
catch (error) {
|
|
70
|
+
catch (error: any) {
|
|
71
|
+
toast.error({ msg: error })
|
|
70
72
|
console.log(error, 'error')
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
else {
|
|
76
|
+
toast.error({ msg: errors })
|
|
74
77
|
console.log(errors, 'errors')
|
|
75
78
|
}
|
|
79
|
+
subloading.value = false
|
|
76
80
|
})
|
|
77
81
|
.catch((error: any) => {
|
|
82
|
+
toast.error({ msg: error })
|
|
78
83
|
console.log(error, 'error')
|
|
79
84
|
})
|
|
80
85
|
}
|
|
@@ -99,7 +104,7 @@ function handleSubmit() {
|
|
|
99
104
|
</view>
|
|
100
105
|
</wd-cell-group>
|
|
101
106
|
<view class="p-4">
|
|
102
|
-
<wd-button block @click="handleSubmit">
|
|
107
|
+
<wd-button block :loading="subloading" @click="handleSubmit">
|
|
103
108
|
登录
|
|
104
109
|
</wd-button>
|
|
105
110
|
</view>
|
|
@@ -4,7 +4,7 @@ import { computed, defineOptions, defineProps, onMounted, ref } from 'vue'
|
|
|
4
4
|
import { useRouter } from 'uni-mini-router'
|
|
5
5
|
import { useGlobalToast } from '../../composables/useGlobalToast'
|
|
6
6
|
import { menu } from '../../api/menu'
|
|
7
|
-
import
|
|
7
|
+
import DemoCard from '../demo-card/demo-card.vue'
|
|
8
8
|
|
|
9
9
|
defineOptions({
|
|
10
10
|
name: 'Menus',
|
|
@@ -19,7 +19,7 @@ const props = defineProps({
|
|
|
19
19
|
default: () => { },
|
|
20
20
|
},
|
|
21
21
|
})
|
|
22
|
-
|
|
22
|
+
const router = useRouter()
|
|
23
23
|
// const toast = useGlobalToast()
|
|
24
24
|
interface Icon {
|
|
25
25
|
id: string
|
|
@@ -56,26 +56,17 @@ function sheetGotoPage(item: any) {
|
|
|
56
56
|
|
|
57
57
|
// 跳转页面
|
|
58
58
|
function goto(item: any) {
|
|
59
|
-
return
|
|
60
59
|
console.log(item.pageType)
|
|
61
60
|
switch (item.pageType) {
|
|
62
61
|
case '列表':
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
url: `/${item.customPath}`,
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
uni.navigateTo({
|
|
70
|
-
url: `/pages/table/table?sourceId=${item.id}&pageTitle=${item.title}`,
|
|
71
|
-
})
|
|
72
|
-
}
|
|
62
|
+
|
|
63
|
+
router.push(`/pages/list/index?sourceId=${item.id}&title=${item.title}`)
|
|
73
64
|
|
|
74
65
|
return true
|
|
75
66
|
|
|
76
67
|
case '报表':
|
|
77
68
|
uni.navigateTo({
|
|
78
|
-
url: `/pages/report-table/report-table?sourceId=${item.id}&
|
|
69
|
+
url: `/pages/report-table/report-table?sourceId=${item.id}&title=${item.title}`,
|
|
79
70
|
})
|
|
80
71
|
return true
|
|
81
72
|
|
|
@@ -162,16 +153,30 @@ function queryList() {
|
|
|
162
153
|
<slot name="top" />
|
|
163
154
|
</template>
|
|
164
155
|
<view>
|
|
165
|
-
<
|
|
166
|
-
<
|
|
167
|
-
<
|
|
168
|
-
<wd-grid
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
156
|
+
<DemoCard v-for="(item, index) in filtermenu" :key="index" :title="item.title">
|
|
157
|
+
<template #content>
|
|
158
|
+
<view class="border-rd-2 bg-white pa-1 dark:bg-[var(--wot-dark-background2)]">
|
|
159
|
+
<wd-grid :column="4" clickable>
|
|
160
|
+
<wd-grid-item
|
|
161
|
+
v-for="(subItem, subIndex) in item.items"
|
|
162
|
+
:key="subIndex" use-text-slot use-icon-slot
|
|
163
|
+
@itemclick="gotoPage(subItem)"
|
|
164
|
+
>
|
|
165
|
+
<template #icon>
|
|
166
|
+
<text class="i-carbon:container-image text-center text-5 text-gray-600 dark:text-white" />
|
|
167
|
+
</template>
|
|
168
|
+
<template #text>
|
|
169
|
+
<view class="pa-2 text-center text-gray-600 dark:text-white">
|
|
170
|
+
<text class="font-bold">
|
|
171
|
+
{{ subItem.title }}
|
|
172
|
+
</text>
|
|
173
|
+
</view>
|
|
174
|
+
</template>
|
|
175
|
+
</wd-grid-item>
|
|
176
|
+
</wd-grid>
|
|
177
|
+
</view>
|
|
178
|
+
</template>
|
|
179
|
+
</DemoCard>
|
|
175
180
|
<slot name="listBottom" />
|
|
176
181
|
</view>
|
|
177
182
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, defineOptions, defineProps, onMounted, ref, toRaw, watch } from 'vue'
|
|
3
|
+
import { useRouter } from 'uni-mini-router'
|
|
4
|
+
|
|
5
|
+
defineOptions({
|
|
6
|
+
name: 'MulselectPicker',
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
const props = defineProps<{
|
|
10
|
+
extControlType: string
|
|
11
|
+
sourceId: string
|
|
12
|
+
title?: string
|
|
13
|
+
modelValue: string | Array<string>
|
|
14
|
+
readonly: boolean
|
|
15
|
+
clearable: boolean
|
|
16
|
+
}>()
|
|
17
|
+
const emits = defineEmits<{
|
|
18
|
+
(e: 'update:modelValue', value: string | string[]): void
|
|
19
|
+
}>()
|
|
20
|
+
const selectData = ref<string | string[]>(props.modelValue)
|
|
21
|
+
const selectformatData = computed(() => {
|
|
22
|
+
if (Array.isArray(selectData.value)) {
|
|
23
|
+
return selectData.value.map(item => item.split('@R@')[1]).join(',')
|
|
24
|
+
}
|
|
25
|
+
return selectData.value.split('@R@')[1] || ''
|
|
26
|
+
})
|
|
27
|
+
const router = useRouter()
|
|
28
|
+
// 事件名称
|
|
29
|
+
const SELECTEVENT = 'select-list-goto-select'
|
|
30
|
+
const SENDSELECTEVENT = 'select-list-send-selected'
|
|
31
|
+
function gotoSlect() {
|
|
32
|
+
if (props.readonly)
|
|
33
|
+
return
|
|
34
|
+
router.push(`/pages/select-list/index?sourceId=${props.sourceId}&title=${props.title}&selectEvent=${SELECTEVENT}&sendSelectEvent=${SENDSELECTEVENT}&extControlType=${props.extControlType}`)
|
|
35
|
+
// 发送数据给选择页面,延迟发送防止页面不刷新
|
|
36
|
+
setTimeout(() => {
|
|
37
|
+
uni.$emit(SENDSELECTEVENT, toRaw(selectData.value))
|
|
38
|
+
}, 100)
|
|
39
|
+
|
|
40
|
+
// 接收勾选页面发送过来的数据
|
|
41
|
+
uni.$once(SELECTEVENT, (data: any) => {
|
|
42
|
+
selectData.value = data
|
|
43
|
+
emits('update:modelValue', data)
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 清空勾选
|
|
48
|
+
function clearSelect() {
|
|
49
|
+
// 清空单选
|
|
50
|
+
if (props.extControlType === 'relselect') {
|
|
51
|
+
selectData.value = ''
|
|
52
|
+
emits('update:modelValue', '')
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
selectData.value = []
|
|
56
|
+
emits('update:modelValue', [])
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<template>
|
|
62
|
+
<view class="relative" @click="gotoSlect">
|
|
63
|
+
<view class="flex flex-wrap text-left">
|
|
64
|
+
<text v-if="selectformatData">
|
|
65
|
+
{{ selectformatData }}
|
|
66
|
+
</text>
|
|
67
|
+
<text v-else class="text-gray-400">
|
|
68
|
+
请选择{{ title }}
|
|
69
|
+
</text>
|
|
70
|
+
</view>
|
|
71
|
+
<view v-if="clearable" class="absolute bottom-0 right-0 top-0">
|
|
72
|
+
<wd-icon v-if="selectformatData" name="error-fill" size="17px" @click.stop="clearSelect" />
|
|
73
|
+
<wd-icon v-else name="arrow-right" size="17px" />
|
|
74
|
+
</view>
|
|
75
|
+
</view>
|
|
76
|
+
</template>
|
|
77
|
+
|
|
78
|
+
<style scoped>
|
|
79
|
+
:deep(.wd-tag__close){
|
|
80
|
+
line-height:0.6
|
|
81
|
+
}
|
|
82
|
+
</style>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { defineEmits, defineOptions, defineProps, ref } from 'vue'
|
|
3
|
+
import type { Fields } from '../../type'
|
|
4
|
+
import formControl from '../form-control/form-control.vue'
|
|
5
|
+
|
|
6
|
+
defineOptions({ name: 'Search' })
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
criterias: Fields[]
|
|
9
|
+
primaryCriteria: Fields
|
|
10
|
+
}>()
|
|
11
|
+
const emits = defineEmits(['submit'])
|
|
12
|
+
const show = ref(false)
|
|
13
|
+
const search = ref('')
|
|
14
|
+
const formControlRef = ref()
|
|
15
|
+
const entity = ref({})
|
|
16
|
+
const filterCriterias = computed(() => {
|
|
17
|
+
return props.criterias.filter(item => item.sourceId !== props.primaryCriteria.sourceId)
|
|
18
|
+
})
|
|
19
|
+
function handleClose() {
|
|
20
|
+
show.value = false
|
|
21
|
+
}
|
|
22
|
+
function handleSubmit() {
|
|
23
|
+
if (!formControlRef.value) {
|
|
24
|
+
const data = {
|
|
25
|
+
[props.primaryCriteria.sourceId]: search.value,
|
|
26
|
+
}
|
|
27
|
+
emits('submit', data)
|
|
28
|
+
handleClose()
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
formControlRef.value.submit().then((fdata: any) => {
|
|
32
|
+
entity.value = {
|
|
33
|
+
...fdata,
|
|
34
|
+
[props.primaryCriteria.sourceId]: search.value,
|
|
35
|
+
}
|
|
36
|
+
const data = {
|
|
37
|
+
[props.primaryCriteria.sourceId]: search.value,
|
|
38
|
+
}
|
|
39
|
+
filterCriterias.value.forEach((item) => {
|
|
40
|
+
for (const key in fdata) {
|
|
41
|
+
if (Object.prototype.hasOwnProperty.call(fdata, key)) {
|
|
42
|
+
const element = fdata[key]
|
|
43
|
+
if (item.sourceId === key) {
|
|
44
|
+
if (item.extControlType === 'relselectvalue') {
|
|
45
|
+
data[item.sourceId] = element.map((item: string) => {
|
|
46
|
+
return item.split('@R@')[1]
|
|
47
|
+
}).join('@,@')
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
emits('submit', data)
|
|
55
|
+
handleClose()
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<template>
|
|
61
|
+
<view v-if="primaryCriteria.controlType === 'text'">
|
|
62
|
+
<wd-search v-model="search" cancel-txt="搜索" :placeholder="`请输入${primaryCriteria.title}搜索`" @clear="handleSubmit" @cancel="handleSubmit">
|
|
63
|
+
<template #prefix>
|
|
64
|
+
<view class="search-type">
|
|
65
|
+
<!-- <wd-icon custom-class="icon-arrow" name="fill-arrow-down" /> -->
|
|
66
|
+
<wd-icon name="view-list" size="18px" class=".dark:text-white .light:text-black" @click="show = true" />
|
|
67
|
+
</view>
|
|
68
|
+
</template>
|
|
69
|
+
</wd-search>
|
|
70
|
+
<wd-popup v-model="show" position="bottom" custom-class="h-80vh" closable @close="handleClose">
|
|
71
|
+
<view class="relative box-border h-full p-1 .dark:bg-gray-900">
|
|
72
|
+
<view class="h-40px" />
|
|
73
|
+
<formControl ref="formControlRef" :field-group="{ fields: filterCriterias, id: '', buttons: [], title: '', type: '', pointSourceId: '' }" :entity="entity" />
|
|
74
|
+
<view class="h-12" />
|
|
75
|
+
<view class="fixed bottom-0 left-0 right-0 box-border w-100% flex p-2 .dark:bg-gray-900 .light:bg-white">
|
|
76
|
+
<wd-button class="flex-1" @click="handleSubmit">
|
|
77
|
+
确定
|
|
78
|
+
</wd-button>
|
|
79
|
+
</view>
|
|
80
|
+
</view>
|
|
81
|
+
</wd-popup>
|
|
82
|
+
</view>
|
|
83
|
+
</template>
|
|
84
|
+
|
|
85
|
+
<style>
|
|
86
|
+
.search-type {
|
|
87
|
+
position: relative;
|
|
88
|
+
height: 30px;
|
|
89
|
+
line-height: 30px;
|
|
90
|
+
padding: 0 8px 0 16px;
|
|
91
|
+
}
|
|
92
|
+
.search-type::after {
|
|
93
|
+
position: absolute;
|
|
94
|
+
content: '';
|
|
95
|
+
width: 1px;
|
|
96
|
+
right: 0;
|
|
97
|
+
top: 5px;
|
|
98
|
+
bottom: 5px;
|
|
99
|
+
/* background: rgba(0, 0, 0, 0.25); */
|
|
100
|
+
}
|
|
101
|
+
.search-type {
|
|
102
|
+
:deep(.icon-arrow) {
|
|
103
|
+
display: inline-block;
|
|
104
|
+
font-size: 20px;
|
|
105
|
+
vertical-align: middle;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
</style>
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed, defineOptions, defineProps, nextTick, onMounted, onUnmounted, reactive, ref, toRaw } from 'vue'
|
|
3
|
+
import { onLoad } from '@dcloudio/uni-app'
|
|
4
|
+
import { useRouter } from 'uni-mini-router'
|
|
5
|
+
import { useManualTheme } from '../../composables/useManualTheme'
|
|
6
|
+
import { listData, pageConfig, pageKey } from '../../api/page'
|
|
7
|
+
import foldCard from '../fold-card/fold-card.vue'
|
|
8
|
+
import type { Config, Entities } from '../../type'
|
|
9
|
+
import { useGlobalToast } from '../../composables/useGlobalToast'
|
|
10
|
+
|
|
11
|
+
defineOptions({
|
|
12
|
+
name: 'SelectList',
|
|
13
|
+
})
|
|
14
|
+
const globalToast = useGlobalToast()
|
|
15
|
+
const router = useRouter()
|
|
16
|
+
const Zpaging = ref<any>(null)
|
|
17
|
+
const config = ref<Config>({ columns: [], primaryColumn: { sourceId: '', controlType: '' }, secondColumn: { sourceId: '', controlType: '' } })
|
|
18
|
+
const sourceId = ref('')
|
|
19
|
+
const datas = ref<Entities[]>([])
|
|
20
|
+
const pageTitle = ref('')
|
|
21
|
+
const selectEvent = ref('')
|
|
22
|
+
const sendSelectEvent = ref('')
|
|
23
|
+
const extControlType = ref('')// 选择模式,例如:单选、多选
|
|
24
|
+
onLoad((option: any) => {
|
|
25
|
+
sourceId.value = option.sourceId
|
|
26
|
+
pageTitle.value = option.title
|
|
27
|
+
selectEvent.value = option.selectEvent
|
|
28
|
+
sendSelectEvent.value = option.sendSelectEvent
|
|
29
|
+
extControlType.value = option.extControlType
|
|
30
|
+
uni.setNavigationBarTitle({
|
|
31
|
+
title: `选择${option.title}`,
|
|
32
|
+
})
|
|
33
|
+
getPageConfig()
|
|
34
|
+
})
|
|
35
|
+
const selectData = ref<Record<string, string>>({})// 选择数据
|
|
36
|
+
onMounted(() => {
|
|
37
|
+
// selectData.value = { '447607223953539077': '447607223953539077@R@光机' }
|
|
38
|
+
})
|
|
39
|
+
uni.$once(sendSelectEvent.value, async (data: string | string[]) => {
|
|
40
|
+
if (!data)
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
if (Array.isArray(data)) {
|
|
44
|
+
const newdata: Record<string, string> = {}
|
|
45
|
+
data.forEach((item) => {
|
|
46
|
+
newdata[item.split('@R@')[0]] = item
|
|
47
|
+
})
|
|
48
|
+
selectData.value = newdata
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
selectData.value[data.split('@R@')[0]] = data
|
|
52
|
+
}
|
|
53
|
+
uni.$off(sendSelectEvent.value)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
async function getPageConfig() {
|
|
57
|
+
try {
|
|
58
|
+
const res = await pageConfig(sourceId.value)
|
|
59
|
+
if (res.ltmplConfig) {
|
|
60
|
+
config.value = res.ltmplConfig
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
console.log(error)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// @query所绑定的方法不要自己调用!!需要刷新列表数据时,只需要调用this.$refs.paging.reload()即可
|
|
69
|
+
async function queryList(pageNo: number, pageSize: number) {
|
|
70
|
+
// 此处请求仅为演示,请替换为自己项目中的请求
|
|
71
|
+
// request.queryList({ pageNo,pageSize }).then(res => {
|
|
72
|
+
// 将请求结果通过complete传给z-paging处理,同时也代表请求结束,这一行必须调用
|
|
73
|
+
// paging.value.complete(res.data.list);
|
|
74
|
+
// }).catch(res => {
|
|
75
|
+
// 如果请求失败写paging.value.complete(false);
|
|
76
|
+
// 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
|
77
|
+
// 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
|
78
|
+
// paging.value.complete(false);
|
|
79
|
+
// paging.value.reload() // 手动触发加载
|
|
80
|
+
// })
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const res = await pageKey(sourceId.value)// 获取key
|
|
84
|
+
const data = await listData(res.key, pageNo, pageSize)// 获取数据
|
|
85
|
+
// const count = await getPageTotal(key.data?.key)// 获取总数
|
|
86
|
+
Zpaging.value.complete(data.entities)
|
|
87
|
+
|
|
88
|
+
// emits('loadData', data.data.entities)
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
Zpaging.value.complete(false)
|
|
92
|
+
console.error(error)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 跳转编辑页面
|
|
97
|
+
function edit(item: Entities) {
|
|
98
|
+
router.push(`/pages/edit-page/edit-page?sourceId=${sourceId.value}&mainCode=${item.code}`)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 勾选变换监听
|
|
102
|
+
function handleChange(item: Entities) {
|
|
103
|
+
// 判断是否有当前选中值,有值则删除
|
|
104
|
+
if (selectData.value[item.code]) {
|
|
105
|
+
delete selectData.value[item.code]
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 判断是否为单选,清空选项
|
|
110
|
+
if (extControlType.value === 'relselect') {
|
|
111
|
+
selectData.value = {}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
selectData.value[item.code] = `${item.code}@R@${item.fieldMap[config.value.primaryColumn.sourceId]}`
|
|
115
|
+
}
|
|
116
|
+
// 发送选中数据
|
|
117
|
+
function send() {
|
|
118
|
+
const data = Object.values(selectData.value)
|
|
119
|
+
if (!data.length) {
|
|
120
|
+
globalToast.warning(`请选择${pageTitle.value}`)
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 判断是否为单选,是:发送字符串,否:发送数组
|
|
125
|
+
if (extControlType.value === 'relselect') {
|
|
126
|
+
uni.$emit(selectEvent.value, data[0])
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
uni.$emit(selectEvent.value, data)
|
|
130
|
+
}
|
|
131
|
+
router.back()
|
|
132
|
+
}
|
|
133
|
+
// 取消
|
|
134
|
+
// function cancel() {
|
|
135
|
+
// send('cancel')
|
|
136
|
+
// router.back()
|
|
137
|
+
// }
|
|
138
|
+
// 确定
|
|
139
|
+
function confirm() {
|
|
140
|
+
send()
|
|
141
|
+
}
|
|
142
|
+
onUnmounted(() => {
|
|
143
|
+
console.log('unmounted')
|
|
144
|
+
uni.$off(selectEvent.value)
|
|
145
|
+
})
|
|
146
|
+
</script>
|
|
147
|
+
|
|
148
|
+
<template>
|
|
149
|
+
<z-paging ref="Zpaging" v-model="datas" :show-loading-more-when-reload="true" @query="queryList">
|
|
150
|
+
<template #top>
|
|
151
|
+
<slot name="top" />
|
|
152
|
+
</template>
|
|
153
|
+
|
|
154
|
+
<foldCard v-for="item in datas" :key="item.code" :data="item" :columns="config.columns" :primary-column="config.primaryColumn" :second-column="config.secondColumn" model="simple" @click="() => { handleChange(item) }">
|
|
155
|
+
<template #select>
|
|
156
|
+
<wd-checkbox :true-value="`${item.code}@R@${item.fieldMap[config.primaryColumn.sourceId]}`" false-value="" :model-value="selectData[item.code]" />
|
|
157
|
+
</template>
|
|
158
|
+
<template #buttons>
|
|
159
|
+
<wd-button size="small" @click="edit(item)">
|
|
160
|
+
编辑
|
|
161
|
+
</wd-button>
|
|
162
|
+
</template>
|
|
163
|
+
</foldCard>
|
|
164
|
+
|
|
165
|
+
<template #bottom>
|
|
166
|
+
<slot name="bottom">
|
|
167
|
+
<view class="flex justify-between gap-1 p-2">
|
|
168
|
+
<!-- <wd-button class="flex-1" type="info" @click="cancel">
|
|
169
|
+
取消
|
|
170
|
+
</wd-button> -->
|
|
171
|
+
<wd-button class="flex-1" @click="confirm">
|
|
172
|
+
确定
|
|
173
|
+
</wd-button>
|
|
174
|
+
</view>
|
|
175
|
+
</slot>
|
|
176
|
+
</template>
|
|
177
|
+
</z-paging>
|
|
178
|
+
</template>
|
package/index.ts
CHANGED
|
@@ -15,6 +15,9 @@ import { req } from './api/index'
|
|
|
15
15
|
import { useTabbar } from './composables/useTabbar'
|
|
16
16
|
import { persistPlugin } from './store/persist'
|
|
17
17
|
import DemoBlock from './components/demo-block/demo-block.vue'
|
|
18
|
+
import List from './components/list/list.vue'
|
|
19
|
+
import selectList from './components/select-list/select-list.vue'
|
|
20
|
+
import editPage from './components/edit-page/edit-page.vue'
|
|
18
21
|
// 组件列表
|
|
19
22
|
const coms: Array<{ name: string }> = [
|
|
20
23
|
SystemSettings,
|
|
@@ -24,6 +27,9 @@ const coms: Array<{ name: string }> = [
|
|
|
24
27
|
LayoutsDefault,
|
|
25
28
|
Tabbar,
|
|
26
29
|
DemoBlock,
|
|
30
|
+
List,
|
|
31
|
+
selectList,
|
|
32
|
+
editPage,
|
|
27
33
|
]
|
|
28
34
|
|
|
29
35
|
/**
|
package/package.json
CHANGED
package/type.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// 列表字段配置
|
|
2
|
+
export interface Columns {
|
|
3
|
+
controlType: string
|
|
4
|
+
extControlType?: string
|
|
5
|
+
sourceId: string
|
|
6
|
+
mstrucId?: string
|
|
7
|
+
title?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface Config {
|
|
11
|
+
columns: Columns[]
|
|
12
|
+
primaryColumn: Columns
|
|
13
|
+
primaryCriteria: Fields
|
|
14
|
+
secondColumn: Columns
|
|
15
|
+
criterias: Fields[]
|
|
16
|
+
buttons: string[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 列表数据
|
|
20
|
+
export interface Entities {
|
|
21
|
+
code: string
|
|
22
|
+
fieldMap: { [key: string]: string }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 列表页面数据
|
|
26
|
+
export interface PageData {
|
|
27
|
+
entities: Entities
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 表单字段配置
|
|
31
|
+
export interface Fields extends Columns {
|
|
32
|
+
disabled: boolean
|
|
33
|
+
defaultValue: string
|
|
34
|
+
transDefaultValue: string
|
|
35
|
+
required: boolean
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface Groups {
|
|
39
|
+
id: string
|
|
40
|
+
buttons: string[]
|
|
41
|
+
fields: Fields[]
|
|
42
|
+
title: string
|
|
43
|
+
type: string
|
|
44
|
+
pointSourceId: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface Entity extends Entities {
|
|
48
|
+
arrayMap: { [key: string]: Entities[] }
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 编辑页面配置
|
|
53
|
+
export interface dtmplConfig {
|
|
54
|
+
id: string
|
|
55
|
+
title: string
|
|
56
|
+
groups: Groups[]
|
|
57
|
+
entity: Entity
|
|
58
|
+
buttons: string[]
|
|
59
|
+
}
|
package/utils/index.ts
CHANGED
|
@@ -1,9 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { isArray } from '@alova/shared'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 获取当前页面路径
|
|
5
|
+
* @returns 当前页面路径
|
|
6
|
+
*/
|
|
7
|
+
export function getCurrentPath() {
|
|
8
|
+
const pages = getCurrentPages()
|
|
9
|
+
const currentPage = pages[pages.length - 1]
|
|
10
|
+
return currentPage.route || ''
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 格式化列表项展示数据
|
|
15
|
+
* @param data 数据值
|
|
16
|
+
* @param type 数据类型
|
|
17
|
+
* @returns 格式化后的数据
|
|
18
|
+
*/
|
|
19
|
+
export function formatItemData(data: any, type: string) {
|
|
20
|
+
if (type === 'relselect') {
|
|
21
|
+
// 判断data是否为数组
|
|
22
|
+
if (isArray(data)) {
|
|
23
|
+
const dataArr = data.map(item => item.split('@R@')[1]).join(',')
|
|
24
|
+
return dataArr
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return data ? data.split('@R@')[1] : ''
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (type === 'datetime') {
|
|
31
|
+
return data ? data.split('.')[0] : ''
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return data
|
|
35
|
+
}
|