feat: 新增详情页和个人主页功能及组件优化

- 添加详情页(details.html)和个人主页(homepage-me.html)的完整功能实现
- 新增多个图片资源用于UI展示
- 优化item-head、item-bottom等组件的数据绑定和交互逻辑
- 添加公共工具函数(public.js)包括时间处理和网络请求
- 完善CSS样式文件,增加响应式布局和交互效果
- 实现用户信息展示、帖子详情、相关帖子推荐等功能模块
- 添加签到、投币等交互功能
- 优化组件模板结构和数据传递方式
This commit is contained in:
DESKTOP-RQ919RC\Pc
2025-10-28 19:10:26 +08:00
parent 89703bf025
commit 7d81e02d3d
48 changed files with 4809 additions and 689 deletions

View File

@@ -5,10 +5,6 @@ const { defineComponent, ref } = Vue;
export const itemBottom = defineComponent({
name: "item-bottom",
props: {
title: {
type: String,
default: "默认标题",
},
itemdata: {
type: Object,
default: () => {},
@@ -17,8 +13,11 @@ export const itemBottom = defineComponent({
setup(props) {
let item = ref({ ...props.itemdata });
const likeClick = (item) => {
console.log("item", item);
};
return { item };
},
template: `<div class="comment flexacenter" v-if="!Array.isArray(item?.commentreviews)"> <img class="icon" :src="item?.commentreviews?.avatar" /> <div class="text one-line-display">{{ item?.commentreviews?.content }}</div></div><div class="bottom flexacenter"> <div class="bottom-item like flexacenter"> <img class="icon" src="./img/like-icon.png" /> <div class="text">{{ item.likes || "赞" }}</div> </div> <div class="bottom-item like flexacenter"> <img class="icon" src="./img/collect-golden.svg" /> <div class="text">{{ item.collections || "收藏" }}</div> </div> <div class="bottom-item like flexacenter"> <img class="icon" src="./img/discuss-icon.png" /> <div class="text">{{ item.comments || "讨论" }}</div> </div> <div class="bottom-item like flexacenter"> <img class="icon" src="./img/bi-copper-icon.png" /> <div class="text">{{ item.coins || "投币" }}</div> </div> <div class="bottom-item like flexacenter"> <img class="icon" src="./img/share-gray.png" /> <div class="text">转发</div> </div></div>`,
template: `<div class="comment flexacenter" v-if="!Array.isArray(item?.commentreviews)"> <img class="icon" :src="item?.commentreviews?.avatar" /> <div class="text one-line-display">{{ item?.commentreviews?.content }}</div></div><div class="bottom flexacenter"> <div class="bottom-item like flexacenter" @click="likeClick(item)"> <image wx:if="{{ item.is_like }}" class="icon" mode="widthFix" src="https://app.gter.net/image/miniApp/offer/like-red.png"></image> <img v-if="item.is_like" class="icon" src="./img/like-red-icon.png" /> <img v-else class="icon" src="./img/like-icon.png" /> <div class="text">{{ item.likes || "赞" }}</div> </div> <div class="bottom-item like flexacenter"> <img class="icon" src="./img/collect-golden.svg" /> <div class="text">{{ item.collections || "收藏" }}</div> </div> <div class="bottom-item flexacenter"> <img class="icon" src="./img/discuss-icon.png" /> <div class="text">{{ item.comments || "讨论" }}</div> </div> <div class="bottom-item flexacenter"> <img class="icon" src="./img/bi-copper-icon.png" /> <div class="text">{{ item.coins || "投币" }}</div> </div> <div class="bottom-item flexacenter"> <img class="icon" src="./img/share-gray.png" /> <div class="text">转发</div> </div></div>`,
});

View File

@@ -3,25 +3,29 @@
<div class="text one-line-display">{{ item?.commentreviews?.content }}</div>
</div>
<div class="bottom flexacenter">
<div class="bottom-item like flexacenter">
<img class="icon" src="./img/like-icon.png" />
<div class="bottom-item like flexacenter" @click="likeClick(item)">
<image wx:if="{{ item.is_like }}" class="icon" mode="widthFix" src="https://app.gter.net/image/miniApp/offer/like-red.png"></image>
<img v-if="item.is_like" class="icon" src="./img/like-red-icon.png" />
<img v-else class="icon" src="./img/like-icon.png" />
<div class="text">{{ item.likes || "赞" }}</div>
</div>
<div class="bottom-item like flexacenter">
<img class="icon" src="./img/collect-golden.svg" />
<div class="text">{{ item.collections || "收藏" }}</div>
</div>
<div class="bottom-item like flexacenter">
<div class="bottom-item flexacenter">
<img class="icon" src="./img/discuss-icon.png" />
<div class="text">{{ item.comments || "讨论" }}</div>
</div>
<div class="bottom-item like flexacenter">
<div class="bottom-item flexacenter">
<img class="icon" src="./img/bi-copper-icon.png" />
<div class="text">{{ item.coins || "投币" }}</div>
</div>
<div class="bottom-item like flexacenter">
<div class="bottom-item flexacenter">
<img class="icon" src="./img/share-gray.png" />
<div class="text">转发</div>
</div>

View File

@@ -1,6 +1,6 @@
// my-component.js
// 引入全局 Vue 对象(因在 HTML 中通过 script 引入Vue 已挂载到 window
const { defineComponent } = Vue;
const { defineComponent, ref } = Vue;
import { itemBottom } from "../item-bottom/item-bottom.js";
import { itemHead } from "../item-head/item-head.js";
@@ -8,16 +8,20 @@ import { itemHead } from "../item-head/item-head.js";
export const itemForum = defineComponent({
name: "item-forum",
props: {
title: {
type: String,
default: "默认标题",
itemdata: {
type: Object,
default: () => {},
},
},
// 方法
methods: {
handleClick() {
alert("组件按钮被点击");
},
setup(props) {
let res = props.itemdata;
res.content = res?.content?.replace(/\[.*?\]/g, "");
res.content = res?.content?.replace(/\<.*?\>/g, "");
res.content = res?.content?.replace(/\[.*?\../g, "");
let item = ref({ ...res });
return { item };
},
components: {
@@ -25,5 +29,5 @@ export const itemForum = defineComponent({
itemHead,
},
template: `<div class="item-box item-forum"> <item-head></item-head> <div class="label flexflex"> <img class="item icon" src="./img/recommend-icon.png" /> <img class="item icon" src="./img/essence-icon.png" /> <div class="item blue">香港</div> <div class="item">香港</div> </div> <div class="title">【干货】香港留学费用准备</div> <div class="message">在即将赴港的时候很多同学好奇香港一年制硕士下来的整体费用大概是多少其实主要包括学费租房费和生活费三部分。学费的话根据不同香港来定大概在10-30万港币之间比较固定…</div> <item-bottom></item-bottom></div>`,
template: `<div class="item-box item-forum"> <item-head :itemdata="item"></item-head> <div v-if="item.title" class="title">{{ item.title }}</div> <div class="message two-line-display">{{ item.content }}</div> <item-bottom :itemdata="item"></item-bottom></div>`,
});

View File

@@ -1,15 +1,9 @@
<div class="item-box item-forum">
<item-head></item-head>
<div class="label flexflex">
<img class="item icon" src="./img/recommend-icon.png" />
<img class="item icon" src="./img/essence-icon.png" />
<div class="item blue">香港</div>
<div class="item">香港</div>
</div>
<item-head :itemdata="item"></item-head>
<div class="title">【干货】香港留学费用准备</div>
<div v-if="item.title" class="title">{{ item.title }}</div>
<div class="message">在即将赴港的时候很多同学好奇香港一年制硕士下来的整体费用大概是多少其实主要包括学费租房费和生活费三部分。学费的话根据不同香港来定大概在10-30万港币之间比较固定…</div>
<div class="message two-line-display">{{ item.content }}</div>
<item-bottom></item-bottom>
<item-bottom :itemdata="item"></item-bottom>
</div>

View File

@@ -1,22 +1,32 @@
// my-component.js
// 引入全局 Vue 对象(因在 HTML 中通过 script 引入Vue 已挂载到 window
const { defineComponent } = Vue;
const { defineComponent, ref } = Vue;
// 定义组件(直接使用模板)
export const itemHead = defineComponent({
name: "item-head",
props: {
title: {
type: String,
default: "默认标题",
},
},
// 方法
methods: {
handleClick() {
alert("组件按钮被点击");
itemdata: {
type: Object,
default: () => {},
},
},
template: `<div class="item-head flexacenter"> <img class="avatar" src="https://nas.gter.net:9008/avatar/97K4EWIMLrsbGTWXslC1UltTF6WOikN42jDKLNjtax7Hc44zLpaKSdU9oWFhY2E~/small" /> <div class="name">小P学姐</div> <img class="group" src="https://o.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c_ZMtdXfqqsgFptxhcq_cQnrlcPJ0DVESBq_D-81qNDQyOQ~~" /> <div class="time">2025-8-11 01:30</div> <div class="flex1"></div> <div class="view flexacenter"> <img class="icon" src="https://app.gter.net/image/miniApp/offer/eye-icon.svg" /> <div class="text">3016</div> </div> <div class="btn flexcenter" @click="cutShow"> <img class="icon" src="https://app.gter.net/image/miniApp/offer/dot-dot-dot-gray.png" /> </div> <!-- <template v-if="show"> <div class="mask" catch:tap="cutShow" catch:touchmove="touchmove"></div> <div class="operate" catch:tap="true"> <div class="item" bind:tap="report">举报</div> <template v-if="ismanager"> <div class="item" bind:tap="hide">{{ item.hidden == 0 ? '隐藏' : '显示' }}</div> <div class="item" bind:tap="recommend">{{ item.recommend == 1 ? '取消' : '' }}推荐</div> <div class="item" bind:tap="essence">{{ item.best == 1 ? '取消' : '' }}精华</div> </template> </div> </template> --></div> `,
setup(props) {
let sectionn = ref([]);
let tags = ref([]);
let item = ref({ ...props.itemdata });
let timestamp = ref(strtimeago(item.value.release_at, 4));
if (item.value.type == "tenement") timestamp = timeago(item.value.updatetime, 2);
sectionn.value = item.value.sectionn || [];
const sectionSet = new Set(sectionn.value);
tags.value = item.value.tags.filter((tag) => !sectionSet.has(tag));
return { item, timestamp, sectionn, tags };
},
template: `<div class="item-head flexacenter"> <img class="avatar" :src="item.user.avatar || item.avatar" /> <div class="name">{{ item.user.nickname || item.nickname || '匿名用户' }}</div> <!-- <img class="group" src="https://o.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c_ZMtdXfqqsgFptxhcq_cQnrlcPJ0DVESBq_D-81qNDQyOQ~~" /> --> <div class="time">{{ timestamp }}</div> <div class="flex1"></div> <div class="view flexacenter"> <img class="icon" src="https://app.gter.net/image/miniApp/offer/eye-icon.svg" /> <div class="text">{{ item.views }}</div> </div> <div class="btn flexcenter"> <img class="icon" src="https://app.gter.net/image/miniApp/offer/dot-dot-dot-gray.png" /> </div> <!-- <template v-if="show"> <div class="mask" catch:tap="cutShow" catch:touchmove="touchmove"></div> <div class="operate" catch:tap="true"> <div class="item" bind:tap="report">举报</div> <template v-if="ismanager"> <div class="item" bind:tap="hide">{{ item.hidden == 0 ? '隐藏' : '显示' }}</div> <div class="item" bind:tap="recommend">{{ item.recommend == 1 ? '取消' : '' }}推荐</div> <div class="item" bind:tap="essence">{{ item.best == 1 ? '取消' : '' }}精华</div> </template> </div> </template> --></div><div class="label flexflex" v-if="sectionn.length || tags.length"> <img class="item icon" src="./img/recommend-icon.png" /> <img class="item icon" src="./img/essence-icon.png" /> <div class="item blue" v-for="(item, index) in sectionn" :key="item">{{ item }}</div> <div class="item" v-for="(item, index) in tags" :key="item">{{ item }}</div></div>`,
});

View File

@@ -1,16 +1,16 @@
<div class="item-head flexacenter">
<img class="avatar" src="https://nas.gter.net:9008/avatar/97K4EWIMLrsbGTWXslC1UltTF6WOikN42jDKLNjtax7Hc44zLpaKSdU9oWFhY2E~/small" />
<div class="name">小P学姐</div>
<img class="group" src="https://o.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c_ZMtdXfqqsgFptxhcq_cQnrlcPJ0DVESBq_D-81qNDQyOQ~~" />
<div class="time">2025-8-11 01:30</div>
<img class="avatar" :src="item.user.avatar || item.avatar" />
<div class="name">{{ item.user.nickname || item.nickname || '匿名用户' }}</div>
<!-- <img class="group" src="https://o.x-php.com/Zvt57TuJSUvkyhw-xG7Y2l-c_ZMtdXfqqsgFptxhcq_cQnrlcPJ0DVESBq_D-81qNDQyOQ~~" /> -->
<div class="time">{{ timestamp }}</div>
<div class="flex1"></div>
<div class="view flexacenter">
<img class="icon" src="https://app.gter.net/image/miniApp/offer/eye-icon.svg" />
<div class="text">3016</div>
<div class="text">{{ item.views }}</div>
</div>
<div class="btn flexcenter" @click="cutShow">
<div class="btn flexcenter">
<img class="icon" src="https://app.gter.net/image/miniApp/offer/dot-dot-dot-gray.png" />
</div>
@@ -25,4 +25,11 @@
</template>
</div>
</template> -->
</div>
</div>
<div class="label flexflex" v-if="sectionn.length || tags.length">
<img class="item icon" src="./img/recommend-icon.png" />
<img class="item icon" src="./img/essence-icon.png" />
<div class="item blue" v-for="(item, index) in sectionn" :key="item">{{ item }}</div>
<div class="item" v-for="(item, index) in tags" :key="item">{{ item }}</div>
</div>

View File

@@ -8,21 +8,11 @@ import { itemHead } from "../item-head/item-head.js";
export const itemOffer = defineComponent({
name: "item-offer",
props: {
title: {
type: String,
default: "默认标题",
},
item: {
type: Object,
default: () => {},
},
},
// 方法
methods: {
handleClick() {
alert("组件按钮被点击");
},
},
components: {
itemBottom,

View File

@@ -8,21 +8,11 @@ import { itemHead } from "../item-head/item-head.js";
export const itemSummary = defineComponent({
name: "item-summary",
props: {
title: {
type: String,
default: "默认标题",
},
item: {
type: Object,
default: () => {},
},
},
// 方法
methods: {
handleClick() {
alert("组件按钮被点击");
},
},
components: {
itemBottom,

View File

@@ -34,5 +34,5 @@ export const itemTenement = defineComponent({
itemHead,
},
template: `<div class="item-box item-vote"> <item-head :itemdata="item"></item-head> <div class="title">{{ item.title }}</div> <div class="message one-line-display" v-if="item.content">{{ item.content }}</div> <div class="info flexacenter"> <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>人参与 </div> <div class="list" :class="{ 'voted': !item.time || item.isvote }"> <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> </div> <item-bottom :itemdata="item"></item-bottom></div>`,
template: `<div class="item-box item-tenement"> <item-head :itemdata="item"></item-head> <div class="title">三房找一位室友合租,家具设备齐全</div> <div class="site-box flexacenter"> <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="https://app.gter.net/image/miniApp/offer/room.png"> {{ item }} </div> </template> <div v-else class="site-item flexacenter"> <img class="site-icon" src="https://app.gter.net/image/miniApp/offer/orientation.png"> {{ item.location || '九龙 > 尖沙咀/佐敦' }} </div> </div> <div class="price-section flexacenter"> <div class="unit">HK$</div> <div class="price">{{ item.rent }}</div> <span class="text">/月</span> <div class="rentalduration">[ 租期{{ item.rentalduration }} ]</div> </div> <div class="picture flexacenter"> <img class="picture-item" v-for="(item, index) in 15" :key="index" src="https://axure-file.lanhuapp.com/md5__34fc6e5f5fef1d31bbd4604d33be77cc.svg" alt=""> </div> <item-bottom :itemdata="item"></item-bottom></div>`,
});

View File

@@ -1,5 +1,30 @@
<div class="item-box item-tenement">
<item-head :itemdata="item"></item-head>
<!-- <div class="title">{{ item.title }}</div> -->
<div class="title">三房找一位室友合租,家具设备齐全</div>
<div class="site-box flexacenter">
<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="https://app.gter.net/image/miniApp/offer/room.png">
{{ item }}
</div>
</template>
<div v-else class="site-item flexacenter">
<img class="site-icon" src="https://app.gter.net/image/miniApp/offer/orientation.png">
{{ item.location || '九龙 > 尖沙咀/佐敦' }}
</div>
</div>
<div class="price-section flexacenter">
<div class="unit">HK$</div>
<div class="price">{{ item.rent }}</div>
<span class="text">/月</span>
<div class="rentalduration">[ 租期{{ item.rentalduration }} ]</div>
</div>
<div class="picture flexacenter">
<img class="picture-item" v-for="(item, index) in 15" :key="index" src="https://axure-file.lanhuapp.com/md5__34fc6e5f5fef1d31bbd4604d33be77cc.svg" alt="">
</div>
<item-bottom :itemdata="item"></item-bottom>
</div>