ShippingTemplateList.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. <template>
  2. <div class="shipping-template-management">
  3. <h2>运费模板管理</h2>
  4. <!-- 模式切换 -->
  5. <el-radio-group v-model="currentMode" style="margin-bottom: 20px;">
  6. <el-radio-button label="create">创建模板</el-radio-button>
  7. <el-radio-button label="edit">编辑模板</el-radio-button>
  8. </el-radio-group>
  9. <!-- 创建模板 -->
  10. <shipping-template-form
  11. v-if="currentMode === 'create'"
  12. :key="formKey"
  13. @save="handleSave"
  14. @cancel="handleCancel"
  15. />
  16. <!-- 编辑模板 -->
  17. <div v-else-if="currentMode === 'edit'">
  18. <!-- 模板选择 -->
  19. <el-card shadow="never" class="mb-4">
  20. <template #header>
  21. <div class="card-sub-header">
  22. <span>选择要编辑的模板</span>
  23. </div>
  24. </template>
  25. <el-form :model="selectedTemplateForm" label-width="120px">
  26. <el-row :gutter="20">
  27. <el-col :span="12">
  28. <el-form-item label="选择模板">
  29. <el-select
  30. v-model="selectedTemplateForm.id"
  31. placeholder="请选择要编辑的模板"
  32. style="width: 100%"
  33. @change="handleTemplateSelect"
  34. >
  35. <el-option
  36. v-for="template in templateList"
  37. :key="template.id"
  38. :label="template.name"
  39. :value="template.id"
  40. />
  41. </el-select>
  42. </el-form-item>
  43. </el-col>
  44. <el-col :span="12">
  45. <el-form-item label="操作">
  46. <el-button
  47. type="danger"
  48. :disabled="!selectedTemplateForm.id"
  49. @click="handleDeleteTemplate"
  50. >
  51. 删除选中模板
  52. </el-button>
  53. </el-form-item>
  54. </el-col>
  55. </el-row>
  56. </el-form>
  57. </el-card>
  58. <!-- 模板编辑表单 -->
  59. <shipping-template-form
  60. v-if="editTemplateData"
  61. :key="formKey"
  62. :template-data="editTemplateData"
  63. :loading="loading"
  64. @save="handleSave"
  65. @cancel="handleCancel"
  66. />
  67. <!-- 加载提示 -->
  68. <div v-if="loading && !editTemplateData" class="loading-container">
  69. <el-skeleton animated />
  70. </div>
  71. </div>
  72. </div>
  73. </template>
  74. <script setup lang="ts">
  75. import {onMounted, reactive, ref, watch} from 'vue'
  76. import {ElMessage, ElMessageBox} from 'element-plus'
  77. import ShippingTemplateForm from './ShippingTemplateForm.vue'
  78. import {
  79. createShippingTemplate,
  80. deleteShippingTemplate,
  81. getShippingTemplateDetail,
  82. getShippingTemplateList,
  83. updateShippingTemplate
  84. } from '../api/index.js'
  85. // 当前模式
  86. const currentMode = ref('create')
  87. const formKey = ref(0)
  88. const loading = ref(false)
  89. // 选中的模板表单
  90. const selectedTemplateForm = reactive({
  91. id: null
  92. })
  93. // 编辑模板数据
  94. const editTemplateData = ref(null)
  95. // 模板列表
  96. const templateList = ref([])
  97. // 监听模式变化,当模式切换时更新key强制重新渲染组件
  98. watch(currentMode, (newMode, oldMode) => {
  99. // 当在create和edit之间切换时,更新key值强制组件重新渲染
  100. if ((newMode === 'create' || newMode === 'edit') && (oldMode === 'create' || oldMode === 'edit')) {
  101. formKey.value += 1
  102. // 重置编辑相关数据
  103. if (newMode === 'edit') {
  104. selectedTemplateForm.id = null
  105. editTemplateData.value = null
  106. }
  107. }
  108. // 根据模式加载相应数据
  109. loadDataForMode(newMode)
  110. })
  111. // 组件挂载时加载初始数据
  112. onMounted(() => {
  113. loadDataForMode(currentMode.value)
  114. })
  115. // 根据当前模式加载数据
  116. const loadDataForMode = async (mode) => {
  117. if (mode === 'edit') {
  118. // 加载模板列表数据
  119. await loadTemplateList()
  120. }
  121. }
  122. // 加载模板列表数据
  123. const loadTemplateList = async () => {
  124. loading.value = true
  125. try {
  126. // 这里需要传入实际的bizType和bizId参数
  127. // 示例中使用默认值
  128. const response = await getShippingTemplateList('product', 1)
  129. if (response.code === 200) {
  130. templateList.value = response.data.map(item => ({
  131. id: item.id,
  132. name: item.name
  133. }))
  134. } else {
  135. throw new Error(response.msg || '获取模板列表失败')
  136. }
  137. } catch (error) {
  138. console.error('加载模板列表失败:', error)
  139. ElMessage.error('模板列表加载失败: ' + (error.message || '未知错误'))
  140. } finally {
  141. loading.value = false
  142. }
  143. }
  144. // 处理模板选择
  145. const handleTemplateSelect = async (templateId) => {
  146. if (!templateId) {
  147. editTemplateData.value = null
  148. return
  149. }
  150. loading.value = true
  151. try {
  152. await loadEditTemplateData(templateId)
  153. } catch (error) {
  154. console.error('加载模板详情失败:', error)
  155. ElMessage.error('模板详情加载失败: ' + (error.message || '未知错误'))
  156. selectedTemplateForm.id = null
  157. } finally {
  158. loading.value = false
  159. }
  160. }
  161. // 加载编辑模板数据
  162. const loadEditTemplateData = async (templateId) => {
  163. try {
  164. const response = await getShippingTemplateDetail(templateId)
  165. if (response.code === 200) {
  166. // 转换API返回的数据格式以适配组件
  167. const templateData = response.data
  168. editTemplateData.value = {
  169. templateInfo: {
  170. id: templateData.id,
  171. name: templateData.name,
  172. calcMethod: templateData.calc_method,
  173. unit: templateData.unit
  174. },
  175. defaultRule: {
  176. first: Number(templateData.default_rule.first) || 1,
  177. firstPrice: Number(templateData.default_rule.first_price) || 0,
  178. nextPrice: Number(templateData.default_rule.next_price) || 0
  179. },
  180. specialAreas: Array.isArray(templateData.special_areas)
  181. ? templateData.special_areas.map(area => ({
  182. area_name: area.area_name || area.name || '', // 优先使用area_name字段
  183. regions: Array.isArray(area.regions)
  184. ? area.regions.map(region => ({
  185. province_id: region.province_id,
  186. province_name: region.province_name,
  187. city_id: region.city_id,
  188. city_name: region.city_name,
  189. area_id: region.area_id,
  190. area_name: region.area_name
  191. }))
  192. : [],
  193. first: Number(area.first) || 1,
  194. firstPrice: Number(area.first_price) || 0,
  195. nextPrice: Number(area.next_price) || 0
  196. }))
  197. : []
  198. }
  199. } else {
  200. throw new Error(response.msg || '获取模板详情失败')
  201. }
  202. } catch (error) {
  203. throw error
  204. }
  205. }
  206. // 处理保存模板(创建或编辑)
  207. const handleSave = async (templateData: any) => {
  208. try {
  209. let response;
  210. // 准备提交数据
  211. const submitData = {
  212. name: templateData.templateInfo.name,
  213. calc_method: templateData.templateInfo.calcMethod,
  214. unit: templateData.templateInfo.unit,
  215. sort: 100,
  216. default_rule: {
  217. first: templateData.defaultRule.first,
  218. first_price: templateData.defaultRule.firstPrice,
  219. next_price: templateData.defaultRule.nextPrice
  220. },
  221. special_areas: Array.isArray(templateData.specialAreas)
  222. ? templateData.specialAreas.map((area: any) => ({
  223. area_name: area.area_name,
  224. first: area.first,
  225. first_price: area.firstPrice,
  226. next_price: area.nextPrice,
  227. regions: Array.isArray(area.regions)
  228. ? area.regions
  229. .filter((region: any) => region && region.province_id)
  230. .map((region: any) => ({
  231. province_id: region.province_id || null,
  232. province_name: region.province_name || '',
  233. city_id: region.city_id || null,
  234. city_name: region.city_name || null,
  235. area_id: region.area_id || null,
  236. area_name: region.area_name || null
  237. }))
  238. : []
  239. }))
  240. : []
  241. }
  242. // 调试日志,查看提交的数据结构
  243. console.log('提交数据结构:', submitData);
  244. console.log('templateData:', templateData);
  245. // 根据当前模式判断是创建还是更新模板
  246. if (currentMode.value === 'edit' && templateData.templateInfo.id) {
  247. // 更新模板
  248. response = await updateShippingTemplate(templateData.templateInfo.id, submitData)
  249. } else {
  250. // 创建模板
  251. response = await createShippingTemplate(submitData)
  252. }
  253. if (response.code === 200) {
  254. const message = currentMode.value === 'edit' && templateData.templateInfo.id ? '模板更新成功' : '模板创建成功'
  255. ElMessage.success(message)
  256. // 如果是创建模板,重置表单
  257. if (currentMode.value === 'create') {
  258. formKey.value += 1 // 通过更新key来重置表单
  259. }
  260. // 如果是编辑模板,刷新模板列表
  261. if (currentMode.value === 'edit') {
  262. await loadTemplateList()
  263. }
  264. console.log('保存模板:', templateData)
  265. } else {
  266. ElMessage.error(response.msg || '操作失败')
  267. }
  268. } catch (error) {
  269. console.error('保存模板失败:', error)
  270. ElMessage.error('操作失败: ' + (error.message || '未知错误'))
  271. }
  272. }
  273. // 处理取消操作
  274. const handleCancel = () => {
  275. ElMessage.info('操作已取消')
  276. console.log('取消操作')
  277. // 重置选择
  278. if (currentMode.value === 'edit') {
  279. selectedTemplateForm.id = null
  280. editTemplateData.value = null
  281. } else if (currentMode.value === 'create') {
  282. // 在创建模式下,重置表单
  283. formKey.value += 1 // 通过更新key来重置表单
  284. }
  285. }
  286. // 处理删除模板
  287. const handleDeleteTemplate = async () => {
  288. if (!selectedTemplateForm.id) {
  289. ElMessage.warning('请先选择要删除的模板')
  290. return
  291. }
  292. try {
  293. // 获取选中模板的名称用于提示
  294. const selectedTemplate = templateList.value.find(t => t.id === selectedTemplateForm.id)
  295. const templateName = selectedTemplate ? selectedTemplate.name : '未知模板'
  296. await ElMessageBox.confirm(
  297. `确定要删除运费模板"${templateName}"吗?此操作不可恢复!`,
  298. '删除确认',
  299. {
  300. type: 'warning',
  301. confirmButtonText: '确定删除',
  302. cancelButtonText: '取消'
  303. }
  304. )
  305. const response = await deleteShippingTemplate(selectedTemplateForm.id)
  306. if (response.code === 200) {
  307. ElMessage.success('模板删除成功')
  308. // 重置选择
  309. selectedTemplateForm.id = null
  310. editTemplateData.value = null
  311. // 重新加载模板列表
  312. await loadTemplateList()
  313. } else {
  314. throw new Error(response.msg || '删除失败')
  315. }
  316. } catch (error) {
  317. if (error !== 'cancel') {
  318. console.error('删除模板失败:', error)
  319. ElMessage.error('删除失败: ' + (error.message || '未知错误'))
  320. }
  321. }
  322. }
  323. </script>
  324. <style scoped lang="scss">
  325. .shipping-template-management {
  326. padding: 20px;
  327. h2 {
  328. margin-bottom: 20px;
  329. color: #303133;
  330. }
  331. .card-sub-header {
  332. font-size: 16px;
  333. font-weight: bold;
  334. }
  335. .loading-container {
  336. padding: 20px;
  337. }
  338. .mb-4 {
  339. margin-bottom: 1rem;
  340. }
  341. }
  342. </style>