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

---
 src/views/mall/product/spu/form/InfoForm.vue |  153 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 153 insertions(+), 0 deletions(-)

diff --git a/src/views/mall/product/spu/form/InfoForm.vue b/src/views/mall/product/spu/form/InfoForm.vue
new file mode 100644
index 0000000..9a9fbfd
--- /dev/null
+++ b/src/views/mall/product/spu/form/InfoForm.vue
@@ -0,0 +1,153 @@
+<!-- 鍟嗗搧鍙戝竷 - 鍩虹璁剧疆 -->
+<template>
+  <el-form ref="formRef" :disabled="isDetail" :model="formData" :rules="rules" label-width="120px">
+    <el-form-item label="鍟嗗搧鍚嶇О" prop="name">
+      <el-input
+        v-model="formData.name"
+        :autosize="{ minRows: 2, maxRows: 2 }"
+        :clearable="true"
+        :show-word-limit="true"
+        class="w-80!"
+        maxlength="64"
+        placeholder="璇疯緭鍏ュ晢鍝佸悕绉�"
+        type="textarea"
+      />
+    </el-form-item>
+    <el-form-item label="鍟嗗搧鍒嗙被" prop="categoryId">
+      <el-cascader
+        v-model="formData.categoryId"
+        :options="categoryList"
+        :props="defaultProps"
+        class="w-80!"
+        clearable
+        filterable
+        placeholder="璇烽�夋嫨鍟嗗搧鍒嗙被"
+      />
+      <el-button :icon="RefreshRight" @click="refreshCategoryList" class="ml-1" size="small" />
+    </el-form-item>
+    <el-form-item label="鍟嗗搧鍝佺墝" prop="brandId">
+      <el-select v-model="formData.brandId" class="w-80!" placeholder="璇烽�夋嫨鍟嗗搧鍝佺墝">
+        <el-option
+          v-for="item in brandList"
+          :key="item.id"
+          :label="item.name"
+          :value="item.id as number"
+        />
+      </el-select>
+      <el-button :icon="RefreshRight" @click="refreshBrandList" class="ml-1" size="small" />
+    </el-form-item>
+    <el-form-item label="鍟嗗搧鍏抽敭瀛�" prop="keyword">
+      <el-input v-model="formData.keyword" class="w-80!" placeholder="璇疯緭鍏ュ晢鍝佸叧閿瓧" />
+    </el-form-item>
+    <el-form-item label="鍟嗗搧绠�浠�" prop="introduction">
+      <el-input
+        v-model="formData.introduction"
+        :autosize="{ minRows: 2, maxRows: 2 }"
+        :clearable="true"
+        :show-word-limit="true"
+        class="w-80!"
+        maxlength="128"
+        placeholder="璇疯緭鍏ュ晢鍝佺畝浠�"
+        type="textarea"
+      />
+    </el-form-item>
+    <el-form-item label="鍟嗗搧灏侀潰鍥�" prop="picUrl">
+      <UploadImg v-model="formData.picUrl" :disabled="isDetail" height="80px" />
+    </el-form-item>
+    <el-form-item label="鍟嗗搧杞挱鍥�" prop="sliderPicUrls">
+      <UploadImgs v-model="formData.sliderPicUrls" :disabled="isDetail" />
+    </el-form-item>
+  </el-form>
+</template>
+<script lang="ts" setup>
+import { PropType } from 'vue'
+import { copyValueToTarget } from '@/utils'
+import { propTypes } from '@/utils/propTypes'
+import { defaultProps, handleTree } from '@/utils/tree'
+import type { Spu } from '@/api/mall/product/spu'
+import * as ProductCategoryApi from '@/api/mall/product/category'
+import { CategoryVO } from '@/api/mall/product/category'
+import * as ProductBrandApi from '@/api/mall/product/brand'
+import { BrandVO } from '@/api/mall/product/brand'
+import { RefreshRight } from '@element-plus/icons-vue'
+
+defineOptions({ name: 'ProductSpuInfoForm' })
+const props = defineProps({
+  propFormData: {
+    type: Object as PropType<Spu>,
+    default: () => {}
+  },
+  isDetail: propTypes.bool.def(false) // 鏄惁浣滀负璇︽儏缁勪欢
+})
+
+const message = useMessage() // 娑堟伅寮圭獥
+
+const formRef = ref() // 琛ㄥ崟 Ref
+const formData = reactive<Spu>({
+  name: '', // 鍟嗗搧鍚嶇О
+  categoryId: undefined, // 鍟嗗搧鍒嗙被
+  keyword: '', // 鍏抽敭瀛�
+  picUrl: '', // 鍟嗗搧灏侀潰鍥�
+  sliderPicUrls: [], // 鍟嗗搧杞挱鍥�
+  introduction: '', // 鍟嗗搧绠�浠�
+  brandId: undefined // 鍟嗗搧鍝佺墝
+})
+const rules = reactive({
+  name: [required],
+  categoryId: [required],
+  keyword: [required],
+  introduction: [required],
+  picUrl: [required],
+  sliderPicUrls: [required],
+  brandId: [required]
+})
+
+/** 灏嗕紶杩涙潵鐨勫�艰祴鍊肩粰 formData */
+watch(
+  () => props.propFormData,
+  (data) => {
+    if (!data) {
+      return
+    }
+    copyValueToTarget(formData, data)
+  },
+  {
+    immediate: true
+  }
+)
+
+/** 琛ㄥ崟鏍¢獙 */
+const emit = defineEmits(['update:activeName'])
+const validate = async () => {
+  if (!formRef) return
+  try {
+    await unref(formRef)?.validate()
+    // 鏍¢獙閫氳繃鏇存柊鏁版嵁
+    Object.assign(props.propFormData, formData)
+  } catch (e) {
+    message.error('銆愬熀纭�璁剧疆銆戜笉瀹屽杽锛岃濉啓鐩稿叧淇℃伅')
+    emit('update:activeName', 'info')
+    throw e // 鐩殑鎴柇涔嬪悗鐨勬牎楠�
+  }
+}
+defineExpose({ validate })
+
+/** 鍒濆鍖� */
+const brandList = ref<BrandVO[]>([]) // 鍟嗗搧鍝佺墝鍒楄〃
+const categoryList = ref<CategoryVO[]>([]) // 鍟嗗搧鍒嗙被鏍�
+async function refreshCategoryList() {
+  // 鑾峰緱鍒嗙被鏍�
+  const data = await ProductCategoryApi.getCategoryList({})
+  categoryList.value = handleTree(data, 'id')
+}
+
+async function refreshBrandList() {
+  brandList.value = await ProductBrandApi.getSimpleBrandList()
+}
+
+onMounted(async () => {
+  await refreshCategoryList()
+  // 鑾峰彇鍟嗗搧鍝佺墝鍒楄〃
+  await refreshBrandList()
+})
+</script>

--
Gitblit v1.8.0