diff --git a/backend/app/services/creator.go b/backend/app/services/creator.go index 9ef6ba6..bc494f4 100644 --- a/backend/app/services/creator.go +++ b/backend/app/services/creator.go @@ -545,15 +545,38 @@ func (s *creator) GetSettings(ctx context.Context, userID int64) (*creator_dto.S if err != nil { return nil, errorx.ErrRecordNotFound } - // Extract from t.Config + cfg := t.Config.Data() return &creator_dto.Settings{ - Name: t.Name, - // Bio/Avatar from Config + Name: t.Name, + Bio: cfg.Bio, + Avatar: cfg.Avatar, + Cover: cfg.Cover, + Description: cfg.Description, }, nil } func (s *creator) UpdateSettings(ctx context.Context, userID int64, form *creator_dto.Settings) error { - return nil + tid, err := s.getTenantID(ctx, userID) + if err != nil { + return err + } + + t, err := models.TenantQuery.WithContext(ctx).Where(models.TenantQuery.ID.Eq(tid)).First() + if err != nil { + return errorx.ErrRecordNotFound + } + + cfg := t.Config.Data() + cfg.Bio = form.Bio + cfg.Avatar = form.Avatar + cfg.Cover = form.Cover + cfg.Description = form.Description + + _, err = models.TenantQuery.WithContext(ctx).Where(models.TenantQuery.ID.Eq(tid)).Updates(&models.Tenant{ + Name: form.Name, + Config: types.NewJSONType(cfg), + }) + return err } func (s *creator) ListPayoutAccounts(ctx context.Context, userID int64) ([]creator_dto.PayoutAccount, error) { diff --git a/backend/database/fields/tenants.go b/backend/database/fields/tenants.go index 8d5cde7..78b24ee 100644 --- a/backend/database/fields/tenants.go +++ b/backend/database/fields/tenants.go @@ -2,6 +2,10 @@ package fields // TenantConfig 租户配置 type TenantConfig struct { - Theme string `json:"theme,omitempty"` - Features []string `json:"features,omitempty"` + Theme string `json:"theme,omitempty"` + Features []string `json:"features,omitempty"` + Bio string `json:"bio,omitempty"` + Avatar string `json:"avatar,omitempty"` + Cover string `json:"cover,omitempty"` + Description string `json:"description,omitempty"` } diff --git a/frontend/portal/src/views/creator/SettingsView.vue b/frontend/portal/src/views/creator/SettingsView.vue index 7940b7e..3fd0759 100644 --- a/frontend/portal/src/views/creator/SettingsView.vue +++ b/frontend/portal/src/views/creator/SettingsView.vue @@ -98,19 +98,26 @@
- -
-
-
-
招商银行
-
储蓄卡 (8888)
+
+
-
+
+ + +
+ +

暂无收款账户,请添加

+
@@ -175,12 +182,15 @@ import Dialog from 'primevue/dialog'; import RadioButton from 'primevue/radiobutton'; import Toast from 'primevue/toast'; import { useToast } from 'primevue/usetoast'; -import { reactive, ref } from 'vue'; +import { reactive, ref, onMounted } from 'vue'; +import { creatorApi } from '../../api/creator'; +import { commonApi } from '../../api/common'; const toast = useToast(); const fileInput = ref(null); const currentUploadType = ref(''); const showAddAccount = ref(false); +const payoutAccounts = ref([]); const newAccount = reactive({ type: 'bank', @@ -190,43 +200,106 @@ const newAccount = reactive({ }); const form = reactive({ - name: '梅派传人小林', - bio: '专注京剧程派艺术传承与推广', + name: '', + bio: '', description: '', - avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Master1', - cover: 'https://images.unsplash.com/photo-1514306191717-452ec28c7f31?ixlib=rb-1.2.1&auto=format&fit=crop&w=1200&q=80' + avatar: '', + cover: '' }); +const fetchData = async () => { + try { + const [settings, accounts] = await Promise.all([ + creatorApi.getSettings(), + creatorApi.listPayoutAccounts() + ]); + if (settings) { + Object.assign(form, settings); + // Set defaults if empty + if (!form.avatar) form.avatar = 'https://api.dicebear.com/7.x/avataaars/svg?seed=Master1'; + } + if (accounts) payoutAccounts.value = accounts; + } catch (e) { + console.error(e); + } +}; + +onMounted(fetchData); + const triggerUpload = (type) => { currentUploadType.value = type; - fileInput.value.click(); -}; - -const handleFileChange = (event) => { - const file = event.target.files[0]; - if (file) { - const reader = new FileReader(); - reader.onload = (e) => { - if (currentUploadType.value === 'avatar') { - form.avatar = e.target.result; - } else { - form.cover = e.target.result; - } - }; - reader.readAsDataURL(file); + if (fileInput.value) { + fileInput.value.accept = 'image/*'; + fileInput.value.click(); } }; -const handleAddAccount = () => { - showAddAccount.value = false; - toast.add({ severity: 'success', summary: '添加成功', detail: '收款账户已添加', life: 3000 }); +const handleFileChange = async (event) => { + const file = event.target.files[0]; + if (!file) return; + + try { + toast.add({ severity: 'info', summary: '正在上传...', life: 2000 }); + const task = commonApi.uploadWithProgress(file, 'image'); + const res = await task.promise; + console.log('Upload response:', res); + + if (res && res.url) { + if (currentUploadType.value === 'avatar') { + form.avatar = res.url; + } else { + form.cover = res.url; + } + toast.add({ severity: 'success', summary: '上传成功', life: 2000 }); + } else { + console.error('Invalid upload response:', res); + toast.add({ severity: 'error', summary: '上传失败', detail: '服务器返回无效数据', life: 3000 }); + } + } catch (e) { + console.error(e); + toast.add({ severity: 'error', summary: '上传失败', detail: e.message, life: 3000 }); + } + event.target.value = ''; }; -const saveSettings = () => { +const handleAddAccount = async () => { + if (!newAccount.name || !newAccount.account || !newAccount.realname) { + toast.add({ severity: 'warn', summary: '提示', detail: '请填写完整信息', life: 3000 }); + return; + } + try { + await creatorApi.addPayoutAccount(newAccount); + showAddAccount.value = false; + toast.add({ severity: 'success', summary: '添加成功', detail: '收款账户已添加', life: 3000 }); + fetchData(); + // Reset + newAccount.name = ''; newAccount.account = ''; newAccount.realname = ''; + } catch (e) { + toast.add({ severity: 'error', summary: '添加失败', detail: e.message, life: 3000 }); + } +}; + +const removeAccount = async (id) => { + if (!confirm('确定要删除此账户吗?')) return; + try { + await creatorApi.removePayoutAccount(id); + toast.add({ severity: 'success', summary: '删除成功', life: 3000 }); + fetchData(); + } catch (e) { + toast.add({ severity: 'error', summary: '删除失败', detail: e.message, life: 3000 }); + } +}; + +const saveSettings = async () => { if (!form.name) { toast.add({ severity: 'error', summary: '错误', detail: '频道名称不能为空', life: 3000 }); return; } - toast.add({ severity: 'success', summary: '保存成功', detail: '部分信息正在审核中', life: 3000 }); + try { + await creatorApi.updateSettings(form); + toast.add({ severity: 'success', summary: '保存成功', detail: '设置已更新', life: 3000 }); + } catch (e) { + toast.add({ severity: 'error', summary: '保存失败', detail: e.message, life: 3000 }); + } }; \ No newline at end of file