feat: release
This commit is contained in:
@@ -6,4 +6,11 @@ export const releaseTopic = async (data) => {
|
||||
method: "POST",
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchTopicCategories = async (data) => {
|
||||
return request({
|
||||
url: "/api/rating/topic/category/list",
|
||||
method: "GET",
|
||||
});
|
||||
};
|
||||
@@ -17,7 +17,7 @@
|
||||
<view class="content-wrap">
|
||||
<view class="topic-editor card-block">
|
||||
<textarea
|
||||
v-model="formData.topic"
|
||||
v-model="formData.title"
|
||||
class="topic-input"
|
||||
maxlength="40"
|
||||
placeholder="输入一个有争议的话题..."
|
||||
@@ -34,10 +34,10 @@
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="cover-card" :class="{ 'has-cover': formData.cover }" @tap="chooseCover">
|
||||
<view class="cover-card" :class="{ 'has-cover': formData.coverUrl }" @tap="chooseCover">
|
||||
<image
|
||||
v-if="formData.cover"
|
||||
:src="formData.cover"
|
||||
v-if="formData.coverUrl"
|
||||
:src="formData.coverUrl"
|
||||
class="cover-image"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
@@ -50,12 +50,12 @@
|
||||
<view class="category-group">
|
||||
<view
|
||||
v-for="category in categories"
|
||||
:key="category"
|
||||
:key="category.id"
|
||||
class="category-chip"
|
||||
:class="{ active: formData.category === category }"
|
||||
@tap="formData.category = category"
|
||||
:class="{ active: formData.categoryId === category.id }"
|
||||
@tap="formData.categoryId = category.id"
|
||||
>
|
||||
{{ category }}
|
||||
{{ category.title }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -158,20 +158,45 @@
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { getStatusBarHeight } from "@/utils/system";
|
||||
import { releaseTopic } from "@/api/release";
|
||||
import { releaseTopic, fetchTopicCategories } from "@/api/release";
|
||||
import { smartNavigateBack } from "@/utils/page";
|
||||
import {
|
||||
uploadImage,
|
||||
} from "@/utils/common.js";
|
||||
|
||||
const statusBarHeight = ref(getStatusBarHeight() || 0);
|
||||
|
||||
const categories = ["历史", "数码", "城市", "景点", "动漫", "影视"];
|
||||
const categories = ref([]);
|
||||
|
||||
const loadCategories = async () => {
|
||||
try {
|
||||
const res = await fetchTopicCategories();
|
||||
// 假设返回结构为 { data: { list: [{ id: 1, title: '历史' }, ...] } }
|
||||
// 或者直接是一个数组 [{ id: 1, title: '历史' }, ...]
|
||||
// 根据实际返回结构调整
|
||||
const list = res?.data?.list || res?.list || res || [];
|
||||
categories.value = list;
|
||||
|
||||
// 如果存在分类且未选择,则默认选中第一个
|
||||
if (categories.value.length > 0 && !formData.categoryId) {
|
||||
formData.categoryId = categories.value[0].id;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取分类失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
onLoad(() => {
|
||||
loadCategories();
|
||||
});
|
||||
|
||||
const formData = reactive({
|
||||
topic: "",
|
||||
title: "",
|
||||
description: "",
|
||||
cover: "",
|
||||
category: "历史",
|
||||
tags: ["历史", "皇帝"],
|
||||
coverUrl: "",
|
||||
categoryId: "",
|
||||
allowComment: true,
|
||||
allowPk: true,
|
||||
anonymous: false,
|
||||
@@ -186,12 +211,6 @@ const participants = ref([
|
||||
desc: "一句话简介",
|
||||
avatar: "",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "汉武帝",
|
||||
desc: "开疆拓土,大汉盛世",
|
||||
avatar: "https://api.dicebear.com/7.x/avataaars/svg?seed=hanwudi",
|
||||
},
|
||||
]);
|
||||
|
||||
const goBack = () => {
|
||||
@@ -239,6 +258,22 @@ const chooseCover = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const onAvatarSelect = async (url) => {
|
||||
if (!url) return;
|
||||
|
||||
uni.showLoading({ title: "上传中...", mask: true });
|
||||
try {
|
||||
const imageUrl = await uploadImage(url);
|
||||
|
||||
formData.coverUrl = imageUrl;
|
||||
uni.hideLoading();
|
||||
} catch (e) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: e || "上传失败", icon: "none" });
|
||||
console.error("Upload avatar error", e);
|
||||
}
|
||||
};
|
||||
|
||||
const chooseParticipantAvatar = (index) => {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
@@ -294,14 +329,18 @@ const removeParticipant = (id) => {
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!formData.topic.trim()) {
|
||||
if (!formData.title.trim()) {
|
||||
uni.showToast({ title: '请输入话题', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!formData.cover) {
|
||||
if (!formData.coverUrl) {
|
||||
uni.showToast({ title: '请上传封面图', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!formData.categoryId) {
|
||||
uni.showToast({ title: '请选择话题分类', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否有空的对象名称
|
||||
const hasEmptyName = participants.value.some(p => !p.name.trim());
|
||||
@@ -316,7 +355,7 @@ const handleSubmit = async () => {
|
||||
...formData,
|
||||
participants: participants.value,
|
||||
};
|
||||
|
||||
console.log(11111, payload)
|
||||
await releaseTopic(payload);
|
||||
|
||||
uni.hideLoading();
|
||||
|
||||
@@ -39,3 +39,73 @@ export const smartNavigateBack = (options = {}) => {
|
||||
executeBack();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 对象转 URL 参数
|
||||
* @param {Object} obj 要转换的对象
|
||||
* @returns {string} 返回 a=1&b=2 格式的字符串
|
||||
*/
|
||||
export const objToUrlParams = (obj) => {
|
||||
if (!obj || typeof obj !== 'object') return '';
|
||||
const params = [];
|
||||
for (let key in obj) {
|
||||
if (obj.hasOwnProperty(key) && obj[key] !== undefined && obj[key] !== null) {
|
||||
// 过滤掉 undefined 和 null 的参数
|
||||
params.push(`${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`);
|
||||
}
|
||||
}
|
||||
return params.join('&');
|
||||
};
|
||||
|
||||
/**
|
||||
* 封装带参数的跳转方法
|
||||
* @param {string} url 跳转的页面路径
|
||||
* @param {Object} params 要传递的参数对象
|
||||
*/
|
||||
export const navigateToWithParams = (url, params = {}) => {
|
||||
const queryStr = objToUrlParams(params);
|
||||
const finalUrl = queryStr ? `${url}${url.includes('?') ? '&' : '?'}${queryStr}` : url;
|
||||
|
||||
uni.navigateTo({
|
||||
url: finalUrl
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取当前页面的实例
|
||||
* @returns {Object|null} 当前页面实例
|
||||
*/
|
||||
export const getCurrentPage = () => {
|
||||
const pages = getCurrentPages();
|
||||
return pages.length > 0 ? pages[pages.length - 1] : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* 刷新当前页面(重新调用 onLoad 和 onShow)
|
||||
* 注意:部分复杂页面可能需要根据具体业务逻辑单独实现刷新机制
|
||||
*/
|
||||
export const refreshCurrentPage = () => {
|
||||
const currentPage = getCurrentPage();
|
||||
if (currentPage) {
|
||||
if (typeof currentPage.onLoad === 'function') {
|
||||
currentPage.onLoad(currentPage.options || {});
|
||||
}
|
||||
if (typeof currentPage.onShow === 'function') {
|
||||
currentPage.onShow();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查当前是否是指定页面
|
||||
* @param {string} route 页面路由,例如 'pages/index/index'
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export const isCurrentPage = (route) => {
|
||||
const currentPage = getCurrentPage();
|
||||
if (!currentPage) return false;
|
||||
// 去除可能的首字符 '/'
|
||||
const checkRoute = route.startsWith('/') ? route.substring(1) : route;
|
||||
return currentPage.route === checkRoute;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const BASE_URL = "https://api.ai-meng.com";
|
||||
// const BASE_URL = 'http://127.0.0.1:3999'
|
||||
// const BASE_URL = "https://api.ai-meng.com";
|
||||
const BASE_URL = 'http://127.0.0.1:3999'
|
||||
// const BASE_URL = "http://192.168.1.2:3999";
|
||||
// const BASE_URL = "http://192.168.31.253:3999";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
@@ -35,7 +35,7 @@ function hideLoading() {
|
||||
function getHeaders() {
|
||||
const userStore = useUserStore();
|
||||
const headers = {
|
||||
"x-app-id": "69665538a49b8ae3be50fe5d",
|
||||
"x-app-id": "6a0d7dbe4c5de50f2ba66475",
|
||||
"x-platform": platform,
|
||||
"x-user-id": userStore?.userInfo?.id || "",
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user