From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/components/AppLinkInput/AppLinkSelectDialog.vue |  211 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 211 insertions(+), 0 deletions(-)

diff --git a/src/components/AppLinkInput/AppLinkSelectDialog.vue b/src/components/AppLinkInput/AppLinkSelectDialog.vue
new file mode 100644
index 0000000..5211f74
--- /dev/null
+++ b/src/components/AppLinkInput/AppLinkSelectDialog.vue
@@ -0,0 +1,211 @@
+<template>
+  <Dialog v-model="dialogVisible" title="閫夋嫨閾炬帴" width="65%">
+    <div class="h-500px flex gap-8px">
+      <!-- 宸︿晶鍒嗙粍鍒楄〃 -->
+      <el-scrollbar wrap-class="h-full" ref="groupScrollbar" view-class="flex flex-col">
+        <el-button
+          v-for="(group, groupIndex) in APP_LINK_GROUP_LIST"
+          :key="groupIndex"
+          :class="[
+            'm-r-16px m-l-0px! justify-start! w-90px',
+            { active: activeGroup === group.name }
+          ]"
+          ref="groupBtnRefs"
+          :text="activeGroup !== group.name"
+          :type="activeGroup === group.name ? 'primary' : 'default'"
+          @click="handleGroupSelected(group.name)"
+        >
+          {{ group.name }}
+        </el-button>
+      </el-scrollbar>
+      <!-- 鍙充晶閾炬帴鍒楄〃 -->
+      <el-scrollbar class="h-full flex-1" @scroll="handleScroll" ref="linkScrollbar">
+        <div v-for="(group, groupIndex) in APP_LINK_GROUP_LIST" :key="groupIndex">
+          <!-- 鍒嗙粍鏍囬 -->
+          <div class="font-bold" ref="groupTitleRefs">{{ group.name }}</div>
+          <!-- 閾炬帴鍒楄〃 -->
+          <el-tooltip
+            v-for="(appLink, appLinkIndex) in group.links"
+            :key="appLinkIndex"
+            :content="appLink.path"
+            placement="bottom"
+            :show-after="300"
+          >
+            <el-button
+              class="m-b-8px m-r-8px m-l-0px!"
+              :type="isSameLink(appLink.path, activeAppLink.path) ? 'primary' : 'default'"
+              @click="handleAppLinkSelected(appLink)"
+            >
+              {{ appLink.name }}
+            </el-button>
+          </el-tooltip>
+        </div>
+      </el-scrollbar>
+    </div>
+    <!-- 搴曢儴瀵硅瘽妗嗘搷浣滄寜閽� -->
+    <template #footer>
+      <el-button type="primary" @click="handleSubmit">纭� 瀹�</el-button>
+      <el-button @click="dialogVisible = false">鍙� 娑�</el-button>
+    </template>
+  </Dialog>
+  <Dialog v-model="detailSelectDialog.visible" title="" width="50%">
+    <el-form class="min-h-200px">
+      <el-form-item
+        label="閫夋嫨鍒嗙被"
+        v-if="detailSelectDialog.type === APP_LINK_TYPE_ENUM.PRODUCT_CATEGORY_LIST"
+      >
+        <ProductCategorySelect
+          v-model="detailSelectDialog.id"
+          :parent-id="0"
+          @update:model-value="handleProductCategorySelected"
+        />
+      </el-form-item>
+    </el-form>
+  </Dialog>
+</template>
+<script lang="ts" setup>
+import { APP_LINK_GROUP_LIST, APP_LINK_TYPE_ENUM, AppLink } from './data'
+import { ButtonInstance, ScrollbarInstance } from 'element-plus'
+import { split } from 'lodash-es'
+import ProductCategorySelect from '@/views/mall/product/category/components/ProductCategorySelect.vue'
+import { getUrlNumberValue } from '@/utils'
+
+// APP 閾炬帴閫夋嫨寮规
+defineOptions({ name: 'AppLinkSelectDialog' })
+// 閫変腑鐨勫垎缁勶紝榛樿閫変腑绗竴涓�
+const activeGroup = ref(APP_LINK_GROUP_LIST[0].name)
+// 閫変腑鐨� APP 閾炬帴
+const activeAppLink = ref({} as AppLink)
+
+/** 鎵撳紑寮圭獥 */
+const dialogVisible = ref(false)
+const open = (link: string) => {
+  // 杩涘叆椤甸潰鏃跺厛閲嶇疆 activeAppLink
+  activeAppLink.value = { name: '', path: '' }
+  dialogVisible.value = true
+
+  // 婊氬姩鍒板綋鍓嶇殑閾炬帴
+  const group = APP_LINK_GROUP_LIST.find((group) =>
+    group.links.some((linkItem) => {
+      const sameLink = isSameLink(linkItem.path, link)
+      if (sameLink) {
+        activeAppLink.value = { ...linkItem, path: link }
+      }
+      return sameLink
+    })
+  )
+  if (group) {
+    // 浣跨敤 nextTick 鐨勫師鍥狅細鍙兘 Dom 杩樻病鐢熸垚锛屽鑷存粴鍔ㄥけ璐�
+    nextTick(() => handleGroupSelected(group.name))
+  }
+}
+defineExpose({ open })
+
+// 澶勭悊 APP 閾炬帴閫変腑
+const handleAppLinkSelected = (appLink: AppLink) => {
+  // 鍙湁涓嶅悓閾炬帴鏃舵墠鏇存柊锛堥伩鍏嶉噸澶嶈Е鍙戯級
+  if (!isSameLink(appLink.path, activeAppLink.value.path)) {
+    // 濡傛灉鏂伴摼鎺ョ殑 path 涓虹┖锛屽垯娌跨敤褰撳墠 activeAppLink 鐨� path
+    const path = appLink.path || activeAppLink.value.path
+    activeAppLink.value = { ...appLink, path: path }
+  }
+  switch (appLink.type) {
+    case APP_LINK_TYPE_ENUM.PRODUCT_CATEGORY_LIST:
+      detailSelectDialog.value.visible = true
+      detailSelectDialog.value.type = appLink.type
+      // 杩旀樉
+      detailSelectDialog.value.id =
+        getUrlNumberValue('id', 'http://127.0.0.1' + activeAppLink.value.path) || undefined
+      break
+    default:
+      break
+  }
+}
+
+// 澶勭悊缁戝畾鍊兼洿鏂�
+const emit = defineEmits<{
+  change: [link: string]
+  appLinkChange: [appLink: AppLink]
+}>()
+const handleSubmit = () => {
+  dialogVisible.value = false
+  emit('change', activeAppLink.value.path)
+  emit('appLinkChange', activeAppLink.value)
+}
+
+// 鍒嗙粍鏍囬寮曠敤鍒楄〃
+const groupTitleRefs = ref<HTMLInputElement[]>([])
+/**
+ * 澶勭悊鍙充晶閾炬帴鍒楄〃婊氬姩
+ * @param scrollTop 婊氬姩鏉$殑浣嶇疆
+ */
+const handleScroll = ({ scrollTop }: { scrollTop: number }) => {
+  const titleEl = groupTitleRefs.value.find((titleEl: HTMLInputElement) => {
+    // 鑾峰彇鏍囬鐨勪綅缃俊鎭�
+    const { offsetHeight, offsetTop } = titleEl
+    // 鍒ゆ柇鏍囬鏄惁鍦ㄥ彲瑙嗚寖鍥村唴
+    return scrollTop >= offsetTop && scrollTop < offsetTop + offsetHeight
+  })
+  // 鍙渶澶勭悊涓�娆�
+  if (titleEl && activeGroup.value !== titleEl.textContent) {
+    activeGroup.value = titleEl.textContent || ''
+    // 鍚屾宸︿晶鐨勬粴鍔ㄦ潯浣嶇疆
+    scrollToGroupBtn(activeGroup.value)
+  }
+}
+
+// 鍙充晶婊氬姩鏉�
+const linkScrollbar = ref<ScrollbarInstance>()
+// 澶勭悊鍒嗙粍閫変腑
+const handleGroupSelected = (group: string) => {
+  activeGroup.value = group
+  const titleRef = groupTitleRefs.value.find((item: HTMLInputElement) => item.textContent === group)
+  if (titleRef) {
+    // 婊氬姩鍒嗙粍鏍囬
+    linkScrollbar.value?.setScrollTop(titleRef.offsetTop)
+  }
+}
+
+// 鍒嗙粍婊氬姩鏉�
+const groupScrollbar = ref<ScrollbarInstance>()
+// 鍒嗙粍寮曠敤鍒楄〃
+const groupBtnRefs = ref<ButtonInstance[]>([])
+// 鑷姩婊氬姩鍒嗙粍鎸夐挳锛岀‘淇濆垎缁勬寜閽繚鎸佸湪鍙鍖哄煙鍐�
+const scrollToGroupBtn = (group: string) => {
+  const groupBtn = groupBtnRefs.value
+    .map((btn: ButtonInstance) => btn['ref'])
+    .find((ref: HTMLButtonElement) => ref.textContent === group)
+  if (groupBtn) {
+    groupScrollbar.value?.setScrollTop(groupBtn.offsetTop)
+  }
+}
+
+// 鏄惁涓虹浉鍚岀殑閾炬帴锛堜笉姣旇緝鍙傛暟锛屽彧姣旇緝閾炬帴锛�
+const isSameLink = (link1: string, link2: string) => {
+  return split(link1, '?', 1)[0] === split(link2, '?', 1)[0]
+}
+
+// 璇︽儏閫夋嫨瀵硅瘽妗�
+const detailSelectDialog = ref<{
+  visible: boolean
+  id?: number
+  type?: APP_LINK_TYPE_ENUM
+}>({
+  visible: false,
+  id: undefined,
+  type: undefined
+})
+// 澶勭悊璇︽儏閫夋嫨
+const handleProductCategorySelected = (id: number) => {
+  const url = new URL(activeAppLink.value.path, 'http://127.0.0.1')
+  // 淇敼 id 鍙傛暟
+  url.searchParams.set('id', `${id}`)
+  // 鎺掗櫎鍩熷悕
+  activeAppLink.value.path = `${url.pathname}${url.search}`
+  // 鍏抽棴瀵硅瘽妗�
+  detailSelectDialog.value.visible = false
+  // 閲嶇疆 id
+  detailSelectDialog.value.id = undefined
+}
+</script>
+<style lang="scss" scoped></style>

--
Gitblit v1.8.0