feat: 更新内容视图和编辑视图,支持动态曲种选项和标签显示
This commit is contained in:
@@ -20,6 +20,16 @@ import (
|
||||
// @provider
|
||||
type creator struct{}
|
||||
|
||||
var genreMap = map[string]string{
|
||||
"Jingju": "京剧",
|
||||
"Kunqu": "昆曲",
|
||||
"Yueju": "越剧",
|
||||
"Yuju": "豫剧",
|
||||
"Huangmeixi": "黄梅戏",
|
||||
"Pingju": "评剧",
|
||||
"Qinqiang": "秦腔",
|
||||
}
|
||||
|
||||
func (s *creator) Apply(ctx context.Context, userID int64, form *creator_dto.ApplyForm) error {
|
||||
if userID == 0 {
|
||||
return errorx.ErrUnauthorized
|
||||
@@ -111,7 +121,12 @@ func (s *creator) ListContents(
|
||||
q = q.Where(tbl.Status.Eq(consts.ContentStatus(*filter.Status)))
|
||||
}
|
||||
if filter.Genre != nil && *filter.Genre != "" {
|
||||
q = q.Where(tbl.Genre.Eq(*filter.Genre))
|
||||
val := *filter.Genre
|
||||
if cn, ok := genreMap[val]; ok {
|
||||
q = q.Where(tbl.Genre.In(val, cn))
|
||||
} else {
|
||||
q = q.Where(tbl.Genre.Eq(val))
|
||||
}
|
||||
}
|
||||
if filter.Keyword != nil && *filter.Keyword != "" {
|
||||
q = q.Where(tbl.Title.Like("%" + *filter.Keyword + "%"))
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<div class="md:col-span-2">
|
||||
<label class="block text-sm font-bold text-slate-700 mb-2">曲种 <span
|
||||
class="text-red-500">*</span></label>
|
||||
<Select v-model="form.genre" :options="genres" placeholder="选择曲种" class="w-full h-12" />
|
||||
<Select v-model="form.genre" :options="genreOptions" optionLabel="value" optionValue="key" placeholder="选择曲种" class="w-full h-12" />
|
||||
</div>
|
||||
<div class="md:col-span-2">
|
||||
<label class="block text-sm font-bold text-slate-700 mb-2">主定调</label>
|
||||
@@ -239,6 +239,9 @@ const currentUploadType = ref('');
|
||||
const isSubmitting = ref(false);
|
||||
const isEditMode = ref(false);
|
||||
const contentId = ref('');
|
||||
const genreOptions = ref([]);
|
||||
|
||||
const autoSaveStatus = ref('已自动保存');
|
||||
|
||||
const form = reactive({
|
||||
genre: null,
|
||||
@@ -255,7 +258,19 @@ const form = reactive({
|
||||
images: [] // { name, size, url, id }
|
||||
});
|
||||
|
||||
const fetchOptions = async () => {
|
||||
try {
|
||||
const res = await commonApi.getOptions();
|
||||
if (res) {
|
||||
genreOptions.value = res.content_genre || [];
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
fetchOptions();
|
||||
if (route.params.id) {
|
||||
isEditMode.value = true;
|
||||
contentId.value = route.params.id;
|
||||
@@ -306,7 +321,6 @@ const loadContent = async (id) => {
|
||||
}
|
||||
};
|
||||
|
||||
const genres = ['京剧', '昆曲', '越剧', '黄梅戏', '豫剧', '评剧'];
|
||||
const keys = ['C大调', 'D大调', 'E大调', 'F大调', 'G大调', 'A大调', 'B大调', '降E大调'];
|
||||
|
||||
const triggerUpload = (type) => {
|
||||
|
||||
@@ -53,14 +53,13 @@
|
||||
<!-- Info -->
|
||||
<div class="flex-1 min-w-0 flex flex-col justify-between">
|
||||
<div>
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs px-1.5 py-0.5 border rounded text-slate-500" v-if="item.genre">{{
|
||||
item.genre }}</span>
|
||||
<span class="text-xs px-1.5 py-0.5 border rounded text-slate-500" v-if="item.key">{{ item.key
|
||||
}}</span>
|
||||
<h3 class="font-bold text-slate-900 text-lg truncate hover:text-primary-600 cursor-pointer transition-colors"
|
||||
@click="$router.push(`/creator/contents/${item.id}`)">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xs px-1.5 py-0.5 border rounded text-slate-500" v-if="item.genre">[{{ getGenreLabel(item.genre) }}]</span>
|
||||
<span class="text-xs px-1.5 py-0.5 border rounded text-slate-500" v-if="item.key">[{{ item.key }}]</span>
|
||||
<h3
|
||||
class="font-bold text-slate-900 text-lg truncate hover:text-primary-600 cursor-pointer transition-colors"
|
||||
@click="$router.push(`/creator/contents/${item.id}`)">
|
||||
{{ item.title }}</h3>
|
||||
</div>
|
||||
<!-- Status Badge -->
|
||||
@@ -173,6 +172,11 @@ const handleSearch = () => {
|
||||
fetchContents();
|
||||
};
|
||||
|
||||
const getGenreLabel = (key) => {
|
||||
const opt = genreOptions.value.find(o => o.key === key);
|
||||
return opt ? opt.value : key;
|
||||
};
|
||||
|
||||
const statusStyle = (status) => {
|
||||
// Map backend status to UI style. Labels should ideally come from backend option value/label map if needed,
|
||||
// but for style/color mapping we can keep it here or use a helper.
|
||||
|
||||
Reference in New Issue
Block a user