返回 AiToEarn
1 /**
2 * 品牌推广模块 Store
3 * 管理草稿箱列表、弹窗状态
4 */
5
6 import type {
7 IBrandPromotionStoreState,
8 PromotionPlan,
9 } from './types'
10 import lodash from 'lodash'
11 import { create } from 'zustand'
12 import { combine } from 'zustand/middleware'
13 import {
14 apiCreateMaterialGroup,
15 apiDeleteMaterialGroup,
16 apiGetMaterialGroupList,
17 apiUpdateMaterialGroupInfo,
18 } from '@/api/materials/material.api'
19 import { PubType } from '@/app/config/publishConfig'
20 import { usePlanTabStore } from '../planTabStore'
21
22 // 初始状态
23 const initialState: IBrandPromotionStoreState = {
24 // 草稿箱列表状态
25 plans: [],
26 plansLoading: false,
27 plansPagination: {
28 current: 1,
29 pageSize: 9,
30 total: 0,
31 hasMore: true,
32 },
33
34 // 弹窗状态
35 createPlanModalOpen: false,
36 editingPlan: null,
37
38 // 加载状态
39 isSubmitting: false,
40 }
41
42 function getInitialState() {
43 return lodash.cloneDeep(initialState)
44 }
45
46 export const useBrandPromotionStore = create(
47 combine(getInitialState(), (set, get) => {
48 const methods = {
49 // ==================== 草稿箱方法 ====================
50
51 /**
52 * 获取草稿箱列表
53 */
54 fetchPlans: async (page: number = 1) => {
55 set({ plansLoading: true })
56 try {
57 const { plansPagination } = get()
58 const res = await apiGetMaterialGroupList(page, plansPagination.pageSize)
59 const list = (res?.data?.list || []) as PromotionPlan[]
60 const total = res?.data?.total || 0
61
62 set({
63 plans: list,
64 plansPagination: {
65 ...plansPagination,
66 current: page,
67 total,
68 hasMore: list.length === plansPagination.pageSize,
69 },
70 })
71 }
72 catch {
73 // 错误由调用方处理
74 }
75 finally {
76 set({ plansLoading: false })
77 }
78 },
79
80 /**
81 * 创建草稿箱
82 */
83 createPlan: async (data: {
84 name: string
85 }): Promise<boolean> => {
86 set({ isSubmitting: true })
87 try {
88 const res = await apiCreateMaterialGroup(data)
89 if (!res)
90 return false
91 await methods.fetchPlans(1)
92 // 通知 planTabStore 同步
93 const newPlanId = res.data?.id
94 await usePlanTabStore.getState().onPlanCreated(
95 newPlanId,
96 newPlanId
97 ? {
98 id: newPlanId,
99 name: data.name,
100 type: PubType.VIDEO,
101 }
102 : undefined,
103 )
104 return true
105 }
106 catch {
107 return false
108 }
109 finally {
110 set({ isSubmitting: false })
111 }
112 },
113
114 /**
115 * 更新草稿箱
116 */
117 updatePlan: async (
118 id: string,
119 data: { name?: string },
120 ): Promise<boolean> => {
121 set({ isSubmitting: true })
122 try {
123 const res = await apiUpdateMaterialGroupInfo(id, data)
124 if (res?.code !== 0)
125 return false
126 const { plansPagination } = get()
127 await methods.fetchPlans(plansPagination.current)
128 // 通知 planTabStore 同步
129 usePlanTabStore.getState().onPlanUpdated(id, data)
130 return true
131 }
132 catch {
133 return false
134 }
135 finally {
136 set({ isSubmitting: false })
137 }
138 },
139
140 /**
141 * 删除草稿箱
142 */
143 deletePlan: async (id: string): Promise<boolean> => {
144 set({ isSubmitting: true })
145 try {
146 const res = await apiDeleteMaterialGroup(id)
147 if (res?.code !== 0)
148 return false
149 const { plansPagination } = get()
150 await methods.fetchPlans(plansPagination.current)
151 // 通知 planTabStore 同步
152 usePlanTabStore.getState().onPlanDeleted(id)
153 return true
154 }
155 catch {
156 return false
157 }
158 finally {
159 set({ isSubmitting: false })
160 }
161 },
162
163 // ==================== 弹窗控制 ====================
164
165 openCreatePlanModal: () => {
166 set({ createPlanModalOpen: true, editingPlan: null })
167 },
168
169 openEditPlanModal: (plan: PromotionPlan) => {
170 set({ createPlanModalOpen: true, editingPlan: plan })
171 },
172
173 closePlanModal: () => {
174 set({ createPlanModalOpen: false, editingPlan: null })
175 },
176
177 // ==================== 重置 ====================
178
179 reset: () => {
180 set(getInitialState())
181 },
182 }
183
184 return methods
185 }),
186 )
187
187 lines TYPESCRIPT