|
|
@@ -17,7 +17,10 @@
|
|
|
<div v-if="loading && !tree.length" class="mp-product-loading">
|
|
|
<van-loading vertical>正在加载分类</van-loading>
|
|
|
</div>
|
|
|
- <van-empty v-else-if="!flatNodes.length" description="暂无分类,点击右上角新增">
|
|
|
+ <van-empty
|
|
|
+ v-else-if="!flatNodes.length"
|
|
|
+ description="暂无分类,点击右上角「新增」创建顶级分类"
|
|
|
+ >
|
|
|
<van-button round type="primary" @click="openAdd()">新增分类</van-button>
|
|
|
</van-empty>
|
|
|
<div v-else class="mp-cat-tree">
|
|
|
@@ -77,6 +80,7 @@
|
|
|
v-model:show="actionOpen"
|
|
|
teleport="body"
|
|
|
:actions="actionSheetActions"
|
|
|
+ :description="actionSheetDescription"
|
|
|
cancel-text="取消"
|
|
|
close-on-click-action
|
|
|
@select="onActionSelect"
|
|
|
@@ -101,14 +105,23 @@
|
|
|
/>
|
|
|
<div class="mp-customer-pool-vant__body">
|
|
|
<van-cell-group inset>
|
|
|
- <van-field
|
|
|
- is-link
|
|
|
- readonly
|
|
|
- label="上级分类"
|
|
|
- :model-value="parentLabel"
|
|
|
- placeholder="选择上级分类(留空为顶级)"
|
|
|
- @click="parentPickerOpen = true"
|
|
|
- />
|
|
|
+ <van-field label="上级分类" label-align="top">
|
|
|
+ <template #input>
|
|
|
+ <el-tree-select
|
|
|
+ v-model="formData.parentId"
|
|
|
+ :data="categoryTreeOptions"
|
|
|
+ node-key="id"
|
|
|
+ :props="{ label: 'categoryName', children: 'children' }"
|
|
|
+ value-key="id"
|
|
|
+ check-strictly
|
|
|
+ filterable
|
|
|
+ clearable
|
|
|
+ placeholder="选择上级分类(留空为顶级)"
|
|
|
+ style="width: 100%"
|
|
|
+ teleported
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </van-field>
|
|
|
<van-field
|
|
|
v-model="formData.categoryName"
|
|
|
label="分类名称"
|
|
|
@@ -122,14 +135,23 @@
|
|
|
label="排序号"
|
|
|
placeholder="数值越小越靠前"
|
|
|
/>
|
|
|
- <van-field
|
|
|
- is-link
|
|
|
- readonly
|
|
|
- label="状态"
|
|
|
- :model-value="statusLabel"
|
|
|
- placeholder="请选择状态"
|
|
|
- @click="statusPickerOpen = true"
|
|
|
- />
|
|
|
+ <van-field label="状态" label-align="top">
|
|
|
+ <template #input>
|
|
|
+ <el-select
|
|
|
+ v-model="formData.status"
|
|
|
+ placeholder="请选择状态"
|
|
|
+ style="width: 100%"
|
|
|
+ teleported
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="opt in dictStore.getOptions('sys_normal_disable')"
|
|
|
+ :key="opt.value"
|
|
|
+ :label="opt.label"
|
|
|
+ :value="opt.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ </van-field>
|
|
|
<van-field
|
|
|
v-model="formData.remark"
|
|
|
rows="3"
|
|
|
@@ -148,24 +170,6 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
</van-popup>
|
|
|
-
|
|
|
- <van-popup v-model:show="parentPickerOpen" position="bottom" round teleport="body">
|
|
|
- <van-picker
|
|
|
- :columns="parentPickerColumns"
|
|
|
- :model-value="[formData.parentId || '0']"
|
|
|
- @confirm="onParentConfirm"
|
|
|
- @cancel="parentPickerOpen = false"
|
|
|
- />
|
|
|
- </van-popup>
|
|
|
-
|
|
|
- <van-popup v-model:show="statusPickerOpen" position="bottom" round teleport="body">
|
|
|
- <van-picker
|
|
|
- :columns="statusPickerColumns"
|
|
|
- :model-value="[formData.status || '0']"
|
|
|
- @confirm="onStatusConfirm"
|
|
|
- @cancel="statusPickerOpen = false"
|
|
|
- />
|
|
|
- </van-popup>
|
|
|
</div>
|
|
|
</MpWebviewShell>
|
|
|
</template>
|
|
|
@@ -224,9 +228,7 @@
|
|
|
const formTitle = ref('')
|
|
|
const submitLoading = ref(false)
|
|
|
const nameError = ref('')
|
|
|
- const parentPickerOpen = ref(false)
|
|
|
- const statusPickerOpen = ref(false)
|
|
|
- const flatParentOptions = ref<Array<{ text: string; value: string }>>([])
|
|
|
+ const categoryTreeOptions = ref<CategoryNode[]>([])
|
|
|
const formData = reactive({
|
|
|
id: '',
|
|
|
parentId: '' as string,
|
|
|
@@ -247,6 +249,10 @@
|
|
|
canDeleteByCreator(actionNode.value as Record<string, unknown> | null)
|
|
|
)
|
|
|
|
|
|
+ const actionSheetDescription = computed(() =>
|
|
|
+ canDeleteActionNode.value ? undefined : CREATOR_DELETE_TIP
|
|
|
+ )
|
|
|
+
|
|
|
const actionSheetActions = computed(() => [
|
|
|
{ name: '新增子级', value: 'add' },
|
|
|
{ name: '编辑', value: 'edit' },
|
|
|
@@ -258,28 +264,6 @@
|
|
|
}
|
|
|
])
|
|
|
|
|
|
- const parentPickerColumns = computed(() => [
|
|
|
- { text: '顶级分类', value: '0' },
|
|
|
- ...flatParentOptions.value
|
|
|
- ])
|
|
|
-
|
|
|
- const statusPickerColumns = computed(() =>
|
|
|
- dictStore.getOptions('sys_normal_disable').map((o) => ({
|
|
|
- text: o.label,
|
|
|
- value: String(o.value)
|
|
|
- }))
|
|
|
- )
|
|
|
-
|
|
|
- const parentLabel = computed(() => {
|
|
|
- const id = formData.parentId || '0'
|
|
|
- if (id === '0' || !id) return '顶级分类'
|
|
|
- return parentPickerColumns.value.find((c) => c.value === id)?.text || id
|
|
|
- })
|
|
|
-
|
|
|
- const statusLabel = computed(() => {
|
|
|
- return dictStore.getLabel('sys_normal_disable', formData.status) || ''
|
|
|
- })
|
|
|
-
|
|
|
const flatNodes = computed((): FlatItem[] => {
|
|
|
const out: FlatItem[] = []
|
|
|
const walk = (nodes: CategoryNode[], depth: number) => {
|
|
|
@@ -300,14 +284,6 @@
|
|
|
return 'success'
|
|
|
}
|
|
|
|
|
|
- function flattenParents(nodes: CategoryNode[], parents: string[] = []): Array<{ text: string; value: string }> {
|
|
|
- return nodes.flatMap((node) => {
|
|
|
- const path = [...parents, String(node.categoryName || '')].filter(Boolean)
|
|
|
- const current = node.id ? [{ text: path.join(' / '), value: String(node.id) }] : []
|
|
|
- return current.concat(flattenParents(node.children || [], path))
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
const expandAllLabel = computed(() =>
|
|
|
areAllExpandableExpanded(tree.value, expandedIds.value) ? '全部折叠' : '全部展开'
|
|
|
)
|
|
|
@@ -332,10 +308,17 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async function refreshParentOptions() {
|
|
|
+ async function getCategoryTreeSelect() {
|
|
|
const res = await fetchCategoryTree({})
|
|
|
const data = ((res as { data?: CategoryNode[] }).data || res || []) as CategoryNode[]
|
|
|
- flatParentOptions.value = flattenParents(Array.isArray(data) ? data : [])
|
|
|
+ categoryTreeOptions.value = [
|
|
|
+ {
|
|
|
+ id: '0',
|
|
|
+ categoryName: '顶级分类',
|
|
|
+ parentId: '0',
|
|
|
+ children: Array.isArray(data) ? data : []
|
|
|
+ }
|
|
|
+ ]
|
|
|
}
|
|
|
|
|
|
function toggleExpand(id: string) {
|
|
|
@@ -366,7 +349,7 @@
|
|
|
async function openAdd(parentRow?: CategoryNode) {
|
|
|
actionOpen.value = false
|
|
|
resetForm()
|
|
|
- await refreshParentOptions()
|
|
|
+ await getCategoryTreeSelect()
|
|
|
if (parentRow?.id) formData.parentId = parentRow.id
|
|
|
formTitle.value = '新增产品分类'
|
|
|
formOpen.value = true
|
|
|
@@ -375,7 +358,7 @@
|
|
|
async function openEdit(node: CategoryNode) {
|
|
|
actionOpen.value = false
|
|
|
resetForm()
|
|
|
- await refreshParentOptions()
|
|
|
+ await getCategoryTreeSelect()
|
|
|
formData.id = node.id
|
|
|
formData.parentId = node.parentId || ''
|
|
|
formData.categoryName = node.categoryName || ''
|
|
|
@@ -391,12 +374,24 @@
|
|
|
actionOpen.value = true
|
|
|
}
|
|
|
|
|
|
- function onActionSelect(action: { value?: string }) {
|
|
|
+ function onActionSelect(action: { value?: string; disabled?: boolean }) {
|
|
|
const node = actionNode.value
|
|
|
if (!node) return
|
|
|
- if (action.value === 'add') void openAdd(node)
|
|
|
- else if (action.value === 'edit') void openEdit(node)
|
|
|
- else if (action.value === 'delete') void onActionDelete()
|
|
|
+ if (action.value === 'add') {
|
|
|
+ void openAdd(node)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (action.value === 'edit') {
|
|
|
+ void openEdit(node)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (action.value === 'delete') {
|
|
|
+ if (!canDeleteActionNode.value || action.disabled) {
|
|
|
+ showFailToast(CREATOR_DELETE_TIP)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ void onActionDelete()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
async function onActionDelete() {
|
|
|
@@ -428,15 +423,6 @@
|
|
|
function closeForm() {
|
|
|
if (!submitLoading.value) formOpen.value = false
|
|
|
}
|
|
|
- function onParentConfirm({ selectedValues }: { selectedValues: string[] }) {
|
|
|
- const v = selectedValues[0] || '0'
|
|
|
- formData.parentId = v === '0' ? '' : v
|
|
|
- parentPickerOpen.value = false
|
|
|
- }
|
|
|
- function onStatusConfirm({ selectedValues }: { selectedValues: string[] }) {
|
|
|
- formData.status = selectedValues[0] || '0'
|
|
|
- statusPickerOpen.value = false
|
|
|
- }
|
|
|
|
|
|
async function submitForm() {
|
|
|
if (!formData.categoryName.trim()) {
|