feat: 添加租房模块图标和功能优化

fix: 修复投票状态显示逻辑
refactor: 重命名ajaxget为ajaxGet
style: 优化CSS样式和布局
docs: 更新组件文档和注释
This commit is contained in:
DESKTOP-RQ919RC\Pc
2025-11-04 19:05:40 +08:00
parent a7d803f633
commit 07f4401f67
28 changed files with 735 additions and 241 deletions

View File

@@ -5,17 +5,35 @@ const { defineComponent, ref, onMounted, nextTick } = Vue;
// 定义组件(直接使用模板)
export const headTop = defineComponent({
name: "headTop",
props: {
itemdata: {
type: Object,
default: () => {},
},
},
props: {},
setup(props) {
onMounted(() => {});
let signInAlreadyState = ref(false);
let state = ref(0); // 是否已经签到
let userInfoWinTimerCount = 0;
const userInfoWinTimer = setInterval(() => {
if (todaysignedState) {
state.value = todaysigned;
clearInterval(userInfoWinTimer);
}
userInfoWinTimerCount++;
if (userInfoWinTimerCount >= 3000) clearInterval(userInfoWinTimer);
}, 50);
const signIn = () => {
ajax("/v2/api/forum/sign").then((res) => {
if (res.code != 200) {
creationAlertBox("error", res.message);
return;
}
let data = res.data;
state.value = 1;
creationAlertBox("success", res.message || "签到成功");
});
};
let input = ref("");
let defaultSearchText = ref("屯特");
@@ -23,8 +41,9 @@ export const headTop = defineComponent({
const searchText = input.value || defaultSearchText.value;
redirectToExternalWebsite("/search/" + searchText);
};
return { input, defaultSearchText, goSearch, signInAlreadyState };
return { state, signIn, input, defaultSearchText, goSearch };
},
template: `<div class="head-top flexacenter"> <a href="/" class="flexacenter" target="_blank"> <img class="logo" src="https://oss.gter.net/logo" alt="" /> </a> <div class="flex1"></div> <div class="input-box flexacenter"> <input class="input flex1" type="text" :placeholder="'大家都在搜:' + defaultSearchText" @keyup.enter="goSearch" v-model="input" /> <img class="icon" src="/img/search-icon.svg" @click="goSearch" /> </div> <div class="sign-in sign-in-already flexcenter" v-if="signInAlreadyState" v-cloak onclick="showWindow('dsu_paulsign', 'https://bbs.gter.net/plugin.php?id=dsu_paulsign:sign&show=sign')"> <img class="sign-icon" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/sign-icon.png" /> <span>已签到,明天再来</span> </div> <div class="sign-in sign-in-no flexacenter" v-else onclick="showWindow('dsu_paulsign', 'https://bbs.gter.net/plugin.php?id=dsu_paulsign:sign&show=sign')" v-cloak> <img class="sign-in-bj" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/sign-in-bj.svg" /> <img class="coin-bj" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/coin-bj.svg" /> <img class="coin-icon" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/coin-icon.png" /> <span class="text flex1">签到领寄托币</span> <div class="sign-go flexcenter"> <img class="sign-go-bj" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/sign-go.svg" /> GO </div> <img class="petal1" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/petal1.png" /> <img class="petal2" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/petal2.png" /> <img class="petal3" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/petal3.png" /> </div></div>`,
template: `<div class="head-top flexacenter"> <a href="/" class="flexacenter" target="_blank"> <img class="logo" src="https://oss.gter.net/logo" alt="" /> </a> <div class="flex1"></div> <div class="input-box flexacenter"> <input class="input flex1" type="text" :placeholder="'大家都在搜:' + defaultSearchText" @keyup.enter="goSearch" v-model="input" /> <img class="icon" src="/img/search-icon.svg" @click="goSearch" /> </div> <div class="sign-in sign-in-no flexacenter" v-if="state == 0" @click="signIn()" v-cloak> <img class="sign-in-bj" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/sign-in-bj.svg" /> <img class="coin-bj" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/coin-bj.svg" /> <img class="coin-icon" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/coin-icon.png" /> <span class="text flex1">签到领寄托币</span> <div class="sign-go flexcenter"> <img class="sign-go-bj" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/sign-go.svg" /> GO </div> <img class="petal1" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/petal1.png" /> <img class="petal2" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/petal2.png" /> <img class="petal3" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/petal3.png" /> </div> <div class="sign-in sign-in-already flexcenter" v-else> <img class="sign-icon" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/sign-icon.png" /> <span>已签到,明天再来</span> </div></div>`,
});

View File

@@ -8,11 +8,7 @@
<img class="icon" src="/img/search-icon.svg" @click="goSearch" />
</div>
<div class="sign-in sign-in-already flexcenter" v-if="signInAlreadyState" v-cloak onclick="showWindow('dsu_paulsign', 'https://bbs.gter.net/plugin.php?id=dsu_paulsign:sign&show=sign')">
<img class="sign-icon" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/sign-icon.png" />
<span>已签到,明天再来</span>
</div>
<div class="sign-in sign-in-no flexacenter" v-else onclick="showWindow('dsu_paulsign', 'https://bbs.gter.net/plugin.php?id=dsu_paulsign:sign&show=sign')" v-cloak>
<div class="sign-in sign-in-no flexacenter" v-if="state == 0" @click="signIn()" v-cloak>
<img class="sign-in-bj" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/sign-in-bj.svg" />
<img class="coin-bj" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/coin-bj.svg" />
<img class="coin-icon" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/coin-icon.png" />
@@ -25,4 +21,8 @@
<img class="petal2" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/petal2.png" />
<img class="petal3" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/petal3.png" />
</div>
<div class="sign-in sign-in-already flexcenter" v-else>
<img class="sign-icon" src="//framework.x-php.com/gter/image/gter/forum/assets/forum/sign-icon.png" />
<span>已签到,明天再来</span>
</div>
</div>

View File

@@ -28,7 +28,7 @@ export const itemHead = defineComponent({
sectionn.value = item.value.sectionn || [];
const sectionNameSet = new Set(sectionn.value.map((item) => item.name));
tags.value = item.value.tags.filter((tagName) => !sectionNameSet.has(tagName));
tags.value = item.value?.tags?.filter((tagName) => !sectionNameSet.has(tagName)) || [];
// const sectionSet = new Set(sectionn.value);
// tags.value = item.value.tags?.filter((tag) => !sectionSet.has(tag));
@@ -49,8 +49,7 @@ export const itemHead = defineComponent({
onMounted(() => {
setTimeout(() => {
permissions.value = window["permissions"] || [];
// ismanager.value = permissions.value.indexOf("topic:manager") >= 0;
ismanager.value = true;
ismanager.value = permissions.value.indexOf("topic:manager") >= 0;
}, 1000);
});
@@ -124,5 +123,5 @@ export const itemHead = defineComponent({
report,
},
template: `<div class="item-head flexacenter"> <div class="user-box flexacenter" @click="goPersonalHomepage(item?.user?.uin, item?.user?.uid)"> <img class="avatar" :src="item?.user?.avatar || item.avatar" /> <div class="name">{{ item?.user?.nickname || item.nickname || "匿名用户" }}</div> <img class="group" v-if="info?.group?.image" :src="info?.group?.image" /> </div> <div class="time">{{ timestamp }}</div> <div class="flex1"></div> <div class="view flexacenter"> <img class="icon" src="/img/eye-icon.svg" /> <div class="text">{{ item.views }}</div> </div> <div class="btn flexcenter" @click.stop="cutShow"> <img class="icon" src="/img/dot-dot-dot-gray.png" /> </div> <div v-if="show"> <div class="mask" @click.stop="cutShow"></div> <div class="operate"> <div class="item" @click.stop="report">举报</div> <template v-if="ismanager"> <div class="item" @click.stop="hide">{{ item.hidden == 0 ? "隐藏" : "显示" }}</div> <div class="item" @click.stop="recommend">{{ item.recommend == 1 ? "取消" : "" }}推荐</div> <div class="item" @click.stop="essence">{{ item.best == 1 ? "取消" : "" }}精华</div> </template> <template v-if="item.type == 'thread' && item.ismyself"> <div class="item" @click.stop="edit">编辑</div> <div class="item" @click.stop="deleteItem">删除</div> </template> </div> </div></div><div class="label flexflex" v-if="sectionn?.length || tags?.length || item.recommend == 1 || item.best == 1"> <img class="item icon" v-if="item.recommend == 1 && item.best != 1" src="/img/recommend-icon.png" /> <img class="item icon" v-if="item.best == 1" src="/img/essence-icon.png" /> <a class="item blue" v-for="(item, index) in sectionn" :key="item" :href="'/section/' + item.uniqid" target="_blank">{{ item.name }}</a> <a class="item" v-for="(item, index) in tags" :key="item" :href="'/tag/' + item" target="_blank">{{ item }}</a></div><report v-if="reportState" :itemdata="item"></report>`,
template: `<div class="item-head flexacenter"> <div class="user-box flexacenter" @click="goPersonalHomepage(item?.user?.uin, item?.user?.uid)"> <img class="avatar" :src="item?.user?.avatar || item.avatar" /> <div class="name">{{ item?.user?.nickname || item.nickname || "匿名用户" }}</div> <img class="group" v-if="info?.group?.image" :src="info?.group?.image" /> </div> <div class="time">{{ timestamp }}</div> <div class="flex1"></div> <div class="view flexacenter"> <img class="icon" src="/img/eye-icon.svg" /> <div class="text">{{ item.views }}</div> </div> <div v-if="item.type != 'tenement'" class="btn flexcenter" @click.stop="cutShow"> <img class="icon" src="/img/dot-dot-dot-gray.png" /> </div> <div v-if="show"> <div class="mask" @click.stop="cutShow"></div> <div class="operate"> <div class="item" @click.stop="report">举报</div> <template v-if="ismanager"> <div class="item" @click.stop="hide">{{ item.hidden == 0 ? "隐藏" : "显示" }}</div> <div class="item" @click.stop="recommend">{{ item.recommend == 1 ? "取消" : "" }}推荐</div> <div class="item" @click.stop="essence">{{ item.best == 1 ? "取消" : "" }}精华</div> </template> <template v-if="item.type == 'thread' && item.ismyself"> <div class="item" @click.stop="edit">编辑</div> <div class="item" @click.stop="deleteItem">删除</div> </template> </div> </div></div><div class="label flexflex" v-if="sectionn?.length || tags?.length || item.recommend == 1 || item.best == 1"> <img class="item icon" v-if="item.recommend == 1 && item.best != 1" src="/img/recommend-icon.png" /> <img class="item icon" v-if="item.best == 1" src="/img/essence-icon.png" /> <a class="item blue" v-for="(item, index) in sectionn" :key="item" :href="'/section/' + item.uniqid" target="_blank">{{ item.name }}</a> <a class="item" v-for="(item, index) in tags" :key="item" :href="'/tag/' + item" target="_blank">{{ item }}</a></div><report v-if="reportState" :itemdata="item"></report>`,
});

View File

@@ -13,7 +13,7 @@
<div class="text">{{ item.views }}</div>
</div>
<div class="btn flexcenter" @click.stop="cutShow">
<div v-if="item.type != 'tenement'" class="btn flexcenter" @click.stop="cutShow">
<img class="icon" src="/img/dot-dot-dot-gray.png" />
</div>

View File

@@ -61,11 +61,22 @@ export const itemTenement = defineComponent({
let item = ref({ ...props.itemdata });
// console.log("item", item.value);
item.value = handleHousing(item.value);
item.value['url'] = '/details/' + item.value.uniqid;
item.value["url"] = "https://fang.gter.net/detail?id=" + item.value.uniqid;
let sectionn = ref([]);
let tags = ref([]);
if (item.value.type == "tenement") {
const tabList = item.value?.tabList || [];
sectionn.value = ["香港租房", tabList[0]];
tags.value = tabList.slice(1) || [];
}
if (item.value.images?.length > 4) item.value.images = item.value.images.slice(0, 4);
console.log("item.value", item.value);
return { item };
return { sectionn, tags, item };
},
components: {
@@ -73,5 +84,5 @@ export const itemTenement = defineComponent({
itemHead,
},
template: `<div class="item-box item-tenement"> <item-head :itemdata="item"></item-head> <a class="title" :href="item.url" target="_blank">{{ item.title }}</a> <a class="site-box flexacenter" :href="item.url" target="_blank"> <template v-if="item.intermediary == 6"> <div class="site-item flexacenter" v-for="(item, index) in item.location" :key="index"> <img class="site-icon" src="/img/orientation.png"> {{ item }} </div> </template> <div v-else class="site-item flexacenter"> <img class="site-icon" src="/img/orientation.png"> {{ item.location || '' }} </div> </a> <a class="price-section flexacenter" :href="item.url" target="_blank"> <div class="unit">HK$</div> <div class="price">{{ item.rent }}</div> <span class="text">/月</span> <div class="rentalduration">[ 租期{{ item.rentalduration }} ]</div> </a> <a class="picture flexacenter" :href="item.url" target="_blank" v-if="item.images?.length != 0"> <img class="picture-item" v-for="(item, index) in item.images" :key="index" :src="item" alt=""> </a> <item-bottom :itemdata="item"></item-bottom></div>`,
template: `<div class="item-box item-tenement"> <item-head :itemdata="item"></item-head> <div class="label flexflex" v-if="sectionn?.length || tags?.length"> <img class="item icon" v-if="item.isintermediary == 1" style="width: 94px; cursor: auto;" src="/img/intermediary-icon.png" /> <img class="item icon" v-if="item.verified == 1" style="width: 94px; cursor: auto;" src="/img/attestation-icon.png" /> <div class="item blue" v-for="(item, index) in sectionn" :key="item" style="cursor: auto;">{{ item }}</div> <div class="item" v-for="(item, index) in tags" :key="item" style="cursor: auto;">{{ item }}</div> </div> <a class="title" :href="item.url" target="_blank">{{ item.subject }}</a> <a class="site-box flexacenter" :href="item.url" target="_blank"> <template v-if="item.intermediary == 6"> <div class="site-item flexacenter" v-for="(item, index) in item.location" :key="index"> <img class="site-icon" src="/img/orientation.png"> {{ item }} </div> </template> <div v-else class="site-item flexacenter"> <img class="site-icon" src="/img/orientation.png"> {{ item.location || '' }} </div> </a> <a class="price-section flexacenter" :href="item.url" target="_blank"> <div class="unit">HK$</div> <div class="price">{{ item.rent }}</div> <span class="text">/月</span> <div class="rentalduration">[ 租期{{ item.rentalduration }} ]</div> </a> <a class="picture flexacenter" :href="item.url" target="_blank" v-if="item.images?.length != 0"> <img class="picture-item" v-for="(item, index) in item.images" :key="index" :src="item" alt=""> </a> <item-bottom :itemdata="item"></item-bottom></div>`,
});

View File

@@ -1,6 +1,13 @@
<div class="item-box item-tenement">
<item-head :itemdata="item"></item-head>
<a class="title" :href="item.url" target="_blank">{{ item.title }}</a>
<div class="label flexflex" v-if="sectionn?.length || tags?.length">
<img class="item icon" v-if="item.isintermediary == 1" style="width: 94px; cursor: auto;" src="/img/intermediary-icon.png" />
<img class="item icon" v-if="item.verified == 1" style="width: 94px; cursor: auto;" src="/img/attestation-icon.png" />
<div class="item blue" v-for="(item, index) in sectionn" :key="item" style="cursor: auto;">{{ item }}</div>
<div class="item" v-for="(item, index) in tags" :key="item" style="cursor: auto;">{{ item }}</div>
</div>
<a class="title" :href="item.url" target="_blank">{{ item.subject }}</a>
<a class="site-box flexacenter" :href="item.url" target="_blank">
<template v-if="item.intermediary == 6">

View File

@@ -25,5 +25,5 @@ export const itemVote = defineComponent({
itemHead,
},
template: `<div class="item-box item-vote"> <item-head :itemdata="item"></item-head> <a class="title" :href="item.url" target="_blank">{{ item.title }}</a> <a class="message one-line-display" v-if="item.content">{{ item.content }}</a> <a class="info flexacenter" target="_blank" :href="item.url"> <template v-if="item.time"> <div class="status">进行中</div> <div class="line"></div> <div class="num">{{ item?.time.num }}</div>{{ item.time.unit }}后结束 </template> <div v-else class="status end">已结束</div> <div class="line"></div> <div class="num">{{ item?.data?.votes }}</div>人参与 </a> <a class="list" :class="{ 'voted': !item.time || item.isvote }" target="_blank" :href="item.url"> <div class="list-item flexcenter " v-for="(item, index) in item?.data?.option" :key="index"> <div class="list-top flexacenter"> <img v-if="item.selected" class="list-tick" src="/img/vote-tick.svg"> <div v-else class="list-serial flexcenter">{{ index + 1 }}</div> <div class="list-text one-line-display flex1">{{ item.value }}</div> </div> <div class="list-bottom flexacenter"> <div class="list-length" :style="{ width: item.percentage + '%' }"></div>{{ item.count }} </div> </div> </a> <item-bottom :itemdata="item"></item-bottom></div>`,
template: `<div class="item-box item-vote"> <item-head :itemdata="item"></item-head> <a class="title" :href="item.url" target="_blank">{{ item.title }}</a> <a class="message one-line-display" v-if="item.content">{{ item.content }}</a> <a class="info flexacenter" target="_blank" :href="item.url"> <template v-if="item?.data.status == 1"> <div class="status">进行中</div> <div class="line"></div> <div class="num">{{ item?.time.num }}</div>{{ item.time.unit }}后结束 </template> <div v-else class="status end">已结束</div> <div class="line"></div> <div class="num">{{ item?.data?.votes }}</div>人参与 </a> <a class="list" :class="{ 'voted': !item.time || item.isvote }" target="_blank" :href="item.url"> <div class="list-item flexcenter " v-for="(item, index) in item?.data?.option" :key="index"> <div class="list-top flexacenter"> <img v-if="item.selected" class="list-tick" src="/img/vote-tick.svg"> <div v-else class="list-serial flexcenter">{{ index + 1 }}</div> <div class="list-text one-line-display flex1">{{ item.value }}</div> </div> <div class="list-bottom flexacenter"> <div class="list-length" :style="{ width: item.percentage + '%' }"></div>{{ item.count }} </div> </div> </a> <item-bottom :itemdata="item"></item-bottom></div>`,
});

View File

@@ -3,7 +3,7 @@
<a class="title" :href="item.url" target="_blank">{{ item.title }}</a>
<a class="message one-line-display" v-if="item.content">{{ item.content }}</a>
<a class="info flexacenter" target="_blank" :href="item.url">
<template v-if="item.time">
<template v-if="item?.data.status == 1">
<div class="status">进行中</div>
<div class="line"></div>
<div class="num">{{ item?.time.num }}</div>{{ item.time.unit }}后结束

View File

@@ -23,15 +23,10 @@ export const latestList = defineComponent({
let postsTab = ref("newest"); // newest essence
let boxtype = ref(props.boxtype);
console.log(boxtype.value);
onMounted(() => {
if (props.boxtype == "newest") {
// boxtype.value = "newest";
getTopicLatest();
} else if (props.boxtype == "essence") {
// boxtype.value = "essence";
topicHandpicked();
} else {
if (props.boxtype == "newest") getTopicLatest();
else if (props.boxtype == "essence") topicHandpicked();
else {
getTopicLatest();
topicHandpicked();
}