feat: 添加媒体资产文件名支持,优化上传和内容获取逻辑
This commit is contained in:
@@ -545,15 +545,38 @@ func (s *creator) GetSettings(ctx context.Context, userID int64) (*creator_dto.S
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errorx.ErrRecordNotFound
|
return nil, errorx.ErrRecordNotFound
|
||||||
}
|
}
|
||||||
// Extract from t.Config
|
cfg := t.Config.Data()
|
||||||
return &creator_dto.Settings{
|
return &creator_dto.Settings{
|
||||||
Name: t.Name,
|
Name: t.Name,
|
||||||
// Bio/Avatar from Config
|
Bio: cfg.Bio,
|
||||||
|
Avatar: cfg.Avatar,
|
||||||
|
Cover: cfg.Cover,
|
||||||
|
Description: cfg.Description,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *creator) UpdateSettings(ctx context.Context, userID int64, form *creator_dto.Settings) error {
|
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) {
|
func (s *creator) ListPayoutAccounts(ctx context.Context, userID int64) ([]creator_dto.PayoutAccount, error) {
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ package fields
|
|||||||
|
|
||||||
// TenantConfig 租户配置
|
// TenantConfig 租户配置
|
||||||
type TenantConfig struct {
|
type TenantConfig struct {
|
||||||
Theme string `json:"theme,omitempty"`
|
Theme string `json:"theme,omitempty"`
|
||||||
Features []string `json:"features,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"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,19 +98,26 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<!-- Mock Account Card -->
|
<div v-for="acc in payoutAccounts" :key="acc.id"
|
||||||
<div
|
|
||||||
class="p-4 border border-slate-200 rounded-xl flex items-center gap-4 bg-white relative group hover:border-primary-200 transition-colors">
|
class="p-4 border border-slate-200 rounded-xl flex items-center gap-4 bg-white relative group hover:border-primary-200 transition-colors">
|
||||||
<div class="w-10 h-10 rounded-full bg-red-50 text-red-600 flex items-center justify-center"><i
|
<div class="w-10 h-10 rounded-full flex items-center justify-center text-xl"
|
||||||
class="pi pi-briefcase"></i></div>
|
:class="acc.type === 'alipay' ? 'bg-blue-50 text-blue-600' : 'bg-red-50 text-red-600'">
|
||||||
<div>
|
<i class="pi" :class="acc.type === 'alipay' ? 'pi-mobile' : 'pi-briefcase'"></i>
|
||||||
<div class="font-bold text-slate-900">招商银行</div>
|
|
||||||
<div class="text-sm text-slate-500">储蓄卡 (8888)</div>
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<div>
|
||||||
|
<div class="font-bold text-slate-900">{{ acc.name }}</div>
|
||||||
|
<div class="text-sm text-slate-500">{{ acc.type === 'alipay' ? '支付宝' : '银行卡' }} ({{ acc.account.slice(-4) }})</div>
|
||||||
|
</div>
|
||||||
|
<button @click="removeAccount(acc.id)"
|
||||||
class="absolute top-4 right-4 text-slate-300 hover:text-red-500 cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity p-2"><i
|
class="absolute top-4 right-4 text-slate-300 hover:text-red-500 cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity p-2"><i
|
||||||
class="pi pi-trash"></i></button>
|
class="pi pi-trash"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Empty State -->
|
||||||
|
<div v-if="payoutAccounts.length === 0" class="col-span-full py-8 text-center text-slate-400 bg-slate-50 rounded-xl border border-dashed border-slate-200">
|
||||||
|
<i class="pi pi-wallet text-2xl mb-2"></i>
|
||||||
|
<p>暂无收款账户,请添加</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -175,12 +182,15 @@ import Dialog from 'primevue/dialog';
|
|||||||
import RadioButton from 'primevue/radiobutton';
|
import RadioButton from 'primevue/radiobutton';
|
||||||
import Toast from 'primevue/toast';
|
import Toast from 'primevue/toast';
|
||||||
import { useToast } from 'primevue/usetoast';
|
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 toast = useToast();
|
||||||
const fileInput = ref(null);
|
const fileInput = ref(null);
|
||||||
const currentUploadType = ref('');
|
const currentUploadType = ref('');
|
||||||
const showAddAccount = ref(false);
|
const showAddAccount = ref(false);
|
||||||
|
const payoutAccounts = ref([]);
|
||||||
|
|
||||||
const newAccount = reactive({
|
const newAccount = reactive({
|
||||||
type: 'bank',
|
type: 'bank',
|
||||||
@@ -190,43 +200,106 @@ const newAccount = reactive({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
name: '梅派传人小林',
|
name: '',
|
||||||
bio: '专注京剧程派艺术传承与推广',
|
bio: '',
|
||||||
description: '',
|
description: '',
|
||||||
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Master1',
|
avatar: '',
|
||||||
cover: 'https://images.unsplash.com/photo-1514306191717-452ec28c7f31?ixlib=rb-1.2.1&auto=format&fit=crop&w=1200&q=80'
|
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) => {
|
const triggerUpload = (type) => {
|
||||||
currentUploadType.value = type;
|
currentUploadType.value = type;
|
||||||
fileInput.value.click();
|
if (fileInput.value) {
|
||||||
};
|
fileInput.value.accept = 'image/*';
|
||||||
|
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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddAccount = () => {
|
const handleFileChange = async (event) => {
|
||||||
showAddAccount.value = false;
|
const file = event.target.files[0];
|
||||||
toast.add({ severity: 'success', summary: '添加成功', detail: '收款账户已添加', life: 3000 });
|
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) {
|
if (!form.name) {
|
||||||
toast.add({ severity: 'error', summary: '错误', detail: '频道名称不能为空', life: 3000 });
|
toast.add({ severity: 'error', summary: '错误', detail: '频道名称不能为空', life: 3000 });
|
||||||
return;
|
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 });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
Reference in New Issue
Block a user