review:“新增 iframe 和省市区选择器组件”

This commit is contained in:
YunaiV
2026-02-08 14:37:55 +08:00
parent c119040307
commit c153ff93c7
4 changed files with 22 additions and 31 deletions

View File

@@ -18,6 +18,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref, watch } from 'vue' import { onMounted, ref, watch } from 'vue'
import { getAreaTree } from '@/api/system/area' import { getAreaTree } from '@/api/system/area'
// TODO @puhui999这里 handleTree 貌似没用到
import { handleTree } from '@/utils/tree' import { handleTree } from '@/utils/tree'
defineOptions({ name: 'AreaSelect' }) defineOptions({ name: 'AreaSelect' })
@@ -34,7 +35,7 @@ interface AreaVO {
interface Props { interface Props {
modelValue?: number[] | string[] modelValue?: number[] | string[]
level?: 1 | 2 | 3 // 1-省 2-市 3-区 level?: 1 | 2 | 3 // 1-省 2-市 3-区 TODO @puhui999这里是不是放到枚举类里
disabled?: boolean disabled?: boolean
placeholder?: string placeholder?: string
clearable?: boolean clearable?: boolean
@@ -45,7 +46,7 @@ interface Props {
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
modelValue: undefined, modelValue: undefined,
level: 3, level: 3, // TODO @puhui999枚举类
disabled: false, disabled: false,
placeholder: '请选择省市区', placeholder: '请选择省市区',
clearable: true, clearable: true,
@@ -57,28 +58,23 @@ const emit = defineEmits<{
(e: 'update:modelValue', value: number[] | string[] | undefined): void (e: 'update:modelValue', value: number[] | string[] | undefined): void
}>() }>()
// Element Plus Cascader 的 props 配置
const cascaderProps = { const cascaderProps = {
label: 'name', label: 'name',
value: 'id', value: 'id',
children: 'children', children: 'children',
checkStrictly: true, // 允许选择任意级别 checkStrictly: true, // 允许选择任意级别
emitPath: true // 返回完整路径 emitPath: true // 返回完整路径
} } // Element Plus Cascader 的 props 配置
// 地区树形数据 const areaTree = ref<AreaVO[]>([]) // 地区树形数据
const areaTree = ref<AreaVO[]>([]) const selectedValue = ref<number[] | undefined>() // 当前选中值
// 当前选中值 const loading = ref(false) // 加载状态
const selectedValue = ref<number[] | undefined>()
// 加载状态
const loading = ref(false)
// 加载地区树形数据 /** 加载地区树形数据 */
async function loadAreaTree(): Promise<void> { async function loadAreaTree(): Promise<void> {
try { try {
loading.value = true loading.value = true
const data = await getAreaTree() const data = await getAreaTree()
// 根据 level 限制层级 // 根据 level 限制层级
areaTree.value = filterTreeByLevel(data || [], props.level) areaTree.value = filterTreeByLevel(data || [], props.level)
} catch (error) { } catch (error) {
@@ -89,13 +85,13 @@ async function loadAreaTree(): Promise<void> {
} }
} }
// 根据层级过滤树形数据 /** 根据层级过滤树形数据 */
function filterTreeByLevel(tree: AreaVO[], maxLevel: number): AreaVO[] { function filterTreeByLevel(tree: AreaVO[], maxLevel: number): AreaVO[] {
if (maxLevel <= 0) return [] if (maxLevel <= 0) {
return []
}
return tree.map((node) => { return tree.map((node) => {
const newNode = { ...node } const newNode = { ...node }
// 如果当前是最后一层,移除 children // 如果当前是最后一层,移除 children
if (maxLevel === 1) { if (maxLevel === 1) {
delete newNode.children delete newNode.children
@@ -103,25 +99,22 @@ function filterTreeByLevel(tree: AreaVO[], maxLevel: number): AreaVO[] {
// 递归处理子节点 // 递归处理子节点
newNode.children = filterTreeByLevel(node.children, maxLevel - 1) newNode.children = filterTreeByLevel(node.children, maxLevel - 1)
} }
return newNode return newNode
}) })
} }
// 处理选中值变化 /** 处理选中值变化 */
function handleChange(value: number[] | undefined): void { function handleChange(value: number[] | undefined): void {
if (value === undefined || value === null) { if (value === undefined || value === null) {
emit('update:modelValue', undefined) emit('update:modelValue', undefined)
return return
} }
emit('update:modelValue', value) emit('update:modelValue', value)
} }
// 同步 modelValue 到内部选中值 /** 同步 modelValue 到内部选中值 */
function syncSelectedValue(): void { function syncSelectedValue(): void {
const newValue = props.modelValue const newValue = props.modelValue
if (newValue === undefined || newValue === null) { if (newValue === undefined || newValue === null) {
selectedValue.value = undefined selectedValue.value = undefined
return return
@@ -135,10 +128,10 @@ function syncSelectedValue(): void {
} }
} }
// 监听 modelValue 变化 /** 监听 modelValue 变化 */
watch(() => props.modelValue, syncSelectedValue, { immediate: true }) watch(() => props.modelValue, syncSelectedValue, { immediate: true })
// 组件挂载时加载数据 /** 组件挂载时加载数据 */
onMounted(async () => { onMounted(async () => {
await loadAreaTree() await loadAreaTree()
}) })

View File

@@ -23,6 +23,7 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
// TODO @AI多余的变量需要删除
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
defineOptions({ name: 'IframeComponent' }) defineOptions({ name: 'IframeComponent' })
@@ -50,19 +51,18 @@ const props = withDefaults(defineProps<Props>(), {
sandbox: '' sandbox: ''
}) })
// TODO @puhui999这里貌似暂时没用到
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:modelValue', value: string): void (e: 'update:modelValue', value: string): void
}>() }>()
// 显示的 URL优先使用 url prop其次使用 modelValue const displayUrl = computed(() => props.url || props.modelValue || '') // 显示的 URL优先使用 url prop其次使用 modelValue
const displayUrl = computed(() => props.url || props.modelValue || '')
// 是否显示预览
const showPreview = computed(() => { const showPreview = computed(() => {
return displayUrl.value && isValidUrl(displayUrl.value) return displayUrl.value && isValidUrl(displayUrl.value)
}) }) // 是否显示预览
// URL 验证 // TODO @puhui999看看全局是不是有可复用的方法
/** URL 验证 */
function isValidUrl(url: string): boolean { function isValidUrl(url: string): boolean {
if (!url || url.trim() === '') return false if (!url || url.trim() === '') return false
try { try {

View File

@@ -7,7 +7,6 @@ import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils
export const useAreaSelectRule = () => { export const useAreaSelectRule = () => {
const label = '省市区选择器' const label = '省市区选择器'
const name = 'AreaSelect' const name = 'AreaSelect'
return { return {
icon: 'icon-location', icon: 'icon-location',
label, label,

View File

@@ -7,7 +7,6 @@ import { localeProps, makeRequiredRule } from '@/components/FormCreate/src/utils
export const useIframeRule = () => { export const useIframeRule = () => {
const label = '网页 iframe' const label = '网页 iframe'
const name = 'IframeComponent' const name = 'IframeComponent'
return { return {
icon: 'icon-link', icon: 'icon-link',
label, label,