feat: update API base URLs and improve UI elements
- Changed API base URLs in app.js to point to the production server for deployment. - Updated the my page UI by refining labels and removing unnecessary text for a cleaner look. - Adjusted CSS styles to enhance layout and reduce whitespace, improving overall user experience. This update aims to ensure proper API connectivity and enhance the visual presentation of the user interface.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
"pages/index/index",
|
||||
"pages/chapters/chapters",
|
||||
"pages/match/match",
|
||||
"pages/super-moments/super-moments",
|
||||
"pages/my/my",
|
||||
"pages/read/read",
|
||||
"pages/link-preview/link-preview",
|
||||
@@ -64,6 +65,10 @@
|
||||
"pagePath": "pages/match/match",
|
||||
"text": "找伙伴"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/super-moments/super-moments",
|
||||
"text": "动态"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/my/my",
|
||||
"text": "我的"
|
||||
|
||||
@@ -1,157 +1,181 @@
|
||||
/**
|
||||
* Soul创业实验 - 自定义TabBar组件
|
||||
* 根据后台配置动态显示/隐藏"找伙伴"按钮
|
||||
* Soul创业实验 - 自定义 TabBar
|
||||
* 支持:首页 / 目录 / [找伙伴] / [动态,审核模式隐藏] / 我的
|
||||
*/
|
||||
|
||||
console.log('[TabBar] ===== 组件文件开始加载 =====')
|
||||
|
||||
const app = getApp()
|
||||
console.log('[TabBar] App 对象:', app)
|
||||
|
||||
Component({
|
||||
data: {
|
||||
selected: 0,
|
||||
color: '#8e8e93',
|
||||
selectedColor: '#00CED1',
|
||||
matchEnabled: false, // 找伙伴功能开关,默认关闭
|
||||
list: [
|
||||
matchEnabled: false,
|
||||
tabList: [
|
||||
{
|
||||
pagePath: '/pages/index/index',
|
||||
text: '首页',
|
||||
iconType: 'home'
|
||||
iconPath: '/assets/icons/home.svg',
|
||||
isSpecial: false,
|
||||
},
|
||||
{
|
||||
pagePath: '/pages/chapters/chapters',
|
||||
text: '目录',
|
||||
iconType: 'list'
|
||||
iconPath: '/assets/icons/list.svg',
|
||||
isSpecial: false,
|
||||
},
|
||||
{
|
||||
pagePath: '/pages/match/match',
|
||||
text: '找伙伴',
|
||||
iconType: 'match',
|
||||
isSpecial: true
|
||||
pagePath: '/pages/super-moments/super-moments',
|
||||
text: '动态',
|
||||
iconPath: '/assets/icons/sparkles.svg',
|
||||
isSpecial: false,
|
||||
},
|
||||
{
|
||||
pagePath: '/pages/my/my',
|
||||
text: '我的',
|
||||
iconType: 'user'
|
||||
}
|
||||
]
|
||||
iconPath: '/assets/icons/user.svg',
|
||||
isSpecial: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
lifetimes: {
|
||||
attached() {
|
||||
console.log('[TabBar] Component attached 生命周期触发')
|
||||
this.loadFeatureConfig()
|
||||
},
|
||||
ready() {
|
||||
console.log('[TabBar] Component ready 生命周期触发')
|
||||
// 如果 attached 中没有成功加载,在 ready 中再次尝试
|
||||
if (this.data.matchEnabled === undefined || this.data.matchEnabled === null) {
|
||||
console.log('[TabBar] 在 ready 中重新加载配置')
|
||||
this.loadFeatureConfig()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 页面加载时也调用(兼容性更好)
|
||||
attached() {
|
||||
console.log('[TabBar] attached() 方法触发')
|
||||
this.loadFeatureConfig()
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 加载功能配置
|
||||
buildTabList(matchEnabled, tabUi, auditMode) {
|
||||
const audit = !!auditMode
|
||||
const ui = tabUi || {}
|
||||
const h = ui.home ? String(ui.home) : '首页'
|
||||
const ch = ui.chapters ? String(ui.chapters) : '目录'
|
||||
const ma = ui.match ? String(ui.match) : '找伙伴'
|
||||
const mo = ui.moments ? String(ui.moments) : ui.feed ? String(ui.feed) : '动态'
|
||||
const my = ui.my ? String(ui.my) : '我的'
|
||||
const tabs = [
|
||||
{
|
||||
pagePath: '/pages/index/index',
|
||||
text: h,
|
||||
iconPath: '/assets/icons/home.svg',
|
||||
isSpecial: false,
|
||||
},
|
||||
{
|
||||
pagePath: '/pages/chapters/chapters',
|
||||
text: ch,
|
||||
iconPath: '/assets/icons/list.svg',
|
||||
isSpecial: false,
|
||||
},
|
||||
]
|
||||
if (matchEnabled) {
|
||||
tabs.push({
|
||||
pagePath: '/pages/match/match',
|
||||
text: ma,
|
||||
iconPath: '/assets/icons/partners.svg',
|
||||
isSpecial: true,
|
||||
})
|
||||
}
|
||||
if (!audit) {
|
||||
tabs.push({
|
||||
pagePath: '/pages/super-moments/super-moments',
|
||||
text: mo,
|
||||
iconPath: '/assets/icons/sparkles.svg',
|
||||
isSpecial: false,
|
||||
})
|
||||
}
|
||||
tabs.push({
|
||||
pagePath: '/pages/my/my',
|
||||
text: my,
|
||||
iconPath: '/assets/icons/user.svg',
|
||||
isSpecial: false,
|
||||
})
|
||||
return tabs
|
||||
},
|
||||
|
||||
async loadFeatureConfig() {
|
||||
try {
|
||||
console.log('[TabBar] 开始加载功能配置...')
|
||||
console.log('[TabBar] API地址:', app.globalData.baseUrl + '/api/miniprogram/config')
|
||||
|
||||
const res = await app.getConfig()
|
||||
|
||||
|
||||
// 兼容两种返回格式
|
||||
let matchEnabled = false
|
||||
|
||||
if (res && res.success && res.features) {
|
||||
console.log('[TabBar] features配置:', JSON.stringify(res.features))
|
||||
matchEnabled = res.features.matchEnabled === true
|
||||
console.log('[TabBar] matchEnabled值:', matchEnabled)
|
||||
} else if (res && res.configs && res.configs.feature_config) {
|
||||
// 备用格式:从 configs.feature_config 读取
|
||||
console.log('[TabBar] 使用备用格式,从configs读取')
|
||||
matchEnabled = res.configs.feature_config.matchEnabled === true
|
||||
console.log('[TabBar] matchEnabled值:', matchEnabled)
|
||||
} else {
|
||||
console.log('[TabBar] ⚠️ 未找到features配置,使用默认值false')
|
||||
console.log('[TabBar] res对象keys:', Object.keys(res || {}))
|
||||
}
|
||||
|
||||
const tabUi = app.globalData.configCache?.mpConfig?.mpUi?.tabBar || {}
|
||||
const list = [...this.data.list]
|
||||
if (tabUi.home) list[0] = { ...list[0], text: String(tabUi.home) }
|
||||
if (tabUi.chapters) list[1] = { ...list[1], text: String(tabUi.chapters) }
|
||||
if (tabUi.match) list[2] = { ...list[2], text: String(tabUi.match) }
|
||||
if (tabUi.my) list[3] = { ...list[3], text: String(tabUi.my) }
|
||||
|
||||
this.setData({ matchEnabled, list }, () => {
|
||||
console.log('[TabBar] ✅ matchEnabled已设置为:', this.data.matchEnabled)
|
||||
// 配置加载完成后,根据当前路由设置选中状态
|
||||
let matchEnabled = false
|
||||
if (res && res.success && res.features) {
|
||||
matchEnabled = res.features.matchEnabled === true
|
||||
} else if (res && res.configs && res.configs.feature_config) {
|
||||
matchEnabled = res.configs.feature_config.matchEnabled === true
|
||||
}
|
||||
|
||||
const tabUi = app.globalData.configCache?.mpConfig?.mpUi?.tabBar || {}
|
||||
try {
|
||||
await app.getAuditMode()
|
||||
} catch (_) {}
|
||||
const auditMode = !!app.globalData.auditMode
|
||||
const tabList = this.buildTabList(matchEnabled, tabUi, auditMode)
|
||||
|
||||
this.setData({ matchEnabled, tabList }, () => {
|
||||
this.updateSelected()
|
||||
})
|
||||
|
||||
// 如果当前在找伙伴页面,但功能已关闭,跳转到首页
|
||||
|
||||
if (!matchEnabled) {
|
||||
const pages = getCurrentPages()
|
||||
const currentPage = pages[pages.length - 1]
|
||||
if (currentPage && currentPage.route === 'pages/match/match') {
|
||||
console.log('[TabBar] 找伙伴功能已关闭,从match页面跳转到首页')
|
||||
wx.switchTab({ url: '/pages/index/index' })
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('[TabBar] ❌ 加载功能配置失败:', error)
|
||||
console.log('[TabBar] 错误详情:', error.message || error)
|
||||
// 默认关闭找伙伴功能
|
||||
this.setData({ matchEnabled: false }, () => {
|
||||
|
||||
if (auditMode) {
|
||||
const pages = getCurrentPages()
|
||||
const currentPage = pages[pages.length - 1]
|
||||
if (currentPage && currentPage.route === 'pages/super-moments/super-moments') {
|
||||
wx.switchTab({ url: '/pages/index/index' })
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
try {
|
||||
await app.getAuditMode()
|
||||
} catch (__) {}
|
||||
const auditMode = !!app.globalData.auditMode
|
||||
const tabList = this.buildTabList(false, {}, auditMode)
|
||||
this.setData({ matchEnabled: false, tabList }, () => {
|
||||
this.updateSelected()
|
||||
})
|
||||
if (auditMode) {
|
||||
const pages = getCurrentPages()
|
||||
const currentPage = pages[pages.length - 1]
|
||||
if (currentPage && currentPage.route === 'pages/super-moments/super-moments') {
|
||||
wx.switchTab({ url: '/pages/index/index' })
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 根据当前路由更新选中状态
|
||||
updateSelected() {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length === 0) return
|
||||
|
||||
const currentPage = pages[pages.length - 1]
|
||||
const route = currentPage.route
|
||||
|
||||
const route = pages[pages.length - 1].route
|
||||
const tabList = this.data.tabList || []
|
||||
let selected = 0
|
||||
const { matchEnabled } = this.data
|
||||
|
||||
// 根据路由匹配对应的索引
|
||||
if (route === 'pages/index/index') {
|
||||
selected = 0
|
||||
} else if (route === 'pages/chapters/chapters') {
|
||||
selected = 1
|
||||
} else if (route === 'pages/match/match') {
|
||||
selected = 2
|
||||
} else if (route === 'pages/my/my') {
|
||||
selected = matchEnabled ? 3 : 2
|
||||
for (let i = 0; i < tabList.length; i++) {
|
||||
const p = tabList[i].pagePath.replace(/^\//, '')
|
||||
if (route === p) {
|
||||
selected = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({ selected })
|
||||
},
|
||||
|
||||
switchTab(e) {
|
||||
const data = e.currentTarget.dataset
|
||||
const url = data.path
|
||||
const index = data.index
|
||||
|
||||
const url = e.currentTarget.dataset.path
|
||||
const index = Number(e.currentTarget.dataset.index)
|
||||
if (Number.isNaN(index)) return
|
||||
if (this.data.selected === index) return
|
||||
|
||||
wx.switchTab({ url })
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,47 +1,36 @@
|
||||
<!--custom-tab-bar/index.wxml-->
|
||||
<view class="tab-bar {{matchEnabled ? 'tab-bar-four' : 'tab-bar-three'}}">
|
||||
<view class="tab-bar" wx:if="{{tabList.length}}">
|
||||
<view class="tab-bar-border"></view>
|
||||
|
||||
<!-- 首页 -->
|
||||
<view class="tab-bar-item" data-path="{{list[0].pagePath}}" data-index="0" bindtap="switchTab">
|
||||
<view class="icon-wrapper">
|
||||
<image class="tab-icon {{selected === 0 ? 'icon-active' : ''}}"
|
||||
src="/assets/icons/home.svg"
|
||||
mode="aspectFit"
|
||||
style="color: {{selected === 0 ? selectedColor : color}}"></image>
|
||||
</view>
|
||||
<view class="tab-bar-text" style="color: {{selected === 0 ? selectedColor : color}}">{{list[0].text}}</view>
|
||||
</view>
|
||||
|
||||
<!-- 目录 -->
|
||||
<view class="tab-bar-item" data-path="{{list[1].pagePath}}" data-index="1" bindtap="switchTab">
|
||||
<view class="icon-wrapper">
|
||||
<image class="tab-icon {{selected === 1 ? 'icon-active' : ''}}"
|
||||
src="/assets/icons/list.svg"
|
||||
mode="aspectFit"
|
||||
style="color: {{selected === 1 ? selectedColor : color}}"></image>
|
||||
<block wx:for="{{tabList}}" wx:key="pagePath">
|
||||
<view
|
||||
wx:if="{{item.isSpecial}}"
|
||||
class="tab-bar-item special-item"
|
||||
data-path="{{item.pagePath}}"
|
||||
data-index="{{index}}"
|
||||
bindtap="switchTab"
|
||||
>
|
||||
<view class="special-button {{selected === index ? 'special-active' : ''}}">
|
||||
<image class="special-icon" src="{{item.iconPath}}" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="tab-bar-text special-text" style="color: {{selected === index ? selectedColor : color}}">{{item.text}}</view>
|
||||
</view>
|
||||
<view class="tab-bar-text" style="color: {{selected === 1 ? selectedColor : color}}">{{list[1].text}}</view>
|
||||
</view>
|
||||
|
||||
<!-- 找伙伴 - 中间突出按钮(根据配置显示) -->
|
||||
<view class="tab-bar-item special-item" wx:if="{{matchEnabled}}" data-path="{{list[2].pagePath}}" data-index="2" bindtap="switchTab">
|
||||
<view class="special-button {{selected === 2 ? 'special-active' : ''}}">
|
||||
<image class="special-icon"
|
||||
src="/assets/icons/partners.svg"
|
||||
mode="aspectFit"></image>
|
||||
<view
|
||||
wx:else
|
||||
class="tab-bar-item"
|
||||
data-path="{{item.pagePath}}"
|
||||
data-index="{{index}}"
|
||||
bindtap="switchTab"
|
||||
>
|
||||
<view class="icon-wrapper">
|
||||
<image
|
||||
class="tab-icon {{selected === index ? 'icon-active' : ''}}"
|
||||
src="{{item.iconPath}}"
|
||||
mode="aspectFit"
|
||||
></image>
|
||||
</view>
|
||||
<view class="tab-bar-text" style="color: {{selected === index ? selectedColor : color}}">{{item.text}}</view>
|
||||
</view>
|
||||
<view class="tab-bar-text special-text" style="color: {{selected === 2 ? selectedColor : color}}">{{list[2].text}}</view>
|
||||
</view>
|
||||
|
||||
<!-- 我的 -->
|
||||
<view class="tab-bar-item" data-path="{{list[3].pagePath}}" data-index="{{matchEnabled ? 3 : 2}}" bindtap="switchTab">
|
||||
<view class="icon-wrapper">
|
||||
<image class="tab-icon {{(matchEnabled && selected === 3) || (!matchEnabled && selected === 2) ? 'icon-active' : ''}}"
|
||||
src="/assets/icons/user.svg"
|
||||
mode="aspectFit"
|
||||
style="color: {{(matchEnabled && selected === 3) || (!matchEnabled && selected === 2) ? selectedColor : color}}"></image>
|
||||
</view>
|
||||
<view class="tab-bar-text" style="color: {{(matchEnabled && selected === 3) || (!matchEnabled && selected === 2) ? selectedColor : color}}">{{list[3].text}}</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
@@ -91,7 +91,7 @@ Page({
|
||||
// 我的余额
|
||||
walletBalanceText: '--',
|
||||
|
||||
// 超级个体:快捷入口「客资 / 链接与轨迹」
|
||||
// 超级个体:快捷入口「链接轨迹」
|
||||
showSuperCrmEntry: false,
|
||||
// 超级个体:发文章入口
|
||||
showSuperArticleEntry: false,
|
||||
|
||||
@@ -100,35 +100,30 @@
|
||||
<view class="stat-icon-wrap">
|
||||
<image class="stat-icon-img" src="/assets/icons/list-teal.svg" mode="aspectFit"/>
|
||||
</view>
|
||||
<text class="stat-num">订单</text>
|
||||
<text class="stat-label">我的订单</text>
|
||||
</view>
|
||||
<view class="stat-box" hover-class="stat-box-hover" wx:if="{{!auditMode}}" bindtap="handleMenuTap" data-id="giftPay">
|
||||
<view class="stat-icon-wrap">
|
||||
<image class="stat-icon-img" src="/assets/icons/share-teal.svg" mode="aspectFit"/>
|
||||
</view>
|
||||
<text class="stat-num">代付</text>
|
||||
<text class="stat-label">我的代付</text>
|
||||
</view>
|
||||
<view class="stat-box" hover-class="stat-box-hover" wx:if="{{!auditMode}}" bindtap="handleMenuTap" data-id="wallet">
|
||||
<view class="stat-icon-wrap">
|
||||
<image class="stat-icon-img" src="/assets/icons/wallet-teal.svg" mode="aspectFit"/>
|
||||
</view>
|
||||
<text class="stat-num stat-num-balance">{{walletBalanceText}}</text>
|
||||
<text class="stat-label">我的余额</text>
|
||||
</view>
|
||||
<view class="stat-box" hover-class="stat-box-hover" wx:if="{{showSuperCrmEntry}}" bindtap="handleMenuTap" data-id="superCrm">
|
||||
<view class="stat-icon-wrap">
|
||||
<image class="stat-icon-img" src="/assets/icons/users-teal.svg" mode="aspectFit"/>
|
||||
</view>
|
||||
<text class="stat-num">客资</text>
|
||||
<text class="stat-label">链接与轨迹</text>
|
||||
<text class="stat-label">链接轨迹</text>
|
||||
</view>
|
||||
<view class="stat-box" hover-class="stat-box-hover" wx:if="{{showSuperArticleEntry && !auditMode}}" bindtap="handleMenuTap" data-id="superArticle">
|
||||
<view class="stat-icon-wrap">
|
||||
<image class="stat-icon-img" src="/assets/icons/book-arrow-teal.svg" mode="aspectFit"/>
|
||||
</view>
|
||||
<text class="stat-num">发文</text>
|
||||
<text class="stat-label">发布文章</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -187,6 +187,11 @@
|
||||
.card-icon-img { width: 40rpx; height: 40rpx; flex-shrink: 0; }
|
||||
.card-title { font-size: 32rpx; font-weight: bold; color: #fff; }
|
||||
|
||||
/* 快捷入口:略减卡片底边距,避免第二行下方大块留白 */
|
||||
.stats-card {
|
||||
padding-bottom: 24rpx;
|
||||
}
|
||||
|
||||
/* ===== 一键收款卡片 ===== */
|
||||
.receive-card { padding: 28rpx 32rpx; }
|
||||
.receive-top { display: flex; align-items: center; justify-content: space-between; gap: 16rpx; }
|
||||
@@ -219,15 +224,15 @@
|
||||
/* 快捷入口:列数由页面 quickEntryGridCols 绑定(≤4 铺满一行;>4 时为 4 列换行) */
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
gap: 24rpx;
|
||||
gap: 20rpx 16rpx;
|
||||
align-items: stretch;
|
||||
}
|
||||
.stat-box {
|
||||
background: linear-gradient(155deg, rgba(42, 42, 42, 0.98) 0%, rgba(28, 35, 34, 0.99) 100%);
|
||||
border-radius: 22rpx;
|
||||
padding: 28rpx 16rpx 24rpx;
|
||||
padding: 18rpx 12rpx 16rpx;
|
||||
display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
|
||||
min-height: 168rpx;
|
||||
min-height: 128rpx;
|
||||
border: 1rpx solid rgba(79, 209, 197, 0.22);
|
||||
box-shadow:
|
||||
0 6rpx 22rpx rgba(0, 0, 0, 0.35),
|
||||
@@ -247,7 +252,7 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
margin-bottom: 14rpx;
|
||||
margin-bottom: 8rpx;
|
||||
background: linear-gradient(145deg, rgba(79, 209, 197, 0.28) 0%, rgba(79, 209, 197, 0.06) 55%, rgba(20, 60, 55, 0.35) 100%);
|
||||
border: 1rpx solid rgba(79, 209, 197, 0.38);
|
||||
box-shadow:
|
||||
@@ -256,22 +261,7 @@
|
||||
inset 0 1rpx 0 rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
.stat-icon-img { width: 48rpx; height: 48rpx; flex-shrink: 0; display: block; }
|
||||
.stat-num {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
line-height: 1.25;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.stat-num-balance {
|
||||
font-size: 30rpx;
|
||||
font-variant-numeric: tabular-nums;
|
||||
background: linear-gradient(90deg, #5eead4 0%, #4fd1c5 50%, #2dd4bf 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
}
|
||||
.stat-label { font-size: 20rpx; color: #8B939E; margin-top: 6rpx; line-height: 1.25; text-align: center; }
|
||||
.stat-label { font-size: 22rpx; color: #8B939E; margin-top: 4rpx; line-height: 1.25; text-align: center; }
|
||||
|
||||
/* 最近阅读 */
|
||||
.recent-list { display: flex; flex-direction: column; gap: 24rpx; }
|
||||
|
||||
@@ -80,12 +80,15 @@ Page({
|
||||
this.setData({ loading: false })
|
||||
return
|
||||
}
|
||||
const imgs = Array.isArray(article.images)
|
||||
? article.images.map((u) => String(u || '').trim()).filter(Boolean)
|
||||
: []
|
||||
this.setData({
|
||||
article: {
|
||||
...article,
|
||||
article: Object.assign({}, article, {
|
||||
createdAtText: formatTime(article.createdAt),
|
||||
imageUrls: imgs,
|
||||
contentHtml: renderArticleHtml(article.content),
|
||||
},
|
||||
}),
|
||||
articleId: String(id),
|
||||
h5ReadUrl: buildH5ReadUrl(id),
|
||||
loading: false,
|
||||
@@ -97,6 +100,15 @@ Page({
|
||||
goBack() {
|
||||
wx.navigateBack({ fail: () => wx.switchTab({ url: '/pages/my/my' }) })
|
||||
},
|
||||
previewArticleImage(e) {
|
||||
const current = e.currentTarget.dataset.current || ''
|
||||
const urls = (this.data.article && this.data.article.imageUrls) || []
|
||||
if (!urls.length) return
|
||||
wx.previewImage({
|
||||
urls,
|
||||
current: current || urls[0],
|
||||
})
|
||||
},
|
||||
copyH5Link() {
|
||||
const url = this.data.h5ReadUrl
|
||||
if (!url) {
|
||||
|
||||
@@ -8,9 +8,20 @@
|
||||
</view>
|
||||
<view style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<view class="card" wx:if="{{article}}">
|
||||
<view class="article-body" wx:if="{{article}}">
|
||||
<text class="title">{{article.title}}</text>
|
||||
<text class="meta">{{article.authorNickname || '超级个体'}} · {{article.createdAtText}}</text>
|
||||
<view class="img-gallery" wx:if="{{article.imageUrls.length}}">
|
||||
<image
|
||||
wx:for="{{article.imageUrls}}"
|
||||
wx:key="*this"
|
||||
class="article-gallery-img"
|
||||
mode="widthFix"
|
||||
src="{{item}}"
|
||||
bindtap="previewArticleImage"
|
||||
data-current="{{item}}"
|
||||
/>
|
||||
</view>
|
||||
<view class="h5-row" wx:if="{{h5ReadUrl}}">
|
||||
<view class="h5-btn" bindtap="copyH5Link">复制 H5 全文链接</view>
|
||||
<text class="h5-hint">浏览器或微信内打开可阅读全文,方便分享</text>
|
||||
|
||||
@@ -6,16 +6,30 @@
|
||||
}
|
||||
.nav-back, .nav-placeholder { width: 64rpx; }
|
||||
.nav-title { font-size: 32rpx; font-weight: 700; }
|
||||
.card {
|
||||
margin: 24rpx; padding: 30rpx; border-radius: 24rpx;
|
||||
background: rgba(15, 23, 42, 0.86); border: 1rpx solid rgba(148, 163, 184, 0.2);
|
||||
.article-body {
|
||||
padding: 8rpx 24rpx 48rpx;
|
||||
}
|
||||
.title { font-size: 36rpx; font-weight: 700; line-height: 1.4; display: block; }
|
||||
.meta { margin-top: 12rpx; font-size: 22rpx; color: #94a3b8; display: block; }
|
||||
.h5-row { margin-top: 20rpx; padding-top: 20rpx; border-top: 1rpx solid rgba(148, 163, 184, 0.2); }
|
||||
.img-gallery {
|
||||
margin-top: 20rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
.article-gallery-img {
|
||||
width: 100%;
|
||||
display: block;
|
||||
border-radius: 0;
|
||||
}
|
||||
.h5-row { margin-top: 28rpx; padding-top: 0; border-top: none; }
|
||||
.h5-btn {
|
||||
display: inline-block; padding: 12rpx 24rpx; border-radius: 999rpx; font-size: 24rpx; font-weight: 600;
|
||||
color: #0ea5e9; background: rgba(14, 165, 233, 0.12); border: 1rpx solid rgba(14, 165, 233, 0.45);
|
||||
display: inline-block;
|
||||
padding: 12rpx 0;
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: #22d3ee;
|
||||
background: transparent;
|
||||
}
|
||||
.h5-hint { display: block; margin-top: 12rpx; font-size: 20rpx; color: #64748b; line-height: 1.5; }
|
||||
.content {
|
||||
|
||||
@@ -15,10 +15,13 @@ function newAttachId() {
|
||||
|
||||
Page({
|
||||
data: {
|
||||
/** 临时隐藏「AI 写文章」卡片;需上线时再设为 true */
|
||||
showAiWriteSection: false,
|
||||
statusBarHeight: 44,
|
||||
auditMode: false,
|
||||
title: '',
|
||||
content: '',
|
||||
bodyImages: [],
|
||||
saving: false,
|
||||
meNickname: '',
|
||||
aiPrompt: '',
|
||||
@@ -99,6 +102,117 @@ Page({
|
||||
this.setData({ content: `${this.data.content}#链接(https://)` })
|
||||
},
|
||||
|
||||
/** 编辑区配图(发布后展示在正文前),最多 9 张 */
|
||||
chooseArticleImages() {
|
||||
this.syncAuditMode()
|
||||
if (this.data.auditMode || app.globalData.auditMode) {
|
||||
wx.showToast({ title: '审核模式下不可用', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const max = 9
|
||||
const cur = this.data.bodyImages.length
|
||||
if (cur >= max) {
|
||||
wx.showToast({ title: '最多 9 张配图', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const pickCount = max - cur
|
||||
const mapFromChooseMedia = (res) => {
|
||||
const files = res.tempFiles || []
|
||||
return files.map((f, i) => ({
|
||||
path: f.tempFilePath,
|
||||
name: `配图_${Date.now()}_${i}.jpg`,
|
||||
size: f.size || 0,
|
||||
}))
|
||||
}
|
||||
const mapFromChooseImage = (res) => {
|
||||
const paths = res.tempFilePaths || []
|
||||
const t = Date.now()
|
||||
return paths.map((path, i) => ({
|
||||
path,
|
||||
name: `配图_${t}_${i}.jpg`,
|
||||
size: 0,
|
||||
}))
|
||||
}
|
||||
const runUpload = async (tempFiles) => {
|
||||
for (const f of tempFiles) {
|
||||
if (this.data.bodyImages.length >= max) break
|
||||
await this._uploadOneArticleBodyImage(f)
|
||||
}
|
||||
}
|
||||
if (typeof wx.chooseMedia === 'function') {
|
||||
wx.chooseMedia({
|
||||
count: pickCount,
|
||||
mediaType: ['image'],
|
||||
sourceType: ['album', 'camera'],
|
||||
sizeType: ['compressed'],
|
||||
success: (res) => {
|
||||
void runUpload(mapFromChooseMedia(res))
|
||||
},
|
||||
fail: (err) => {
|
||||
const em = String((err && err.errMsg) || '')
|
||||
if (/cancel|取消/i.test(em)) return
|
||||
wx.showToast({ title: '选择图片失败', icon: 'none' })
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
if (typeof wx.chooseImage === 'function') {
|
||||
wx.chooseImage({
|
||||
count: pickCount,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
void runUpload(mapFromChooseImage(res))
|
||||
},
|
||||
fail: (err) => {
|
||||
const em = String((err && err.errMsg) || '')
|
||||
if (/cancel|取消/i.test(em)) return
|
||||
wx.showToast({ title: '选择图片失败', icon: 'none' })
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
wx.showToast({ title: '当前环境不支持选图片', icon: 'none' })
|
||||
},
|
||||
|
||||
async _uploadOneArticleBodyImage(f) {
|
||||
const filePath = f.path
|
||||
const name = String(f.name || '配图').trim() || '配图'
|
||||
const size = f.size || 0
|
||||
if (!filePath) return
|
||||
if (size > 29 * 1024 * 1024) {
|
||||
wx.showToast({ title: '单张请勿超过 30MB', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const id = newAttachId()
|
||||
this.setData({
|
||||
bodyImages: this.data.bodyImages.concat([{ id, url: '', uploading: true }]),
|
||||
})
|
||||
try {
|
||||
const up = await uploadByApi({ filePath, folder: 'super-article-images' })
|
||||
const url = this._pickUploadUrl(up)
|
||||
if (!url) throw new Error('no url')
|
||||
const next = this.data.bodyImages.map((x) =>
|
||||
x.id === id ? Object.assign({}, x, { url, uploading: false }) : x,
|
||||
)
|
||||
this.setData({ bodyImages: next })
|
||||
} catch (_) {
|
||||
this.setData({
|
||||
bodyImages: this.data.bodyImages.filter((x) => x.id !== id),
|
||||
})
|
||||
wx.showToast({ title: `${name} 上传失败`, icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
removeArticleImage(e) {
|
||||
if (this.data.auditMode) return
|
||||
const id = e.currentTarget.dataset.id
|
||||
if (!id) return
|
||||
this.setData({
|
||||
bodyImages: this.data.bodyImages.filter((x) => x.id !== id),
|
||||
})
|
||||
},
|
||||
|
||||
/** 参考素材:仅从相册/相机选图片并上传(AI 侧按图理解) */
|
||||
chooseReferenceImages() {
|
||||
this.syncAuditMode()
|
||||
@@ -334,19 +448,30 @@ Page({
|
||||
wx.showToast({ title: '请填写标题和正文', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (this.data.bodyImages.some((x) => x.uploading)) {
|
||||
wx.showToast({ title: '请等待配图上传完成', icon: 'none' })
|
||||
return
|
||||
}
|
||||
const images = this.data.bodyImages
|
||||
.map((x) => String(x.url || '').trim())
|
||||
.filter(Boolean)
|
||||
this.setData({ saving: true })
|
||||
wx.showLoading({ title: '发布中…', mask: true })
|
||||
try {
|
||||
const res = await app.request({
|
||||
url: '/api/miniprogram/super/articles',
|
||||
method: 'POST',
|
||||
data: { userId, title, content },
|
||||
data: { userId, title, content, images },
|
||||
})
|
||||
if (!res?.success) throw new Error(res?.error || '发布失败')
|
||||
this.setData({ title: '', content: '', bodyImages: [] })
|
||||
wx.showToast({ title: '发布成功', icon: 'success' })
|
||||
setTimeout(() => wx.navigateBack(), 400)
|
||||
} catch (e) {
|
||||
wx.showToast({ title: e.message || '发布失败', icon: 'none' })
|
||||
} finally {
|
||||
try {
|
||||
wx.hideLoading()
|
||||
} catch (_) {}
|
||||
this.setData({ saving: false })
|
||||
}
|
||||
},
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
</view>
|
||||
<view style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<!-- AI:参考图片 + 提示词 -->
|
||||
<view class="card">
|
||||
<!-- AI:参考图片 + 提示词(开关:showAiWriteSection) -->
|
||||
<view wx:if="{{showAiWriteSection}}" class="card">
|
||||
<text class="section-title">AI 写文章</text>
|
||||
<text class="label">参考图片(可多选)</text>
|
||||
<view class="file-actions">
|
||||
@@ -42,6 +42,19 @@
|
||||
<input class="input" maxlength="40" placeholder="写个标题(最多40字)" value="{{title}}" bindinput="onTitleInput" disabled="{{auditMode}}" />
|
||||
</view>
|
||||
|
||||
<text class="label">配图(可选,最多 9 张)</text>
|
||||
<view class="file-actions">
|
||||
<view class="add-file-btn" bindtap="chooseArticleImages">+ 添加配图</view>
|
||||
</view>
|
||||
<view class="body-img-grid" wx:if="{{bodyImages.length}}">
|
||||
<view wx:for="{{bodyImages}}" wx:key="id" class="body-img-cell">
|
||||
<image wx:if="{{item.url}}" class="body-img-thumb" mode="aspectFill" src="{{item.url}}" />
|
||||
<view wx:if="{{item.uploading}}" class="body-img-mask">上传中…</view>
|
||||
<text class="body-img-remove" data-id="{{item.id}}" bindtap="removeArticleImage">×</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="hint">配图会展示在正文上方(与书籍正文分离存储);单张建议不超 30MB。</text>
|
||||
|
||||
<text class="label">正文</text>
|
||||
<view class="toolbar">
|
||||
<view class="tool-btn" bindtap="insertMentionSelf">@自己</view>
|
||||
@@ -52,7 +65,7 @@
|
||||
</view>
|
||||
<text class="hint">提示:可直接输入 @昵称 或 #链接(https://xxx)</text>
|
||||
|
||||
<view class="submit-btn" bindtap="submitArticle">{{saving ? '发布中…' : '发布文章'}}</view>
|
||||
<view class="submit-btn {{saving ? 'submit-btn-loading' : ''}}" bindtap="submitArticle">{{saving ? '发布中…' : '发布文章'}}</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{auditMode}}" class="audit-mode-mask" catchtouchmove="preventMove">
|
||||
|
||||
@@ -36,6 +36,54 @@
|
||||
.file-remove {
|
||||
flex-shrink: 0; font-size: 24rpx; color: #f97316; padding: 8rpx 12rpx;
|
||||
}
|
||||
.body-img-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.body-img-cell {
|
||||
position: relative;
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 14rpx;
|
||||
overflow: hidden;
|
||||
background: rgba(2, 6, 23, 0.65);
|
||||
border: 1rpx solid rgba(148, 163, 184, 0.18);
|
||||
}
|
||||
.body-img-thumb {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
.body-img-mask {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22rpx;
|
||||
color: #94a3b8;
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
}
|
||||
.body-img-remove {
|
||||
position: absolute;
|
||||
right: 6rpx;
|
||||
top: 4rpx;
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
line-height: 40rpx;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.45);
|
||||
border-radius: 999rpx;
|
||||
z-index: 2;
|
||||
}
|
||||
.prompt-textarea { min-height: 200rpx; }
|
||||
.generate-btn {
|
||||
margin-top: 20rpx; height: 88rpx; border-radius: 16rpx;
|
||||
@@ -60,6 +108,7 @@
|
||||
color: #032b35; font-size: 30rpx; font-weight: 700;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.submit-btn-loading { opacity: 0.72; pointer-events: none; }
|
||||
|
||||
/* 审核模式:盖住整页(含自定义导航),高于 .nav-bar 的 z-index: 10 */
|
||||
.audit-mode-mask {
|
||||
|
||||
157
miniprogram/pages/super-moments/super-moments.js
Normal file
157
miniprogram/pages/super-moments/super-moments.js
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* 动态广场:超级个体图文列表(触底分页)
|
||||
*/
|
||||
const app = getApp()
|
||||
const { isSafeImageSrc } = require('../../utils/imageUrl.js')
|
||||
|
||||
const PAGE_SIZE = 10
|
||||
|
||||
function avatarLetter(name) {
|
||||
const s = String(name || '').trim()
|
||||
if (!s) return '会'
|
||||
const ch = s[0]
|
||||
return /[\u4e00-\u9fff]/.test(ch) ? ch : '会'
|
||||
}
|
||||
|
||||
function relativeTime(iso) {
|
||||
if (!iso) return ''
|
||||
const d = new Date(iso)
|
||||
const t = d.getTime()
|
||||
if (Number.isNaN(t)) return ''
|
||||
const sec = Math.max(0, Math.floor((Date.now() - t) / 1000))
|
||||
if (sec < 60) return '刚刚'
|
||||
if (sec < 3600) return `${Math.floor(sec / 60)}分钟前`
|
||||
if (sec < 86400) return `${Math.floor(sec / 3600)}小时前`
|
||||
if (sec < 86400 * 7) return `${Math.floor(sec / 86400)}天前`
|
||||
const m = `${d.getMonth() + 1}`.padStart(2, '0')
|
||||
const day = `${d.getDate()}`.padStart(2, '0')
|
||||
return `${m}-${day}`
|
||||
}
|
||||
|
||||
function mapFeedRows(rows) {
|
||||
return (rows || []).map((r) => {
|
||||
const nick = String(r.authorNickname || '').trim() || '超级个体'
|
||||
const av = String(r.authorAvatar || '').trim()
|
||||
const avatarOk = isSafeImageSrc(av)
|
||||
const imgs = Array.isArray(r.images) ? r.images : []
|
||||
const displayImages = imgs.map((u) => String(u || '').trim()).filter((u) => isSafeImageSrc(u))
|
||||
return Object.assign({}, r, {
|
||||
authorNickname: nick,
|
||||
avatarSrc: av,
|
||||
avatarOk,
|
||||
avatarLetter: avatarLetter(nick),
|
||||
timeText: relativeTime(r.createdAt),
|
||||
preview: String(r.preview || '').trim(),
|
||||
displayImages,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 44,
|
||||
feedList: [],
|
||||
page: 1,
|
||||
total: 0,
|
||||
hasMore: true,
|
||||
loading: true,
|
||||
loadingMore: false,
|
||||
},
|
||||
|
||||
async onLoad() {
|
||||
this.setData({ statusBarHeight: app.globalData.statusBarHeight || 44 })
|
||||
try {
|
||||
await app.getAuditMode()
|
||||
} catch (_) {}
|
||||
if (app.globalData.auditMode) {
|
||||
wx.switchTab({ url: '/pages/index/index' })
|
||||
return
|
||||
}
|
||||
this.reloadFeed()
|
||||
},
|
||||
|
||||
async onShow() {
|
||||
try {
|
||||
await app.getAuditMode()
|
||||
} catch (_) {}
|
||||
if (app.globalData.auditMode) {
|
||||
wx.switchTab({ url: '/pages/index/index' })
|
||||
return
|
||||
}
|
||||
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
|
||||
const tabBar = this.getTabBar()
|
||||
if (tabBar && tabBar.loadFeatureConfig) tabBar.loadFeatureConfig()
|
||||
if (tabBar && tabBar.updateSelected) tabBar.updateSelected()
|
||||
}
|
||||
},
|
||||
|
||||
onReachBottom() {
|
||||
this.loadMore()
|
||||
},
|
||||
|
||||
async reloadFeed() {
|
||||
this.setData({
|
||||
loading: true,
|
||||
page: 1,
|
||||
feedList: [],
|
||||
hasMore: true,
|
||||
total: 0,
|
||||
})
|
||||
try {
|
||||
await this.fetchPage(1, true)
|
||||
} finally {
|
||||
this.setData({ loading: false })
|
||||
}
|
||||
},
|
||||
|
||||
async loadMore() {
|
||||
if (this.data.loading || this.data.loadingMore || !this.data.hasMore) return
|
||||
const next = this.data.page + 1
|
||||
this.setData({ loadingMore: true })
|
||||
try {
|
||||
await this.fetchPage(next, false)
|
||||
} finally {
|
||||
this.setData({ loadingMore: false })
|
||||
}
|
||||
},
|
||||
|
||||
async fetchPage(page, replace) {
|
||||
const res = await app.request({
|
||||
url: `/api/miniprogram/super/articles/feed?page=${encodeURIComponent(String(page))}&pageSize=${PAGE_SIZE}`,
|
||||
silent: true,
|
||||
})
|
||||
if (!res?.success) {
|
||||
wx.showToast({ title: String(res?.error || '加载失败'), icon: 'none' })
|
||||
if (replace) this.setData({ feedList: [], hasMore: false, total: 0 })
|
||||
return
|
||||
}
|
||||
const list = mapFeedRows(res.list || [])
|
||||
const total = Number(res.total) || 0
|
||||
const merged = replace ? list : this.data.feedList.concat(list)
|
||||
const hasMore = merged.length < total
|
||||
this.setData({
|
||||
feedList: merged,
|
||||
page,
|
||||
total,
|
||||
hasMore,
|
||||
})
|
||||
},
|
||||
|
||||
openArticle(e) {
|
||||
const id = e.currentTarget.dataset.id
|
||||
if (!id) return
|
||||
wx.navigateTo({
|
||||
url: `/pages/super-article-detail/super-article-detail?id=${encodeURIComponent(String(id))}`,
|
||||
})
|
||||
},
|
||||
|
||||
previewArticleImages(e) {
|
||||
const fi = Number(e.currentTarget.dataset.feedIndex)
|
||||
const ii = Number(e.currentTarget.dataset.imgIndex)
|
||||
const row = this.data.feedList[fi]
|
||||
const urls = row && row.displayImages ? row.displayImages : []
|
||||
if (!urls.length) return
|
||||
const current = urls[ii] || urls[0]
|
||||
wx.previewImage({ urls, current })
|
||||
},
|
||||
})
|
||||
9
miniprogram/pages/super-moments/super-moments.json
Normal file
9
miniprogram/pages/super-moments/super-moments.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"usingComponents": {
|
||||
"icon": "/components/icon/icon"
|
||||
},
|
||||
"enablePullDownRefresh": false,
|
||||
"onReachBottomDistance": 160,
|
||||
"backgroundTextStyle": "light",
|
||||
"backgroundColor": "#0b1220"
|
||||
}
|
||||
61
miniprogram/pages/super-moments/super-moments.wxml
Normal file
61
miniprogram/pages/super-moments/super-moments.wxml
Normal file
@@ -0,0 +1,61 @@
|
||||
<view class="page">
|
||||
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
|
||||
<view class="nav-placeholder"></view>
|
||||
<text class="nav-title">动态广场</text>
|
||||
<view class="nav-placeholder"></view>
|
||||
</view>
|
||||
<view class="nav-offset" style="height: {{statusBarHeight + 44}}px;"></view>
|
||||
|
||||
<view class="feed-wrap">
|
||||
<view class="empty-block" wx:if="{{!loading && feedList.length === 0}}">
|
||||
<text class="empty-text">暂无动态</text>
|
||||
<text class="empty-sub">超级个体发文后将出现在这里</text>
|
||||
</view>
|
||||
|
||||
<block wx:for="{{feedList}}" wx:key="id">
|
||||
<view class="feed-item" bindtap="openArticle" data-id="{{item.id}}">
|
||||
<view class="feed-head">
|
||||
<image
|
||||
wx:if="{{item.avatarOk}}"
|
||||
class="feed-avatar"
|
||||
mode="aspectFill"
|
||||
src="{{item.avatarSrc}}"
|
||||
/>
|
||||
<view wx:else class="feed-avatar feed-avatar-ph">{{item.avatarLetter}}</view>
|
||||
<view class="feed-head-mid">
|
||||
<text class="feed-name">{{item.authorNickname || '超级个体'}}</text>
|
||||
<text class="feed-time">{{item.timeText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<text class="feed-title" wx:if="{{item.title}}">{{item.title}}</text>
|
||||
<text class="feed-preview">{{item.preview}}</text>
|
||||
|
||||
<view class="feed-imgs" wx:if="{{item.displayImages.length}}">
|
||||
<image
|
||||
wx:for="{{item.displayImages}}"
|
||||
wx:for-item="img"
|
||||
wx:for-index="ii"
|
||||
wx:key="*this"
|
||||
class="feed-img {{item.displayImages.length === 1 ? 'feed-img-one' : ''}}"
|
||||
mode="aspectFill"
|
||||
src="{{img}}"
|
||||
catchtap="previewArticleImages"
|
||||
data-feed-index="{{index}}"
|
||||
data-img-index="{{ii}}"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="feed-foot">
|
||||
<text class="feed-more">查看全文</text>
|
||||
<icon name="chevron-right" size="28" color="rgba(34,211,238,0.75)" customClass="feed-more-icon"></icon>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view class="load-more" wx:if="{{feedList.length}}">
|
||||
<text wx:if="{{loadingMore}}">加载中…</text>
|
||||
<text wx:elif="{{!hasMore}}">已经到底啦</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
164
miniprogram/pages/super-moments/super-moments.wxss
Normal file
164
miniprogram/pages/super-moments/super-moments.wxss
Normal file
@@ -0,0 +1,164 @@
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #0b1220;
|
||||
color: #e2e8f0;
|
||||
padding-bottom: calc(220rpx + env(safe-area-inset-bottom, 0px));
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 44px;
|
||||
padding: 0 24rpx;
|
||||
background: rgba(5, 11, 20, 0.92);
|
||||
border-bottom: 1rpx solid rgba(148, 163, 184, 0.08);
|
||||
}
|
||||
|
||||
.nav-placeholder {
|
||||
width: 64rpx;
|
||||
}
|
||||
|
||||
.nav-title {
|
||||
font-size: 34rpx;
|
||||
font-weight: 700;
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.feed-wrap {
|
||||
padding: 8rpx 0 32rpx;
|
||||
}
|
||||
|
||||
.empty-block {
|
||||
padding: 120rpx 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
display: block;
|
||||
font-size: 30rpx;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.empty-sub {
|
||||
display: block;
|
||||
margin-top: 16rpx;
|
||||
font-size: 24rpx;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
/* 扁平信息流:无卡片底、无描边、无阴影 */
|
||||
.feed-item {
|
||||
padding: 28rpx 24rpx 36rpx;
|
||||
}
|
||||
|
||||
.feed-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.feed-avatar {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
background: #1e293b;
|
||||
}
|
||||
|
||||
.feed-avatar-ph {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #67e8f9;
|
||||
background: rgba(30, 41, 59, 0.65);
|
||||
}
|
||||
|
||||
.feed-head-mid {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
}
|
||||
|
||||
.feed-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
color: #f1f5f9;
|
||||
}
|
||||
|
||||
.feed-time {
|
||||
font-size: 22rpx;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.feed-title {
|
||||
display: block;
|
||||
margin-top: 18rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #f8fafc;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.feed-preview {
|
||||
display: block;
|
||||
margin-top: 12rpx;
|
||||
font-size: 26rpx;
|
||||
color: #cbd5e1;
|
||||
line-height: 1.55;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.feed-imgs {
|
||||
margin-top: 16rpx;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.feed-img {
|
||||
width: calc((100% - 20rpx) / 3);
|
||||
height: 200rpx;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.feed-img-one {
|
||||
width: 100%;
|
||||
height: 320rpx;
|
||||
}
|
||||
|
||||
.feed-foot {
|
||||
margin-top: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 4rpx;
|
||||
}
|
||||
|
||||
.feed-more {
|
||||
font-size: 24rpx;
|
||||
color: rgba(34, 211, 238, 0.85);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.feed-more-icon {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
text-align: center;
|
||||
padding: 24rpx 0 48rpx;
|
||||
font-size: 24rpx;
|
||||
color: #64748b;
|
||||
}
|
||||
Reference in New Issue
Block a user