Browse Source

授权登录,手机号登录,发布文章视频列表

master
ZhaoYang 2 months ago
parent
commit
ae14fa6e7a
  1. 8
      app.json
  2. 41
      pages/home/home.js
  3. 6
      pages/home/home.wxml
  4. 18
      pages/home/home.wxss
  5. BIN
      pages/images/sjh.png
  6. BIN
      pagesA/images/jh.png
  7. 66
      pagesA/pages/askingSy/askingSy.js
  8. 3
      pagesA/pages/askingSy/askingSy.json
  9. 2
      pagesA/pages/askingSy/askingSy.wxml
  10. 1
      pagesA/pages/askingSy/askingSy.wxss
  11. 154
      pagesA/pages/carouselDetail/carouselDetail.js
  12. 4
      pagesA/pages/carouselDetail/carouselDetail.json
  13. 104
      pagesA/pages/carouselDetail/carouselDetail.wxml
  14. 284
      pagesA/pages/carouselDetail/carouselDetail.wxss
  15. BIN
      pagesB/images/bo.png
  16. BIN
      pagesB/images/hf.png
  17. BIN
      pagesB/images/lll.png
  18. BIN
      pagesB/images/sou.png
  19. 286
      pagesB/pages/administrativeDivision/administrativeDivision.js
  20. 4
      pagesB/pages/administrativeDivision/administrativeDivision.json
  21. 95
      pagesB/pages/administrativeDivision/administrativeDivision.wxml
  22. 316
      pagesB/pages/administrativeDivision/administrativeDivision.wxss
  23. 580
      pagesB/pages/publishAdd/publishAdd.js
  24. 4
      pagesB/pages/publishAdd/publishAdd.json
  25. 205
      pagesB/pages/publishAdd/publishAdd.wxml
  26. 457
      pagesB/pages/publishAdd/publishAdd.wxss
  27. 66
      pagesB/pages/repository/repository.js
  28. 3
      pagesB/pages/repository/repository.json
  29. 2
      pagesB/pages/repository/repository.wxml
  30. 1
      pagesB/pages/repository/repository.wxss
  31. 381
      pagesB/pages/spDetails/spDetails.js
  32. 4
      pagesB/pages/spDetails/spDetails.json
  33. 174
      pagesB/pages/spDetails/spDetails.wxml
  34. 664
      pagesB/pages/spDetails/spDetails.wxss
  35. 402
      pagesB/pages/training/training.js
  36. 4
      pagesB/pages/training/training.json
  37. 215
      pagesB/pages/training/training.wxml
  38. 1105
      pagesB/pages/training/training.wxss
  39. 99
      pagesB/pages/wzDetails/wzDetails.js
  40. 4
      pagesB/pages/wzDetails/wzDetails.json
  41. 62
      pagesB/pages/wzDetails/wzDetails.wxml
  42. 322
      pagesB/pages/wzDetails/wzDetails.wxss
  43. 123
      utils/api.js

8
app.json

@ -9,13 +9,17 @@
{
"root": "pagesA",
"pages": [
"pages/askingSy/askingSy"
"pages/carouselDetail/carouselDetail"
]
},
{
"root": "pagesB",
"pages": [
"pages/repository/repository"
"pages/administrativeDivision/administrativeDivision",
"pages/training/training",
"pages/wzDetails/wzDetails",
"pages/spDetails/spDetails",
"pages/publishAdd/publishAdd"
],
"independent": true
}

41
pages/home/home.js

@ -7,8 +7,7 @@ Page({
baseUrl: baseUrl,
swiperList: [],
articleList:[
{title:'文章发布',describe:'快速发布养殖知识',icon:'/pages/images/fkjy.png'},
{title:'在线学习',describe:'视频培训发布',icon:'/pages/images/tx.png'}
{title:'发布信息',describe:'快速发布养殖知识|视频培训发布',icon:'/pages/images/fkjy.png'},
],
// 通知公告数据
currentNotice: 0,
@ -33,6 +32,15 @@ Page({
})
},
// 跳转发布信息
bindPx() {
wx.navigateTo({
url: '/pagesB/pages/training/training',
})
},
// 在线问答列表
getforumList() {
http.forumList({
@ -73,34 +81,7 @@ Page({
})
},
// 灾害/通知公告
getDisaster() {
http.disaster({
data: {},
success: res => {
// 处理通知数据,添加时间戳
const notices = res.rows.map(item => {
return {
...item,
// // 判断是否是24小时内的通知
// isNew: this.isNewNotification(item.createdTime)
}
})
this.setData({
noticeList: notices
})
}
})
},
// // 判断通知是否在24小时内
// isNewNotification(createdTime) {
// if (!createdTime) return false
// const noticeTime = new Date(createdTime.replace(/-/g, '/')).getTime()
// const now = new Date().getTime()
// const twentyFourHours = 24 * 60 * 60 * 1000
// return now - noticeTime < twentyFourHours
// },
// 区域划分跳转
bindXzqh() {
@ -200,7 +181,6 @@ Page({
},
onLoad() {
this.getDisaster()
this.getCarousel()
this.getLocation()
this.getforumList()
@ -276,7 +256,6 @@ Page({
// 重新加载所有数据
Promise.all([
new Promise(resolve => this.getUserInfo(resolve)),
new Promise(resolve => this.getDisaster(resolve)),
new Promise(resolve => this.getCarousel(resolve)),
new Promise(resolve => this.getforumList(resolve)),
new Promise(resolve => this.getexperience(resolve))

6
pages/home/home.wxml

@ -17,10 +17,6 @@
</view>
</view>
<!-- AI问诊 -->
<view class="Aidiagnosis" bind:tap="bindAI">
<image src="/pages/images/aiwz.png" mode="" />
</view>
<!-- 轮播图区域-->
<view class="swiper-container">
@ -71,7 +67,7 @@
<!-- 文章发布-视频培训 -->
<view class="article">
<view class="article1_1" wx:for="{{articleList}}">
<view class="article1_1" wx:for="{{articleList}}" data-value="{{item}}" bind:tap="bindPx">
<view class="article2">
<view>{{item.title}}</view>
<view>{{item.describe}}</view>

18
pages/home/home.wxss

@ -13,20 +13,6 @@
padding-bottom: 40rpx;
}
/* AI问诊 */
.Aidiagnosis {
position: fixed;
right: 0;
bottom: 150px;
margin: 0 auto;
z-index: 100;
}
.Aidiagnosis image {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
}
.orientation{
display: flex;
@ -267,7 +253,7 @@
display: flex;
align-items: center;
justify-content: space-between;
padding: 10rpx 30rpx;
padding: 20rpx 30rpx;
margin-top: 30rpx;
}
.article2 view:first-child{
@ -276,7 +262,7 @@
.article2 view:last-child{
color: #C5C6CC;
font-size: 24rpx;
margin-top: 10rpx;
margin-top: 20rpx;
}
.article3 image{
width: 100rpx;

BIN
pages/images/sjh.png

After

Width: 200  |  Height: 200  |  Size: 4.7 KiB

BIN
pagesA/images/jh.png

After

Width: 200  |  Height: 200  |  Size: 1.7 KiB

66
pagesA/pages/askingSy/askingSy.js

@ -1,66 +0,0 @@
// pagesA/pages/askingSy/askingSy.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})

3
pagesA/pages/askingSy/askingSy.json

@ -1,3 +0,0 @@
{
"usingComponents": {}
}

2
pagesA/pages/askingSy/askingSy.wxml

@ -1,2 +0,0 @@
<!--pagesA/pages/askingSy/askingSy.wxml-->
<text>pagesA/pages/askingSy/askingSy.wxml</text>

1
pagesA/pages/askingSy/askingSy.wxss

@ -1 +0,0 @@
/* pagesA/pages/askingSy/askingSy.wxss */

154
pagesA/pages/carouselDetail/carouselDetail.js

@ -0,0 +1,154 @@
import http from '../../../utils/api';
const baseUrl = require('../../../utils/baseUrl');
Page({
/**
* 页面的初始数据
*/
data: {
baseUrl: baseUrl,
detailInfo: {},
id: null,
cardAnimation: {} // 卡片动画数据
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
if (options.id) {
this.setData({ id: options.id });
this.getCarouselDetail(options.id);
this.initAnimation();
} else {
wx.showToast({
title: '参数错误',
icon: 'none'
});
}
},
/**
* 初始化卡片动画
*/
initAnimation() {
const animation = wx.createAnimation({
duration: 600,
timingFunction: 'ease-out',
delay: 100
});
animation.translateY(0).opacity(1).step();
this.setData({
cardAnimation: animation.export()
});
},
/**
* 获取轮播详情
*/
getCarouselDetail(id) {
wx.showLoading({ title: '加载中...', mask: true });
http.carouselDetail({
data: { id: id },
success: (res) => {
wx.hideLoading();
console.log('轮播详情:', res);
if (res && res.code === 200 && res.data) {
this.setData({
detailInfo: res.data
});
wx.setNavigationBarTitle({
title: res.data.title || '轮播详情'
});
} else {
wx.showToast({
title: res?.msg || '数据加载失败',
icon: 'none'
});
}
},
fail: (err) => {
wx.hideLoading();
console.error('请求失败:', err);
wx.showToast({
title: '网络错误',
icon: 'none'
});
}
});
},
/**
* 颜色调整函数用于渐变效果
*/
adjustColor(hex, percent) {
if (!hex) return '#4CAF50';
// 简单实现:如果传入颜色,返回稍浅的版本
// 这里为了简化,直接返回原色稍微变浅,实际项目中可使用颜色处理库
return hex;
},
/**
* 图片加载错误处理
*/
imageLoadError(e) {
console.warn('图片加载失败', e);
},
/**
* 返回上一页
*/
goBack() {
wx.navigateBack({
delta: 1
});
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {},
/**
* 生命周期函数--监听页面显示
*/
onShow() {},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
const { title, imageUrl } = this.data.detailInfo;
return {
title: title || '轮播详情',
imageUrl: this.data.baseUrl + (imageUrl || ''),
path: `/pages/carousel/detail/detail?id=${this.data.id}`
};
}
});

4
pagesA/pages/carouselDetail/carouselDetail.json

@ -0,0 +1,4 @@
{
"navigationBarTitleText":"轮播详情",
"usingComponents": {}
}

104
pagesA/pages/carouselDetail/carouselDetail.wxml

@ -0,0 +1,104 @@
<view class="carousel-detail-container" style="--bg-color: {{detailInfo.bgColor || '#F8F9FA'}};">
<!-- 沉浸式头部,带渐变遮罩和返回按钮 -->
<view class="hero-section">
<image
class="hero-image"
src="{{baseUrl + detailInfo.imageUrl}}"
mode="aspectFill"
binderror="imageLoadError"
></image>
<view class="hero-overlay" style="background: linear-gradient(to bottom, transparent 30%, {{detailInfo.bgColor || '#F8F9FA'}} 90%);"></view>
<!-- 返回按钮 -->
<view class="nav-back glass" bindtap="goBack">
<text class="iconfont icon-back">←</text>
</view>
<!-- 页面标题 - 仅在需要时显示 -->
<view class="page-title glass" wx:if="{{detailInfo.adsType}}">
<text>{{detailInfo.adsType}}</text>
</view>
</view>
<!-- 主要内容卡片 -->
<view class="content-card" animation="{{cardAnimation}}" style="--text-color: {{detailInfo.textColor || '#2E7D32'}};">
<!-- 标题区域 -->
<view class="title-section">
<text class="main-title" style="color: {{detailInfo.textColor || '#1A1A1A'}};">{{detailInfo.title || '无标题'}}</text>
<text class="sub-title">{{detailInfo.subtitle || '暂无副标题'}}</text>
</view>
<!-- 装饰分割线 -->
<view class="divider">
<view class="divider-line" style="background-color: {{detailInfo.textColor || '#2E7D32'}};"></view>
<view class="divider-dot" style="background-color: {{detailInfo.textColor || '#2E7D32'}};"></view>
<view class="divider-line" style="background-color: {{detailInfo.textColor || '#2E7D32'}};"></view>
</view>
<!-- 信息网格 -->
<view class="info-grid">
<!-- 尺寸信息卡片 -->
<view class="info-item" wx:if="{{detailInfo.imageSize}}">
<view class="info-icon">📐</view>
<view class="info-content">
<text class="info-label">图片尺寸</text>
<text class="info-value">{{detailInfo.imageSize}}</text>
</view>
</view>
<!-- 展示次数卡片 -->
<view class="info-item" wx:if="{{detailInfo.displayCount !== undefined}}">
<view class="info-icon">👁️</view>
<view class="info-content">
<text class="info-label">浏览次数</text>
<text class="info-value">{{detailInfo.viewCount}}</text>
</view>
</view>
<!-- 创建时间卡片 -->
<view class="info-item" wx:if="{{detailInfo.createdAt}}">
<view class="info-icon">📅</view>
<view class="info-content">
<text class="info-label">创建时间</text>
<text class="info-value">{{detailInfo.createdAt}}</text>
</view>
</view>
<!-- 更新时间卡片 -->
<view class="info-item" wx:if="{{detailInfo.updatedAt}}">
<view class="info-icon">🔄</view>
<view class="info-content">
<text class="info-label">更新时间</text>
<text class="info-value">{{detailInfo.updatedAt}}</text>
</view>
</view>
<!-- 有效性状态卡片 - 使用优雅的徽章设计 -->
<view class="info-item status-item" wx:if="{{detailInfo.isActive !== undefined}}">
<view class="info-icon">⚡</view>
<view class="info-content">
<text class="info-label">状态</text>
<view class="status-badge" style="background-color: {{detailInfo.isActive === 1 ? '#4CAF50' : '#9E9E9E'}}20; border-color: {{detailInfo.isActive === 1 ? '#4CAF50' : '#9E9E9E'}};">
<text class="status-dot" style="background-color: {{detailInfo.isActive === 1 ? '#4CAF50' : '#9E9E9E'}};"></text>
<text class="status-text" style="color: {{detailInfo.isActive === 1 ? '#4CAF50' : '#9E9E9E'}};">{{detailInfo.isActive === 1 ? '有效' : '无效'}}</text>
</view>
</view>
</view>
</view>
<!-- 描述/备注区域(如果有remark字段) -->
<view class="remark-section" wx:if="{{detailInfo.remark}}">
<view class="remark-icon">📝</view>
<view class="remark-content">{{detailInfo.remark}}</view>
</view>
<!-- 辅助信息:始终有效标识 -->
<view class="always-valid" wx:if="{{detailInfo.isAlwaysValid === 1}}">
<text class="valid-icon">✨</text>
<text class="valid-text">长期有效</text>
</view>
</view>
</view>

284
pagesA/pages/carouselDetail/carouselDetail.wxss

@ -0,0 +1,284 @@
.carousel-detail-container {
min-height: 100vh;
background-color: var(--bg-color, #F8F9FA);
position: relative;
padding-bottom: 40rpx;
}
/* 沉浸式头部 */
.hero-section {
position: relative;
width: 100%;
height: 600rpx;
overflow: hidden;
}
.hero-image {
width: 100%;
height: 100%;
filter: brightness(0.9);
transition: transform 0.3s ease;
}
.hero-image:active {
transform: scale(1.02);
}
.hero-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 200rpx;
pointer-events: none;
}
/* 毛玻璃返回按钮 */
.nav-back {
position: absolute;
top: 60rpx;
left: 30rpx;
width: 72rpx;
height: 72rpx;
border-radius: 36rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 40rpx;
color: #333;
z-index: 10;
}
.glass {
background: rgba(255, 255, 255, 0.25);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1rpx solid rgba(255, 255, 255, 0.3);
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.page-title {
position: absolute;
top: 60rpx;
right: 30rpx;
padding: 16rpx 32rpx;
border-radius: 40rpx;
font-size: 26rpx;
color: #333;
font-weight: 500;
z-index: 10;
letter-spacing: 1rpx;
}
/* 主要内容卡片 */
.content-card {
margin: -100rpx 30rpx 0;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 48rpx;
padding: 48rpx 32rpx;
box-shadow: 0 30rpx 60rpx rgba(0, 0, 0, 0.1),
0 10rpx 30rpx rgba(0, 0, 0, 0.05);
position: relative;
z-index: 5;
border: 1rpx solid rgba(255, 255, 255, 0.5);
opacity: 0;
transform: translateY(50rpx);
animation: cardFloat 0.6s ease-out forwards;
}
@keyframes cardFloat {
to {
opacity: 1;
transform: translateY(0);
}
}
/* 标题区域 */
.title-section {
margin-bottom: 40rpx;
}
.main-title {
display: block;
font-size: 56rpx;
font-weight: 700;
line-height: 1.3;
margin-bottom: 16rpx;
letter-spacing: -0.5rpx;
}
.sub-title {
display: block;
font-size: 30rpx;
color: #666;
line-height: 1.5;
font-weight: 400;
opacity: 0.8;
}
/* 装饰分割线 */
.divider {
display: flex;
align-items: center;
margin: 30rpx 0 40rpx;
}
.divider-line {
flex: 1;
height: 2rpx;
opacity: 0.2;
}
.divider-dot {
width: 8rpx;
height: 8rpx;
border-radius: 4rpx;
margin: 0 20rpx;
opacity: 0.5;
}
/* 信息网格 */
.info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 24rpx;
margin-bottom: 40rpx;
}
.info-item {
background: rgba(0, 0, 0, 0.02);
border-radius: 28rpx;
padding: 28rpx 20rpx;
display: flex;
align-items: center;
border: 1rpx solid rgba(0, 0, 0, 0.03);
transition: all 0.3s ease;
}
.info-item:active {
transform: scale(0.98);
background: rgba(0, 0, 0, 0.04);
}
.info-icon {
font-size: 48rpx;
margin-right: 20rpx;
filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.1));
}
.info-content {
flex: 1;
display: flex;
flex-direction: column;
}
.info-label {
font-size: 22rpx;
color: #999;
margin-bottom: 8rpx;
letter-spacing: 0.5rpx;
}
.info-value {
font-size: 28rpx;
font-weight: 600;
color: #333;
word-break: break-all;
}
/* 状态特殊样式 */
.status-item .info-content {
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.status-badge {
display: flex;
align-items: center;
padding: 8rpx 16rpx;
border-radius: 40rpx;
border-width: 1rpx;
border-style: solid;
background-color: rgba(76, 175, 80, 0.1);
}
.status-dot {
width: 16rpx;
height: 16rpx;
border-radius: 8rpx;
margin-right: 8rpx;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.6; }
}
.status-text {
font-size: 24rpx;
font-weight: 500;
}
/* 备注区域 */
.remark-section {
background: rgba(0, 0, 0, 0.02);
border-radius: 28rpx;
padding: 28rpx;
margin-bottom: 40rpx;
display: flex;
border-left: 8rpx solid var(--text-color, #2E7D32);
}
.remark-icon {
font-size: 40rpx;
margin-right: 20rpx;
}
.remark-content {
flex: 1;
font-size: 28rpx;
color: #444;
line-height: 1.6;
}
/* 始终有效标识 */
.always-valid {
display: flex;
align-items: center;
justify-content: center;
margin-top: 30rpx;
padding: 20rpx;
background: linear-gradient(135deg, rgba(255, 215, 0, 0.1), rgba(255, 215, 0, 0.05));
border-radius: 40rpx;
border: 1rpx solid rgba(255, 215, 0, 0.3);
}
.valid-icon {
font-size: 32rpx;
margin-right: 12rpx;
animation: starTwinkle 1.5s infinite;
}
@keyframes starTwinkle {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.1); }
}
.valid-text {
font-size: 26rpx;
color: #B8860B;
font-weight: 500;
}
/* 响应式调整 */
@media (min-width: 768px) {
.content-card {
max-width: 700rpx;
margin: -100rpx auto 0;
}
}

BIN
pagesB/images/bo.png

After

Width: 200  |  Height: 200  |  Size: 2.5 KiB

BIN
pagesB/images/hf.png

After

Width: 200  |  Height: 200  |  Size: 3.8 KiB

BIN
pagesB/images/lll.png

After

Width: 200  |  Height: 200  |  Size: 3.6 KiB

BIN
pagesB/images/sou.png

After

Width: 200  |  Height: 200  |  Size: 4.5 KiB

286
pagesB/pages/administrativeDivision/administrativeDivision.js

@ -0,0 +1,286 @@
import http from '../../../utils/api'
Page({
/**
* 页面的初始数据
*/
data: {
regionList: [], // 当前显示的区域列表
selectedRegions: [], // 已选择的区域路径
currentParentCode: '', // 当前父级code
loading: false,
showPicker: false,
regionTitle: '请选择区域',
autoShowPicker: false // 新增:控制是否自动弹出选择器
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
// 首次加载,获取第一级数据
this.getRegionData('', () => {
// 首次加载完成后自动弹出选择器
this.setData({
showPicker: true,
regionTitle: '请选择区域'
})
})
},
// 获取区域数据
getRegionData(parentCode, callback) {
this.setData({
loading: true
})
http.areaChildren({
data: {
parentCode: parentCode || ''
},
success: res => {
console.log('区域数据响应:', res)
if (res.code === 200 && res.data && res.data.length > 0) {
this.setData({
regionList: res.data,
currentParentCode: parentCode,
loading: false
})
} else {
// 没有更多数据了,说明已经是最后一级
this.setData({
loading: false,
regionList: []
})
// 如果是最后一级,关闭选择器
if (this.data.showPicker) {
this.setData({
showPicker: false
})
wx.showToast({
title: '已选择到最后一级',
icon: 'none'
})
}
}
// 执行回调
if (callback) {
callback()
}
},
fail: err => {
console.error('请求失败:', err)
this.setData({
loading: false
})
wx.showToast({
title: '加载失败',
icon: 'none'
})
if (callback) {
callback()
}
}
})
},
// 开始选择(点击按钮时调用)
startSelection() {
// 如果还没有选择任何区域,重新加载第一级
if (this.data.selectedRegions.length === 0) {
this.getRegionData('', () => {
this.setData({
showPicker: true,
regionTitle: '请选择区域'
})
})
} else {
// 如果有已选择的区域,加载下一级
const lastRegion = this.data.selectedRegions[this.data.selectedRegions.length - 1]
this.loadAndShowNextLevel(lastRegion.code)
}
},
// 加载并显示下一级区域选择器
loadAndShowNextLevel(parentCode) {
this.getRegionData(parentCode, () => {
if (this.data.regionList.length > 0) {
// 有下一级数据,自动弹出选择器
this.setData({
showPicker: true,
regionTitle: `请选择${this.data.selectedRegions[this.data.selectedRegions.length - 1].name}的下一级区域`
})
} else {
// 没有下一级数据,提示用户
wx.showToast({
title: '已经是最后一级,无法继续选择',
icon: 'none'
})
}
})
},
// 关闭选择器
closePicker() {
this.setData({
showPicker: false
})
},
// 选择区域
selectRegion(e) {
const index = e.currentTarget.dataset.index
const region = this.data.regionList[index]
console.log('选择的区域:', region)
// 获取当前已选择的最后一级
const lastSelectedRegion = this.data.selectedRegions.length > 0 ?
this.data.selectedRegions[this.data.selectedRegions.length - 1] :
null
// 检查是否是同级选择(替换最后一级)
const isSameLevel = lastSelectedRegion &&
lastSelectedRegion.parentCode === region.parentCode
let selectedRegions = [...this.data.selectedRegions]
if (isSameLevel) {
// 同级选择,替换最后一级
selectedRegions[selectedRegions.length - 1] = {
code: region.code,
name: region.name,
parentCode: region.parentCode
}
} else {
// 选择下一级,添加到路径
selectedRegions.push({
code: region.code,
name: region.name,
parentCode: region.parentCode
})
}
this.setData({
selectedRegions
})
// 关闭当前选择器
this.setData({
showPicker: false
})
// 延迟一段时间后自动加载并显示下一级选择器
setTimeout(() => {
this.loadAndShowNextLevel(region.code)
}, 300)
},
// 重新选择(点击已选择的任意层级)
reSelectRegion(e) {
const index = e.currentTarget.dataset.index
// 截断到指定级别(包括点击的层级)
const selectedRegions = this.data.selectedRegions.slice(0, index + 1)
this.setData({
selectedRegions
})
// 获取该层级的数据
const targetRegion = selectedRegions[selectedRegions.length - 1]
// 获取点击层级的同级数据并显示选择器
this.getRegionData(targetRegion.parentCode, () => {
this.setData({
showPicker: true,
regionTitle: index === 0 ?
'请选择区域' :
`请选择${this.data.selectedRegions[index - 1]?.name || '区域'}的下一级`
})
})
},
// 完成选择
completeSelection() {
if (this.data.selectedRegions.length === 0) {
wx.showToast({
title: '请先选择区域',
icon: 'none'
})
return
}
const lastRegion = this.data.selectedRegions[this.data.selectedRegions.length - 1]
// 这里可以调用你的业务接口,传递parentCode
this.submitRegion(lastRegion.code)
},
// 提交选择的区域(示例)
submitRegion(parentCode) {
console.log('提交的parentCode:', parentCode)
console.log('完整选择路径:', this.data.selectedRegions)
http.userCode({
data: {
areaCode: parentCode
},
success: res => {
console.log(11111, res);
if (res.code == 200) {
wx.showModal({
title: '选择完成',
content: `已选择到: ${this.data.selectedRegions.map(r => r.name).join(' > ')}`,
showCancel: false,
success: (res) => {
if (res.confirm) {
wx.switchTab({
url: '/pages/home/home',
})
}
}
})
}
}
})
},
// 重置选择
resetSelection() {
wx.showModal({
title: '确认重置',
content: '确定要重置所有选择吗?',
success: (res) => {
if (res.confirm) {
this.setData({
selectedRegions: [],
regionList: [],
currentParentCode: '',
showPicker: false
})
// 重新获取第一级数据
this.getRegionData('', () => {
// 重置后自动弹出第一级选择器
this.setData({
showPicker: true,
regionTitle: '请选择区域'
})
})
}
}
})
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
}
})

4
pagesB/pages/administrativeDivision/administrativeDivision.json

@ -0,0 +1,4 @@
{
"navigationBarTitleText":"区域选择",
"usingComponents": {}
}

95
pagesB/pages/administrativeDivision/administrativeDivision.wxml

@ -0,0 +1,95 @@
<view class="container">
<!-- 已选择区域路径显示 -->
<view class="selected-path" wx:if="{{selectedRegions.length > 0}}">
<text class="path-title">已选择:</text>
<view class="path-items">
<view
wx:for="{{selectedRegions}}"
wx:key="index"
class="path-item {{index === selectedRegions.length - 1 ? 'last' : ''}}"
data-index="{{index}}"
bindtap="reSelectRegion"
>
<text>{{item.name}}</text>
<text class="separator" wx:if="{{index < selectedRegions.length - 1}}">></text>
</view>
</view>
</view>
<!-- 选择按钮 -->
<view class="select-btn-container">
<button
class="select-btn"
bindtap="startSelection"
loading="{{loading}}"
>
{{selectedRegions.length === 0 ? '开始选择区域' : '继续选择下一级'}}
</button>
</view>
<!-- 操作按钮 -->
<view class="action-buttons">
<button
class="btn complete-btn"
bindtap="completeSelection"
disabled="{{selectedRegions.length === 0}}"
>
完成选择
</button>
<button
class="btn reset-btn"
bindtap="resetSelection"
wx:if="{{selectedRegions.length > 0}}"
>
重置
</button>
</view>
<!-- 选择器弹出层 -->
<view class="picker-modal" wx:if="{{showPicker}}">
<view class="picker-mask" bindtap="closePicker"></view>
<view class="picker-content">
<view class="picker-header">
<text class="picker-title">{{regionTitle}}</text>
<text class="picker-close" bindtap="closePicker">×</text>
</view>
<view class="picker-body">
<!-- 加载状态 -->
<view class="loading-container" wx:if="{{loading}}">
<view class="loading-spinner"></view>
<text class="loading-text">加载中...</text>
</view>
<!-- 区域列表 -->
<scroll-view scroll-y class="region-list" wx:else>
<view
wx:for="{{regionList}}"
wx:key="id"
class="region-item"
data-index="{{index}}"
bindtap="selectRegion"
>
<view class="region-info">
<text class="region-name">{{item.name}}</text>
</view>
<text class="arrow">›</text>
</view>
<!-- 空状态 -->
<view class="empty-state" wx:if="{{regionList.length === 0}}">
<text class="empty-text">
{{selectedRegions.length > 0 ? '已选择到最后一级' : '暂无区域数据'}}
</text>
</view>
</scroll-view>
</view>
</view>
</view>
<!-- 使用说明 -->
<view class="instruction">
<text class="instruction-title">使用说明:</text>
<text class="instruction-text">1. 点击"开始选择区域"开始选择\n2. 选择后会加载下一级区域\n3. 点击已选择区域的任意级别可以重新选择\n4. 选择最后一级时会直接替换\n5. 完成选择后点击"完成选择"按钮</text>
</view>
</view>

316
pagesB/pages/administrativeDivision/administrativeDivision.wxss

@ -0,0 +1,316 @@
.container {
padding: 30rpx;
min-height: 100vh;
background: #f5f5f5;
}
/* 已选择路径 */
.selected-path {
background: white;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
}
.path-title {
font-size: 28rpx;
color: #666;
display: block;
margin-bottom: 20rpx;
}
.path-items {
display: flex;
flex-wrap: wrap;
align-items: center;
margin-bottom: 20rpx;
}
.path-item {
display: flex;
align-items: center;
padding: 12rpx 20rpx;
background: #f0f8ff;
border-radius: 8rpx;
margin-right: 10rpx;
margin-bottom: 10rpx;
cursor: pointer;
}
.path-item:active {
background: #e1f0ff;
}
.path-item.last {
background: #e6f7ff;
border: 1rpx solid #1890ff;
}
.path-item text:first-child {
font-size: 28rpx;
color: #1890ff;
font-weight: 500;
}
.separator {
margin-left: 10rpx;
color: #999;
}
/* 选择按钮 */
.select-btn-container {
margin: 40rpx 0;
}
.select-btn {
width: 100%;
background: linear-gradient(135deg, #1890ff, #096dd9);
color: white;
border-radius: 12rpx;
font-size: 32rpx;
height: 88rpx;
line-height: 88rpx;
border: none;
}
.select-btn::after {
border: none;
}
.select-btn[loading] {
opacity: 0.8;
}
.select-btn:active {
opacity: 0.9;
}
/* 操作按钮 */
.action-buttons {
display: flex;
gap: 20rpx;
margin-top: 50rpx;
}
.btn {
flex: 1;
border-radius: 12rpx;
font-size: 28rpx;
height: 80rpx;
line-height: 80rpx;
border: none;
}
.btn::after {
border: none;
}
.complete-btn {
background: #07c160;
color: white;
}
.complete-btn[disabled] {
background: #ccc;
color: #999;
}
.complete-btn:active:not([disabled]) {
background: #06ad56;
}
.reset-btn {
background: #fff;
color: #ff4d4f;
border: 1rpx solid #ff4d4f !important;
}
.reset-btn:active {
background: #fff5f5;
}
/* 选择器模态框 */
.picker-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
}
.picker-mask {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
animation: fadeIn 0.3s ease;
}
.picker-content {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: white;
border-radius: 32rpx 32rpx 0 0;
max-height: 70vh;
display: flex;
flex-direction: column;
animation: slideUp 0.3s ease;
}
.picker-header {
padding: 32rpx 40rpx;
border-bottom: 1rpx solid #f0f0f0;
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
}
.picker-title {
font-size: 32rpx;
color: #333;
font-weight: 600;
flex: 1;
text-align: center;
}
.picker-close {
font-size: 48rpx;
color: #999;
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
width: 60rpx;
height: 60rpx;
text-align: center;
line-height: 60rpx;
}
.picker-close:active {
background: #f5f5f5;
border-radius: 50%;
}
.picker-body {
flex: 1;
overflow: hidden;
}
/* 加载状态 */
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300rpx;
}
.loading-spinner {
width: 60rpx;
height: 60rpx;
border: 4rpx solid #f0f0f0;
border-top-color: #1890ff;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20rpx;
}
.loading-text {
font-size: 28rpx;
color: #999;
}
/* 区域列表 */
.region-list {
height: 60vh;
}
.region-item {
padding: 32rpx 40rpx;
border-bottom: 1rpx solid #f0f0f0;
display: flex;
align-items: center;
justify-content: space-between;
}
.region-item:active {
background: #f5f5f5;
}
.region-info {
flex: 1;
}
.region-name {
font-size: 30rpx;
color: #333;
display: block;
margin-bottom: 8rpx;
}
.arrow {
color: #ccc;
font-size: 36rpx;
margin-left: 20rpx;
}
/* 空状态 */
.empty-state {
display: flex;
justify-content: center;
align-items: center;
height: 200rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
/* 使用说明 */
.instruction {
margin-top: 60rpx;
padding: 24rpx;
background: white;
border-radius: 12rpx;
border-left: 6rpx solid #1890ff;
}
.instruction-title {
font-size: 28rpx;
color: #1890ff;
font-weight: 600;
display: block;
margin-bottom: 16rpx;
}
.instruction-text {
font-size: 26rpx;
color: #666;
line-height: 1.6;
white-space: pre-line;
}
/* 动画 */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideUp {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}

580
pagesB/pages/publishAdd/publishAdd.js

@ -0,0 +1,580 @@
import http from '../../../utils/api'
const baseUrl = require('../../../utils/baseUrl')
Page({
data: {
baseUrl,
currentTab: 'article',
// 文章相关
articleForm: {
title: '',
subtitle: '',
category: '',
content: '',
coverImage: '' // 这里存储服务器返回的文件名
},
articleCoverTemp: '', // 本地临时路径,用于预览
articleCategory: null,
articleCategories: [],
// 视频相关
videoForm: {
title: '',
description: '',
category: '',
videoUrl: '', // 这里存储服务器返回的视频文件名
coverImage: '' // 这里存储服务器返回的封面文件名
},
videoCoverTemp: '', // 本地临时路径,用于预览
videoUrlTemp: '', // 本地临时路径,用于显示
videoCategory: null,
videoCategories: [],
// UI状态
submitting: false,
isUploading: false, // 防止重复上传
showLoadingMask: false, // 显示加载遮罩层
loadingText: '发布中...', // 加载提示文字
// 表单验证状态
articleFormValid: false,
videoFormValid: false,
},
onLoad() {
this.getArticleCategories()
this.getVideoCategories()
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
// 页面卸载时重置状态
this.setData({
submitting: false,
showLoadingMask: false
});
},
// 获取文章分类
getArticleCategories() {
http.articleZd({
data: {
dictType: 'article_category'
},
success: res => {
if (res.rows) {
this.setData({
articleCategories: res.rows
})
}
}
})
},
// 获取视频分类
getVideoCategories() {
http.videoZd({
data: {
dictType: 'video_category'
},
success: res => {
if (res.rows) {
this.setData({
videoCategories: res.rows
})
}
}
})
},
// 切换标签
switchTab(e) {
const type = e.currentTarget.dataset.type
if (type === this.data.currentTab) return
this.setData({ currentTab: type })
},
// 验证文章表单
validateArticleForm() {
const { articleForm } = this.data
const isValid = !!(articleForm.title?.trim() && articleForm.category && articleForm.content?.trim())
this.setData({ articleFormValid: isValid })
return isValid
},
// 验证视频表单
validateVideoForm() {
const { videoForm } = this.data
const isValid = !!(videoForm.title?.trim() && videoForm.category && videoForm.videoUrl)
this.setData({ videoFormValid: isValid })
return isValid
},
// 文章输入处理
onArticleInput(e) {
const field = e.currentTarget.dataset.field
const value = e.detail.value
this.setData({
[`articleForm.${field}`]: value
}, () => {
this.validateArticleForm()
})
},
// 视频输入处理
onVideoInput(e) {
const field = e.currentTarget.dataset.field
const value = e.detail.value
this.setData({
[`videoForm.${field}`]: value
}, () => {
this.validateVideoForm()
})
},
// 文章分类选择
onArticleCategoryChange(e) {
const index = e.detail.value
const category = this.data.articleCategories[index]
this.setData({
'articleForm.category': category.dictValue,
articleCategory: category
}, () => {
this.validateArticleForm()
})
},
// 视频分类选择
onVideoCategoryChange(e) {
const index = e.detail.value
const category = this.data.videoCategories[index]
this.setData({
'videoForm.category': category.dictValue,
videoCategory: category
}, () => {
this.validateVideoForm()
})
},
// 选择封面图片(文章或视频)
chooseCover(e) {
if (this.data.isUploading) {
wx.showToast({
title: '正在上传中,请稍候',
icon: 'none'
});
return;
}
const type = e.currentTarget.dataset.type
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album', 'camera'],
sizeType: ['compressed'],
success: (res) => {
if (res.tempFiles && res.tempFiles.length > 0) {
this.setData({
isUploading: true
});
// 显示加载提示
wx.showLoading({
title: '上传图片中...',
mask: true
});
// 上传图片
this.uploadImage(res.tempFiles[0].tempFilePath, type);
}
}
});
},
// 上传单张图片
uploadImage(tempPath, type) {
wx.uploadFile({
url: baseUrl + '/common/upload',
header: {
'Authorization': 'Bearer ' + wx.getStorageSync('token')
},
filePath: tempPath,
name: 'file',
success: (uploadRes) => {
try {
const result = JSON.parse(uploadRes.data);
if (result.code === 200 || result.fileName) {
const serverPath = result.fileName || result.url;
if (type === 'article') {
// 文章封面
this.setData({
articleCoverTemp: tempPath,
'articleForm.coverImage': serverPath,
isUploading: false
});
} else {
// 视频封面
this.setData({
videoCoverTemp: tempPath,
'videoForm.coverImage': serverPath,
isUploading: false
}, () => {
this.validateVideoForm();
});
}
wx.hideLoading();
wx.showToast({
title: '上传成功',
icon: 'success'
});
} else {
throw new Error(result.msg || '上传失败');
}
} catch (error) {
wx.hideLoading();
this.setData({
isUploading: false
});
wx.showToast({
title: error.message || '上传失败',
icon: 'none'
});
}
},
fail: (error) => {
wx.hideLoading();
this.setData({
isUploading: false
});
wx.showToast({
title: '网络请求失败',
icon: 'none'
});
}
});
},
// 选择视频
chooseVideo() {
if (this.data.isUploading) {
wx.showToast({
title: '正在上传中,请稍候',
icon: 'none'
});
return;
}
wx.chooseMedia({
count: 1,
mediaType: ['video'],
sourceType: ['album', 'camera'],
maxDuration: 300,
success: (res) => {
if (res.tempFiles && res.tempFiles.length > 0) {
this.setData({
isUploading: true,
videoUrlTemp: res.tempFiles[0].tempFilePath // 先显示本地路径
});
// 显示加载提示
wx.showLoading({
title: '上传视频中...',
mask: true
});
// 上传视频
this.uploadVideo(res.tempFiles[0].tempFilePath);
}
}
});
},
// 上传视频
uploadVideo(tempPath) {
wx.uploadFile({
url: baseUrl + '/common/upload',
header: {
'Authorization': 'Bearer ' + wx.getStorageSync('token')
},
filePath: tempPath,
name: 'file',
success: (uploadRes) => {
try {
const result = JSON.parse(uploadRes.data);
if (result.code === 200 || result.fileName) {
const serverPath = result.fileName || result.url;
this.setData({
'videoForm.videoUrl': serverPath,
isUploading: false
}, () => {
this.validateVideoForm();
});
wx.hideLoading();
wx.showToast({
title: '上传成功',
icon: 'success'
});
} else {
throw new Error(result.msg || '上传失败');
}
} catch (error) {
wx.hideLoading();
this.setData({
videoUrlTemp: '', // 上传失败清空临时路径
isUploading: false
});
wx.showToast({
title: error.message || '上传失败',
icon: 'none'
});
}
},
fail: (error) => {
wx.hideLoading();
this.setData({
videoUrlTemp: '', // 上传失败清空临时路径
isUploading: false
});
wx.showToast({
title: '网络请求失败',
icon: 'none'
});
}
});
},
// 提交文章
submitArticle() {
const { articleForm, submitting, isUploading } = this.data
if (submitting) return
// 检查是否还有图片正在上传
if (isUploading) {
wx.showToast({
title: '图片正在上传中,请稍后提交',
icon: 'none'
});
return;
}
// 表单验证
if (!this.validateArticleForm()) {
if (!articleForm.title?.trim()) {
this.showError('请输入文章标题')
} else if (!articleForm.category) {
this.showError('请选择文章分类')
} else if (!articleForm.content?.trim()) {
this.showError('请输入文章内容')
}
return
}
// 显示加载遮罩层
this.setData({
submitting: true,
showLoadingMask: true,
loadingText: '发布中...'
});
// 构建提交数据
const submitData = {
title: articleForm.title.trim(),
subtitle: articleForm.subtitle?.trim() || '',
content: articleForm.content.trim(),
coverImage: articleForm.coverImage || '',
category: articleForm.category
}
// 调用接口
http.articleAdd({
data: submitData,
success: (res) => {
if (res.code == 200) {
this.setData({
loadingText: '发布成功'
});
setTimeout(() => {
this.setData({
submitting: false,
showLoadingMask: false
});
wx.showToast({
title: '发布成功',
icon: 'success',
duration: 1500,
success: () => {
setTimeout(() => {
wx.navigateBack()
}, 1500);
}
});
}, 1000);
} else {
this.setData({
loadingText: '发布失败'
});
setTimeout(() => {
this.setData({
submitting: false,
showLoadingMask: false
});
wx.showToast({
title: res.msg || '发布失败,请重试',
icon: 'none',
duration: 2000
});
}, 1000);
}
},
fail: (err) => {
this.setData({
loadingText: '网络错误'
});
setTimeout(() => {
this.setData({
submitting: false,
showLoadingMask: false
});
wx.showToast({
title: '网络异常,请检查网络后重试',
icon: 'none',
duration: 2000
});
}, 1000);
}
})
},
// 提交视频
submitVideo() {
const { videoForm, submitting, isUploading } = this.data
if (submitting) return
// 检查是否还有图片或视频正在上传
if (isUploading) {
wx.showToast({
title: '文件正在上传中,请稍后提交',
icon: 'none'
});
return;
}
// 表单验证
if (!this.validateVideoForm()) {
if (!videoForm.title?.trim()) {
this.showError('请输入视频标题')
} else if (!videoForm.category) {
this.showError('请选择视频分类')
} else if (!videoForm.videoUrl) {
this.showError('请选择视频')
}
return
}
// 显示加载遮罩层
this.setData({
submitting: true,
showLoadingMask: true,
loadingText: '发布中...'
});
// 构建提交数据
const submitData = {
title: videoForm.title.trim(),
description: videoForm.description?.trim() || '',
videoUrl: videoForm.videoUrl,
coverImage: videoForm.coverImage || '',
category: videoForm.category
}
// 调用接口
http.videoAdd({
data: submitData,
success: (res) => {
if (res.code == 200) {
this.setData({
loadingText: '发布成功'
});
setTimeout(() => {
this.setData({
submitting: false,
showLoadingMask: false
});
wx.showToast({
title: '发布成功',
icon: 'success',
duration: 1500,
success: () => {
setTimeout(() => {
wx.navigateBack()
}, 1500);
}
});
}, 1000);
} else {
this.setData({
loadingText: '发布失败'
});
setTimeout(() => {
this.setData({
submitting: false,
showLoadingMask: false
});
wx.showToast({
title: res.msg || '发布失败,请重试',
icon: 'none',
duration: 2000
});
}, 1000);
}
},
fail: (err) => {
this.setData({
loadingText: '网络错误'
});
setTimeout(() => {
this.setData({
submitting: false,
showLoadingMask: false
});
wx.showToast({
title: '网络异常,请检查网络后重试',
icon: 'none',
duration: 2000
});
}, 1000);
}
})
},
// 显示错误提示
showError(msg) {
wx.showToast({
title: msg,
icon: 'none',
duration: 2000
});
}
})

4
pagesB/pages/publishAdd/publishAdd.json

@ -0,0 +1,4 @@
{
"navigationBarTitleText":"发布",
"usingComponents": {}
}

205
pagesB/pages/publishAdd/publishAdd.wxml

@ -0,0 +1,205 @@
<view class="container">
<!-- 顶部背景装饰 -->
<view class="bg-decoration">
<view class="circle circle-1"></view>
<view class="circle circle-2"></view>
</view>
<!-- 分类切换卡片 -->
<view class="tab-card">
<view class="category-tab">
<view class="tab-item {{currentTab === 'article' ? 'active' : ''}}" data-type="article" bindtap="switchTab">
<text class="tab-text">发布文章</text>
</view>
<view class="tab-item {{currentTab === 'video' ? 'active' : ''}}" data-type="video" bindtap="switchTab">
<text class="tab-text">发布视频</text>
</view>
</view>
</view>
<!-- 文章发布表单 -->
<form wx:if="{{currentTab === 'article'}}" catchsubmit="submitArticle">
<view class="form-container">
<!-- 文章标题 -->
<view class="form-card">
<view class="form-item">
<view class="label-wrapper">
<text class="label">文章标题</text>
<text class="required">*</text>
</view>
<input class="input" type="text" placeholder="请输入文章标题" placeholder-class="placeholder" bindinput="onArticleInput" data-field="title" value="{{articleForm.title}}" />
</view>
</view>
<!-- 副标题 -->
<view class="form-card">
<view class="form-item">
<view class="label-wrapper">
<text class="label">副标题</text>
<text class="optional">选填</text>
</view>
<input class="input" type="text" placeholder="请输入副标题" placeholder-class="placeholder" bindinput="onArticleInput" data-field="subtitle" value="{{articleForm.subtitle}}" />
</view>
</view>
<!-- 文章分类 - 新样式 -->
<view class="form-card">
<view class="form-item">
<view class="label-wrapper">
<text class="label">文章分类</text>
<text class="required">*</text>
</view>
<picker mode="selector" range="{{articleCategories}}" range-key="dictLabel" bindchange="onArticleCategoryChange" data-type="article">
<view class="category-selector">
<block wx:if="{{articleCategory}}">
<view class="category-badge" style="background: linear-gradient(135deg, {{getCategoryColor(articleCategory.dictLabel).start}} 0%, {{getCategoryColor(articleCategory.dictLabel).end}} 100%);">
{{articleCategory.dictLabel}}
</view>
</block>
<view wx:else class="category-placeholder">
<text>请选择文章分类</text>
<text class="arrow">›</text>
</view>
</view>
</picker>
</view>
</view>
<!-- 文章封面 -->
<view class="form-card">
<view class="form-item">
<view class="label-wrapper">
<text class="label">封面图片</text>
<text class="optional">选填</text>
</view>
<view class="uploader-wrapper">
<view class="uploader" bindtap="chooseCover" data-type="article">
<image class="preview" src="{{articleCoverTemp || ''}}" mode="aspectFill" wx:if="{{articleCoverTemp}}"></image>
<view class="upload-placeholder" wx:else>
<text class="plus">+</text>
<text class="hint">点击上传封面</text>
</view>
</view>
<text class="upload-tip">建议尺寸 16:9,不超过5M</text>
</view>
</view>
</view>
<!-- 文章内容 -->
<view class="form-card">
<view class="form-item">
<view class="label-wrapper">
<text class="label">文章内容</text>
<text class="required">*</text>
</view>
<textarea class="textarea" placeholder="写下你的精彩内容吧..." placeholder-class="placeholder" bindinput="onArticleInput" data-field="content" value="{{articleForm.content}}" auto-height maxlength="5000" />
<text class="word-count">{{articleForm.content.length || 0}}/5000</text>
</view>
</view>
<!-- 提交按钮 -->
<view class="btn-wrapper">
<button class="submit-btn {{!articleFormValid ? 'disabled' : ''}}" form-type="submit" disabled="{{!articleFormValid || submitting}}">
<text wx:if="{{!submitting}}">发布文章</text>
<text wx:else>发布中...</text>
</button>
</view>
</view>
</form>
<!-- 视频发布表单 -->
<form wx:else catchsubmit="submitVideo">
<view class="form-container">
<!-- 视频标题 -->
<view class="form-card">
<view class="form-item">
<view class="label-wrapper">
<text class="label">视频标题</text>
<text class="required">*</text>
</view>
<input class="input" type="text" placeholder="请输入视频标题" placeholder-class="placeholder" bindinput="onVideoInput" data-field="title" value="{{videoForm.title}}" />
</view>
</view>
<!-- 视频描述 -->
<view class="form-card">
<view class="form-item">
<view class="label-wrapper">
<text class="label">视频描述</text>
<text class="optional">选填</text>
</view>
<input class="input" type="text" placeholder="简单描述一下你的视频内容" placeholder-class="placeholder" bindinput="onVideoInput" data-field="description" value="{{videoForm.description}}" />
</view>
</view>
<!-- 视频分类 - 新样式 -->
<view class="form-card">
<view class="form-item">
<view class="label-wrapper">
<text class="label">视频分类</text>
<text class="required">*</text>
</view>
<picker mode="selector" range="{{videoCategories}}" range-key="dictLabel" bindchange="onVideoCategoryChange" data-type="video">
<view class="category-selector">
<block wx:if="{{videoCategory}}">
<view class="category-badge" style="background: linear-gradient(135deg, {{getCategoryColor(videoCategory.dictLabel).start}} 0%, {{getCategoryColor(videoCategory.dictLabel).end}} 100%);">
{{videoCategory.dictLabel}}
</view>
</block>
<view wx:else class="category-placeholder">
<text>请选择视频分类</text>
<text class="arrow">›</text>
</view>
</view>
</picker>
</view>
</view>
<!-- 视频封面 -->
<view class="form-card">
<view class="form-item">
<view class="label-wrapper">
<text class="label">视频封面</text>
<text class="optional">选填</text>
</view>
<view class="uploader-wrapper">
<view class="uploader" bindtap="chooseCover" data-type="video">
<image class="preview" src="{{videoCoverTemp || ''}}" mode="aspectFill" wx:if="{{videoCoverTemp}}"></image>
<view class="upload-placeholder" wx:else>
<text class="plus">+</text>
<text class="hint">点击上传封面</text>
</view>
</view>
</view>
</view>
</view>
<!-- 视频地址 -->
<view class="form-card">
<view class="form-item">
<view class="label-wrapper">
<text class="label">视频地址</text>
<text class="required">*</text>
</view>
<view class="video-picker" bindtap="chooseVideo">
<view wx:if="{{videoUrlTemp}}" class="video-info">
<text class="video-name">{{videoUrlTemp}}</text>
</view>
<view wx:else class="video-placeholder">
<text class="plus">+</text>
<text class="hint">点击选择视频</text>
</view>
</view>
</view>
</view>
<!-- 提交按钮 -->
<view class="btn-wrapper">
<button class="submit-btn {{!videoFormValid ? 'disabled' : ''}}" form-type="submit" disabled="{{!videoFormValid || submitting}}">
<text wx:if="{{!submitting}}">发布视频</text>
<text wx:else>发布中...</text>
</button>
</view>
</view>
</form>
</view>

457
pagesB/pages/publishAdd/publishAdd.wxss

@ -0,0 +1,457 @@
.container {
min-height: 100vh;
background: linear-gradient(145deg, #f8f9ff 0%, #f0f2f6 100%);
position: relative;
}
/* 背景装饰 */
.bg-decoration {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
z-index: 0;
}
.circle {
position: absolute;
border-radius: 50%;
background: linear-gradient(135deg, rgba(7, 193, 96, 0.1) 0%, rgba(7, 193, 96, 0.05) 100%);
}
.circle-1 {
width: 400rpx;
height: 400rpx;
top: -100rpx;
right: -100rpx;
background: linear-gradient(135deg, rgba(64, 169, 255, 0.1) 0%, rgba(64, 169, 255, 0.05) 100%);
}
.circle-2 {
width: 300rpx;
height: 300rpx;
bottom: 100rpx;
left: -100rpx;
background: linear-gradient(135deg, rgba(255, 184, 0, 0.1) 0%, rgba(255, 184, 0, 0.05) 100%);
}
/* 切换卡片 */
.tab-card {
margin: 30rpx 30rpx 20rpx;
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(20px);
border-radius: 60rpx;
padding: 10rpx;
box-shadow:
0 20rpx 40rpx rgba(0, 0, 0, 0.06),
0 8rpx 20rpx rgba(0, 0, 0, 0.03),
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.8);
border: 1px solid rgba(255, 255, 255, 0.9);
position: relative;
z-index: 10;
transition: all 0.3s ease;
}
/* 内层标签容器 */
.category-tab {
display: flex;
background: rgba(0, 0, 0, 0.02);
border-radius: 56rpx;
padding: 6rpx;
gap: 6rpx;
}
/* 单个标签项 */
.tab-item {
flex: 1;
text-align: center;
padding: 24rpx 0;
position: relative;
border-radius: 50rpx;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
overflow: hidden;
}
/* 标签文字 */
.tab-text {
font-size: 30rpx;
font-weight: 500;
color: #666;
letter-spacing: 2rpx;
position: relative;
z-index: 2;
transition: all 0.3s ease;
}
/* 选中状态 - 渐变背景 */
.tab-item.active {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
box-shadow:
0 10rpx 20rpx rgba(102, 126, 234, 0.3),
0 4rpx 8rpx rgba(0, 0, 0, 0.1),
inset 0 2rpx 4rpx rgba(255, 255, 255, 0.5);
transform: translateY(-2rpx);
}
/* 选中状态的文字 */
.tab-item.active .tab-text {
color: #ffffff;
font-weight: 600;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2);
}
/* 添加光泽效果 */
.tab-item.active::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(45deg,
rgba(255, 255, 255, 0.3) 0%,
rgba(255, 255, 255, 0.2) 20%,
transparent 50%);
border-radius: 50rpx;
pointer-events: none;
z-index: 1;
}
/* 添加微光动画 */
.tab-item.active::after {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.3) 0%, transparent 70%);
opacity: 0.5;
animation: shimmer 3s infinite;
pointer-events: none;
z-index: 1;
}
/* 悬停效果 */
@media (hover: hover) {
.tab-item:hover:not(.active) {
background: rgba(255, 255, 255, 0.8);
transform: translateY(-2rpx);
box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.05);
}
.tab-item:hover:not(.active) .tab-text {
color: #333;
}
}
/* 点击效果 */
.tab-item:active {
transform: scale(0.98);
}
/* 微光动画 */
@keyframes shimmer {
0% {
transform: translateX(-100%) translateY(-100%) rotate(45deg);
opacity: 0;
}
20% {
opacity: 0.5;
}
40% {
transform: translateX(100%) translateY(100%) rotate(45deg);
opacity: 0;
}
100% {
transform: translateX(100%) translateY(100%) rotate(45deg);
opacity: 0;
}
}
.tab-item.active:nth-child(1) {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.tab-item.active:nth-child(2) {
background-image: linear-gradient(to right, #f78ca0 0%, #f9748f 19%, #fd868c 60%, #fe9a8b 100%);
}
.tab-item.active-bottom {
position: relative;
}
.tab-item.active-bottom::after {
content: '';
position: absolute;
bottom: -10rpx;
left: 50%;
transform: translateX(-50%);
width: 60rpx;
height: 4rpx;
background: linear-gradient(90deg, #667eea, #764ba2);
border-radius: 4rpx;
animation: slideIn 0.3s ease;
}
/* 表单容器 */
.form-container {
padding: 0 30rpx 40rpx;
position: relative;
z-index: 10;
}
.form-card {
background: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(20px);
border-radius: 32rpx;
margin-bottom: 20rpx;
padding: 30rpx;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.02),
0 2rpx 8rpx rgba(0, 0, 0, 0.01);
border: 1px solid rgba(255, 255, 255, 0.8);
}
.form-item {
width: 100%;
}
.label-wrapper {
display: flex;
align-items: center;
margin-bottom: 20rpx;
}
.label {
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-right: 8rpx;
}
.required {
font-size: 24rpx;
color: #ff6b6b;
margin-left: 8rpx;
}
.optional {
font-size: 24rpx;
color: #999;
background: rgba(0, 0, 0, 0.03);
padding: 4rpx 12rpx;
border-radius: 20rpx;
margin-left: 8rpx;
}
.input {
width: 100%;
height: 88rpx;
background: #f8f9fc;
border-radius: 20rpx;
padding: 0 30rpx;
font-size: 28rpx;
color: #333;
border: 2rpx solid transparent;
box-sizing: border-box;
}
.input:focus {
border-color: #07c160;
background: #fff;
}
.placeholder {
color: #b8b8b8;
font-size: 28rpx;
}
.textarea {
width: 100%;
min-height: 240rpx;
background: #f8f9fc;
border-radius: 20rpx;
padding: 24rpx 30rpx;
font-size: 28rpx;
color: #333;
border: 2rpx solid transparent;
box-sizing: border-box;
}
.textarea:focus {
border-color: #07c160;
background: #fff;
}
.word-count {
display: block;
text-align: right;
font-size: 24rpx;
color: #999;
margin-top: 12rpx;
}
/* 分类选择器 */
.category-selector {
width: 100%;
min-height: 88rpx;
display: flex;
align-items: center;
}
.category-badge {
display: inline-block;
padding: 16rpx 32rpx;
border-radius: 40rpx;
color: #648ac2;
font-size: 28rpx;
font-weight: 500;
box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.1);
letter-spacing: 1rpx;
}
.category-placeholder {
width: 100%;
height: 88rpx;
background: #f8f9fc;
border-radius: 20rpx;
padding: 0 30rpx;
font-size: 28rpx;
line-height: 88rpx;
color: #b8b8b8;
border: 2rpx solid transparent;
display: flex;
align-items: center;
justify-content: space-between;
}
.category-placeholder .arrow {
font-size: 40rpx;
color: #999;
transform: rotate(90deg);
display: inline-block;
}
/* 上传器 */
.uploader-wrapper {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.uploader {
width: 220rpx;
height: 220rpx;
background: #f8f9fc;
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
border: 2rpx dashed #ddd;
}
.preview {
width: 100%;
height: 100%;
object-fit: cover;
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.upload-placeholder .plus {
font-size: 60rpx;
color: #ccc;
line-height: 1;
margin-bottom: 8rpx;
}
.upload-placeholder .hint {
font-size: 22rpx;
color: #999;
}
.upload-tip {
font-size: 22rpx;
color: #999;
margin-top: 12rpx;
}
/* 视频选择器 */
.video-picker {
width: 100%;
min-height: 120rpx;
background: #f8f9fc;
border-radius: 20rpx;
padding: 20rpx 30rpx;
box-sizing: border-box;
border: 2rpx dashed #ddd;
}
.video-info {
display: flex;
align-items: center;
}
.video-name {
font-size: 26rpx;
color: #333;
flex: 1;
word-break: break-all;
}
.video-placeholder {
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
height: 80rpx;
}
.video-placeholder .plus {
font-size: 40rpx;
color: #ccc;
}
.video-placeholder .hint {
font-size: 26rpx;
color: #999;
}
/* 提交按钮 */
.btn-wrapper {
margin-top: 40rpx;
padding: 0 20rpx;
}
.submit-btn {
width: 100%;
height: 96rpx;
background: linear-gradient(135deg, #07c160 0%, #08994d 100%);
color: #ffffff;
font-size: 32rpx;
font-weight: 600;
border-radius: 48rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 20rpx 40rpx rgba(7, 193, 96, 0.3);
border: none;
}
.submit-btn.disabled {
background: linear-gradient(135deg, #c0c0c0 0%, #a0a0a0 100%);
box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.1);
}

66
pagesB/pages/repository/repository.js

@ -1,66 +0,0 @@
// pagesB/pages/repository/repository.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})

3
pagesB/pages/repository/repository.json

@ -1,3 +0,0 @@
{
"usingComponents": {}
}

2
pagesB/pages/repository/repository.wxml

@ -1,2 +0,0 @@
<!--pagesB/pages/repository/repository.wxml-->
<text>pagesB/pages/repository/repository.wxml</text>

1
pagesB/pages/repository/repository.wxss

@ -1 +0,0 @@
/* pagesB/pages/repository/repository.wxss */

381
pagesB/pages/spDetails/spDetails.js

@ -0,0 +1,381 @@
// pages/training/videoDetail/videoDetail.js
import http from '../../../utils/api'
const baseUrl = require('../../../utils/baseUrl')
Page({
data: {
baseUrl: baseUrl,
video: {},
videoUrl: '',
loading: true,
fullScreen: false,
isPlaying: false,
isMuted: false,
loop: false,
playbackRate: 1,
currentTime: 0,
duration: 0,
videoTags: [],
videoError: false,
autoplay: false,
controlsVisible: true,
controlsTimer: null,
lastTouchTime: 0,
},
onLoad(options) {
console.log('页面参数:', options)
this.getVideoDetails(options.id)
},
onReady() {
this.videoContext = wx.createVideoContext('videoPlayer', this)
console.log('视频上下文创建成功')
},
onUnload() {
// 清除定时器
if (this.data.controlsTimer) {
clearTimeout(this.data.controlsTimer)
}
// 页面卸载时停止播放
if (this.videoContext) {
this.videoContext.pause()
}
},
// 获取视频详情
getVideoDetails(id) {
this.setData({
loading: true,
videoError: false
})
http.videoDetails({
data: { id },
success: res => {
console.log('视频详情响应:', res)
if (res.code === 200 && res.data) {
const video = res.data
console.log('视频数据:', video)
// 处理视频URL
let videoUrl = ''
if (video.videoUrl) {
videoUrl = this.data.baseUrl + video.videoUrl
console.log('视频完整URL:', videoUrl)
}
// 处理视频标签
const tags = video.tags ? video.tags.split(',').filter(tag => tag.trim()) : []
this.setData({
video: video,
videoUrl: videoUrl,
videoTags: tags,
loading: false
})
// 设置页面标题
wx.setNavigationBarTitle({
title: video.title.substring(0, 12) + (video.title.length > 12 ? '...' : '')
})
} else {
wx.showToast({
title: res.msg || '视频不存在',
icon: 'none',
duration: 2000
})
setTimeout(() => {
wx.navigateBack()
}, 2000)
}
},
fail: err => {
console.error('获取视频详情失败:', err)
this.setData({
loading: false,
videoError: true
})
wx.showToast({
title: '加载失败,请重试',
icon: 'none',
duration: 2000
})
}
})
},
// 返回上一页
goBack() {
wx.navigateBack()
},
// 视频加载完成
onVideoLoaded(e) {
console.log('视频元数据加载完成:', e.detail)
this.setData({
duration: e.detail.duration || 0,
videoError: false
})
},
// 视频播放错误
onVideoError(e) {
console.error('视频播放错误详情:', e.detail)
this.setData({
videoError: true,
isPlaying: false
})
wx.showModal({
title: '播放错误',
content: '视频加载失败,请检查网络或视频链接',
showCancel: true,
confirmText: '重试',
success: (res) => {
if (res.confirm) {
this.retryVideo()
}
}
})
},
// 视频播放事件
onVideoPlay(e) {
console.log('视频开始播放')
this.setData({
isPlaying: true,
videoError: false
})
// 播放时隐藏控制栏
if (this.data.fullScreen) {
this.hideControls()
}
},
// 视频暂停事件
onVideoPause(e) {
console.log('视频暂停')
this.setData({
isPlaying: false
})
// 暂停时显示控制栏
if (this.data.fullScreen) {
this.showControls()
}
},
// 视频播放结束
onVideoEnded(e) {
console.log('视频播放结束')
this.setData({
isPlaying: false,
currentTime: 0
})
// 结束播放时显示控制栏
if (this.data.fullScreen) {
this.showControls()
}
},
// 时间更新事件
onTimeUpdate(e) {
const currentTime = e.detail.currentTime
const duration = e.detail.duration
// 更新当前时间和总时长
this.setData({
currentTime: currentTime,
duration: duration > 0 ? duration : this.data.duration
})
},
// 全屏切换事件
onFullScreenChange(e) {
const fullScreen = e.detail.fullScreen
console.log('全屏状态变化:', fullScreen)
this.setData({
fullScreen: fullScreen,
controlsVisible: !fullScreen
})
if (fullScreen) {
wx.setKeepScreenOn({ keepScreenOn: true })
// 进入全屏后自动播放
setTimeout(() => {
this.videoContext.play()
}, 300)
} else {
wx.setKeepScreenOn({ keepScreenOn: false })
// 退出全屏时暂停
this.videoContext.pause()
}
},
// 进入全屏
enterFullScreen() {
this.videoContext.requestFullScreen({ direction: 90 })
},
// 退出全屏
exitFullScreen() {
this.videoContext.exitFullScreen()
},
// 切换播放状态
togglePlay() {
console.log('切换播放状态,当前状态:', this.data.isPlaying)
if (this.data.videoError) {
this.retryVideo()
return
}
if (this.data.isPlaying) {
this.videoContext.pause()
} else {
this.videoContext.play()
}
},
// 切换静音
toggleMute() {
const isMuted = !this.data.isMuted
this.setData({ isMuted: isMuted })
this.videoContext.muted(isMuted)
wx.showToast({
title: isMuted ? '已静音' : '已取消静音',
icon: 'none',
duration: 800
})
},
// 切换循环
toggleLoop() {
const loop = !this.data.loop
this.setData({ loop: loop })
this.videoContext.loop(loop)
wx.showToast({
title: loop ? '开启循环播放' : '关闭循环播放',
icon: 'none',
duration: 800
})
},
// 切换播放速度
toggleSpeed() {
const speeds = [0.5, 0.75, 1, 1.25, 1.5, 2]
const currentIndex = speeds.indexOf(this.data.playbackRate)
const nextIndex = (currentIndex + 1) % speeds.length
const nextSpeed = speeds[nextIndex]
this.setData({ playbackRate: nextSpeed })
this.videoContext.playbackRate(nextSpeed)
wx.showToast({
title: `播放速度 ${nextSpeed}x`,
icon: 'none',
duration: 800
})
},
// 重试播放
retryVideo() {
console.log('重试播放视频')
this.setData({
videoError: false,
loading: true
})
// 重新加载视频
setTimeout(() => {
this.setData({ loading: false })
if (this.videoContext) {
this.videoContext.seek(0)
this.videoContext.play()
}
}, 500)
},
// 触摸控制
onTouchControl(e) {
const type = e.currentTarget.dataset.type
const currentTime = this.data.currentTime
const duration = this.data.duration
if (type === 'backward') {
const newTime = Math.max(0, currentTime - 10)
this.setData({ currentTime: newTime })
this.videoContext.seek(newTime)
wx.showToast({
title: '-10秒',
icon: 'none',
duration: 500
})
} else if (type === 'forward') {
const newTime = Math.min(duration, currentTime + 10)
this.setData({ currentTime: newTime })
this.videoContext.seek(newTime)
wx.showToast({
title: '+10秒',
icon: 'none',
duration: 500
})
}
},
// 触摸移动
onTouchMove() {
if (this.data.fullScreen) {
this.showControls()
this.hideControls()
}
},
// 显示控制栏
showControls() {
this.setData({ controlsVisible: true })
// 清除之前的定时器
if (this.data.controlsTimer) {
clearTimeout(this.data.controlsTimer)
}
// 3秒后自动隐藏控制栏
const timer = setTimeout(() => {
if (this.data.isPlaying && this.data.fullScreen) {
this.setData({ controlsVisible: false })
}
}, 3000)
this.setData({ controlsTimer: timer })
},
// 隐藏控制栏
hideControls() {
if (this.data.controlsTimer) {
clearTimeout(this.data.controlsTimer)
}
const timer = setTimeout(() => {
if (this.data.isPlaying && this.data.fullScreen) {
this.setData({ controlsVisible: false })
}
}, 3000)
this.setData({ controlsTimer: timer })
},
})

4
pagesB/pages/spDetails/spDetails.json

@ -0,0 +1,4 @@
{
"navigationBarTitleText":"视频详情",
"usingComponents": {}
}

174
pagesB/pages/spDetails/spDetails.wxml

@ -0,0 +1,174 @@
<view class="video-detail-container">
<!-- 导航栏 -->
<view class="nav-bar" wx:if="{{!fullScreen}}">
<view class="nav-title">{{video.title}}</view>
</view>
<!-- 视频播放器区域 -->
<view class="video-player-section" style="{{fullScreen ? 'height: 100vh;' : ''}}">
<!-- 视频播放器 -->
<video
id="videoPlayer"
src="{{videoUrl}}"
poster="{{video.coverImage ? baseUrl + video.coverImage : ''}}"
initial-time="0"
autoplay="{{autoplay}}"
loop="{{loop}}"
muted="{{isMuted}}"
controls="{{!fullScreen}}"
show-fullscreen-btn="{{!fullScreen}}"
show-play-btn="true"
show-center-play-btn="true"
enable-progress-gesture="true"
enable-play-gesture="{{fullScreen}}"
object-fit="contain"
direction="0"
bindplay="onVideoPlay"
bindpause="onVideoPause"
bindended="onVideoEnded"
bindtimeupdate="onTimeUpdate"
bindfullscreenchange="onFullScreenChange"
bindloadedmetadata="onVideoLoaded"
binderror="onVideoError"
class="video-player"
></video>
<!-- 视频封面 -->
<view class="video-cover" wx:if="{{video.coverImage && !isPlaying && !fullScreen}}">
<image
src="{{baseUrl + video.coverImage}}"
mode="aspectFill"
class="cover-image"
></image>
<view class="cover-play-btn" catchtap="togglePlay">
<image class="play-icon" src="/pagesB/images/bo.png"></image>
</view>
</view>
<!-- 全屏时的自定义控制栏 -->
<view class="fullscreen-controls" wx:if="{{fullScreen}}" catchtouchmove="onTouchMove">
<!-- 顶部控制栏 -->
<view class="fullscreen-top-bar">
<view class="top-bar-left" catchtap="exitFullScreen">
<image class="back-icon" src="/pagesB/images/left.png"></image>
<text class="back-text">返回</text>
</view>
<view class="top-bar-title">{{video.title}}</view>
<view class="top-bar-right"></view>
</view>
<!-- 播放按钮(中间) -->
<view class="center-play-btn" wx:if="{{!isPlaying}}" catchtap="togglePlay">
<image class="play-large-icon" src="/pagesB/images/play.png"></image>
<view class="play-ripple"></view>
</view>
<!-- 底部控制栏 -->
<view class="fullscreen-bottom-bar">
<!-- 进度条 -->
<view class="fullscreen-progress">
<view class="progress-time">{{formatTime(currentTime)}}</view>
<view class="progress-slider-container">
<view class="progress-bg">
<view class="progress-current" style="width: {{duration ? (currentTime / duration * 100) + '%' : '0%'}}"></view>
</view>
<view
class="progress-thumb"
style="left: {{duration ? (currentTime / duration * 100) + '%' : '0%'}}"
></view>
</view>
<view class="progress-time">{{formatTime(duration)}}</view>
</view>
<view class="bottom-controls">
<view class="control-item" catchtap="togglePlay">
<image class="control-icon" src="{{isPlaying ? '/pagesB/images/pause.png' : '/pagesB/images/play.png'}}"></image>
</view>
<view class="control-item" catchtap="toggleMute">
<image class="control-icon" src="{{isMuted ? '/pagesB/images/volume_mute.png' : '/pagesB/images/volume.png'}}"></image>
</view>
<view class="control-item" catchtap="toggleLoop">
<image class="control-icon" src="{{loop ? '/pagesB/images/loop_on.png' : '/pagesB/images/loop.png'}}"></image>
</view>
<view class="control-item" catchtap="toggleSpeed">
<text class="speed-text">{{playbackRate}}x</text>
</view>
<view class="control-item" catchtap="enterFullScreen">
<image class="control-icon" src="/pagesB/images/fullscreen.png"></image>
</view>
</view>
</view>
<!-- 触摸控制区域 -->
<view class="touch-control-left" catchtap="onTouchControl" data-type="backward"></view>
<view class="touch-control-center" catchtap="togglePlay"></view>
<view class="touch-control-right" catchtap="onTouchControl" data-type="forward"></view>
</view>
<!-- 非全屏播放按钮 -->
<view class="normal-play-btn" wx:if="{{!fullScreen && !isPlaying && !video.coverImage}}" catchtap="togglePlay">
<image class="play-icon" src="/pagesB/images/bo.png"></image>
</view>
</view>
<!-- 视频信息区域 -->
<scroll-view
class="video-info-section"
scroll-y
wx:if="{{!fullScreen}}"
scroll-with-animation
>
<!-- 视频标题和描述 -->
<view class="video-header">
<view class="video-title">{{video.title}}</view>
<view class="video-description">{{video.description}}</view>
<!-- 视频统计数据 -->
<view class="video-stats">
<view class="stat-item">
<text>{{video.viewCount}} 播放</text>
</view>
<view class="stat-item">
<text>{{video.publishTime}}</text>
</view>
<view class="stat-item">
<text>{{video.category}}</text>
</view>
</view>
</view>
<!-- 发布者信息 -->
<view class="publisher-section" wx:if="{{video.publisherName}}">
<image class="publisher-avatar" src="{{video.publisherAvatar ? baseUrl + video.publisherAvatar : '/pagesB/images/default_avatar.png'}}"></image>
<view class="publisher-info">
<view class="publisher-name">{{video.publisherName}}</view>
<view class="publisher-desc">{{video.publisherDesc || '视频发布者'}}</view>
</view>
</view>
<!-- 视频标签 -->
<view class="tags-section" wx:if="{{videoTags.length > 0}}">
<view class="section-title">标签</view>
<view class="tags-container">
<view class="tag-item" wx:for="{{videoTags}}" wx:key="index">
{{item}}
</view>
</view>
</view>
</scroll-view>
<!-- 加载中 -->
<view class="loading-container" wx:if="{{loading}}">
<view class="loading-spinner">
<view class="spinner-circle"></view>
</view>
<text class="loading-text">加载中...</text>
</view>
<!-- 错误提示 -->
<view class="error-container" wx:if="{{videoError}}">
<image class="error-icon" src="/pagesB/images/error.png"></image>
<text class="error-text">视频加载失败</text>
<view class="retry-btn" catchtap="retryVideo">重试</view>
</view>
</view>

664
pagesB/pages/spDetails/spDetails.wxss

@ -0,0 +1,664 @@
.video-detail-container {
min-height: 100vh;
background: linear-gradient(135deg, #0f172a 0%, #1a1e2c 100%);
position: relative;
}
/* 导航栏 */
.nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 88rpx;
padding: 0 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
background: linear-gradient(180deg, rgba(15, 23, 42, 0.98) 0%, rgba(15, 23, 42, 0.9) 100%);
backdrop-filter: blur(20rpx);
z-index: 1000;
border-bottom: 1rpx solid rgba(255, 255, 255, 0.08);
}
.nav-title {
font-size: 34rpx;
font-weight: 700;
color: #fff;
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
}
/* 视频播放器区域 */
.video-player-section {
width: 100%;
height: 500rpx;
position: relative;
background: #000;
overflow: hidden;
}
.video-player {
width: 100%;
height: 100%;
background: #000;
}
/* 视频封面 */
.video-cover {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #000;
z-index: 2;
}
.cover-image {
width: 100%;
height: 100%;
opacity: 0.9;
}
.cover-play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 120rpx;
height: 120rpx;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(20rpx);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 3rpx solid rgba(255, 255, 255, 0.3);
box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.5);
}
.cover-play-btn .play-icon {
width: 50rpx;
height: 50rpx;
margin-left: 8rpx;
filter: brightness(2);
}
/* 全屏控制栏 */
.fullscreen-controls {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 10;
opacity: 1;
transition: opacity 0.3s;
}
.fullscreen-controls.hidden {
opacity: 0;
pointer-events: none;
}
.fullscreen-top-bar {
padding: 80rpx 40rpx 0;
display: flex;
align-items: center;
justify-content: space-between;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0) 100%);
height: 120rpx;
}
.top-bar-left {
display: flex;
align-items: center;
gap: 16rpx;
padding: 16rpx 28rpx;
background: rgba(0, 0, 0, 0.6);
border-radius: 40rpx;
backdrop-filter: blur(20rpx);
border: 1rpx solid rgba(255, 255, 255, 0.1);
}
.back-text {
color: #fff;
font-size: 28rpx;
font-weight: 500;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.3);
}
.top-bar-title {
font-size: 32rpx;
color: #fff;
max-width: 400rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-weight: 600;
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.5);
padding: 12rpx 24rpx;
background: rgba(0, 0, 0, 0.5);
border-radius: 20rpx;
backdrop-filter: blur(10rpx);
}
/* 中间播放按钮 */
.center-play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 160rpx;
height: 160rpx;
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(30rpx);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
border: 4rpx solid rgba(255, 255, 255, 0.3);
z-index: 20;
box-shadow:
0 12rpx 60rpx rgba(0, 0, 0, 0.5),
inset 0 0 0 1rpx rgba(255, 255, 255, 0.1);
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
box-shadow:
0 12rpx 60rpx rgba(0, 0, 0, 0.5),
inset 0 0 0 1rpx rgba(255, 255, 255, 0.1);
}
50% {
box-shadow:
0 12rpx 80rpx rgba(52, 152, 219, 0.4),
inset 0 0 0 1rpx rgba(52, 152, 219, 0.3);
}
100% {
box-shadow:
0 12rpx 60rpx rgba(0, 0, 0, 0.5),
inset 0 0 0 1rpx rgba(255, 255, 255, 0.1);
}
}
.play-large-icon {
width: 70rpx;
height: 70rpx;
margin-left: 10rpx;
filter: brightness(2) drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.5));
}
.play-ripple {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 0;
height: 0;
border-radius: 50%;
border: 2rpx solid rgba(255, 255, 255, 0.4);
animation: ripple 2s infinite;
}
@keyframes ripple {
0% {
width: 0;
height: 0;
opacity: 1;
}
100% {
width: 240rpx;
height: 240rpx;
opacity: 0;
}
}
/* 底部控制栏 */
.fullscreen-bottom-bar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 0 40rpx 80rpx;
background: linear-gradient(to top, rgba(0, 0, 0, 0.95) 0%, rgba(0, 0, 0, 0) 100%);
}
.fullscreen-progress {
display: flex;
align-items: center;
gap: 24rpx;
margin-bottom: 60rpx;
padding: 0 20rpx;
}
.progress-time {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.95);
min-width: 90rpx;
text-align: center;
font-weight: 500;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.5);
}
.progress-slider-container {
flex: 1;
position: relative;
height: 8rpx;
background: rgba(255, 255, 255, 0.2);
border-radius: 4rpx;
overflow: hidden;
}
.progress-bg {
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.1);
border-radius: 4rpx;
}
.progress-current {
height: 100%;
background: linear-gradient(90deg, #3498db, #9b59b6);
border-radius: 4rpx;
transition: width 0.1s;
}
.progress-thumb {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 28rpx;
height: 28rpx;
background: #fff;
border-radius: 50%;
box-shadow:
0 4rpx 12rpx rgba(0, 0, 0, 0.5),
0 0 0 2rpx #3498db;
}
.bottom-controls {
display: flex;
justify-content: center;
align-items: center;
gap: 80rpx;
padding: 30rpx 50rpx;
background: rgba(0, 0, 0, 0.7);
border-radius: 80rpx;
backdrop-filter: blur(30rpx);
margin: 0 auto;
max-width: 700rpx;
border: 1rpx solid rgba(255, 255, 255, 0.1);
}
.control-item {
width: 90rpx;
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
transition: all 0.2s;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.3);
}
.control-item:active {
background: rgba(255, 255, 255, 0.2);
transform: scale(0.9);
}
.control-icon {
width: 44rpx;
height: 44rpx;
filter: brightness(2) drop-shadow(0 2rpx 4rpx rgba(0, 0, 0, 0.3));
}
.speed-text {
color: #fff;
font-size: 30rpx;
font-weight: 700;
background: linear-gradient(135deg, #3498db, #9b59b6);
padding: 12rpx 28rpx;
border-radius: 40rpx;
box-shadow: 0 6rpx 24rpx rgba(52, 152, 219, 0.4);
}
/* 触摸控制区域 */
.touch-control-left,
.touch-control-center,
.touch-control-right {
position: absolute;
top: 120rpx;
bottom: 200rpx;
z-index: 5;
}
.touch-control-left {
left: 0;
width: 30%;
}
.touch-control-center {
left: 30%;
width: 40%;
}
.touch-control-right {
left: 70%;
width: 30%;
}
/* 非全屏播放按钮 */
.normal-play-btn {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 120rpx;
height: 120rpx;
background: rgba(0, 0, 0, 0.7);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 3;
border: 3rpx solid rgba(255, 255, 255, 0.3);
backdrop-filter: blur(10rpx);
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.5);
}
.normal-play-btn .play-icon {
width: 50rpx;
height: 50rpx;
margin-left: 8rpx;
filter: brightness(2);
}
/* 视频信息区域 */
.video-info-section {
height: calc(100vh - 500rpx);
background: linear-gradient(180deg, #1a1e2c 0%, #0f172a 100%);
}
.video-header {
padding: 50rpx 40rpx 40rpx;
border-bottom: 1rpx solid rgba(255, 255, 255, 0.08);
}
.video-title {
font-size: 40rpx;
font-weight: 800;
color: #fff;
line-height: 1.3;
margin-bottom: 30rpx;
letter-spacing: 0.5rpx;
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
}
.video-description {
font-size: 30rpx;
color: rgba(255, 255, 255, 0.85);
line-height: 1.6;
margin-bottom: 40rpx;
}
.video-stats {
display: flex;
gap: 30rpx;
flex-wrap: wrap;
}
.stat-item {
display: flex;
align-items: center;
gap: 14rpx;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.7);
padding: 14rpx 28rpx;
background: rgba(255, 255, 255, 0.08);
border-radius: 40rpx;
backdrop-filter: blur(10rpx);
}
/* 发布者信息 */
.publisher-section {
padding: 40rpx;
display: flex;
align-items: center;
gap: 30rpx;
border-bottom: 1rpx solid rgba(255, 255, 255, 0.08);
background: rgba(255, 255, 255, 0.03);
margin: 0 20rpx;
border-radius: 24rpx;
margin-top: 20rpx;
}
.publisher-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
border: 4rpx solid #3498db;
box-shadow:
0 12rpx 40rpx rgba(52, 152, 219, 0.5),
0 0 0 1rpx rgba(255, 255, 255, 0.1);
background: #1e293b;
}
.publisher-info {
flex: 1;
}
.publisher-name {
font-size: 36rpx;
font-weight: 700;
color: #fff;
margin-bottom: 12rpx;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.3);
}
.publisher-desc {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.6);
line-height: 1.4;
}
/* 标签区域 */
.tags-section {
padding: 40rpx;
background: rgba(255, 255, 255, 0.03);
margin: 20rpx;
border-radius: 24rpx;
}
.section-title {
font-size: 32rpx;
font-weight: 700;
color: #fff;
margin-bottom: 30rpx;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.3);
}
.tags-container {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.tag-item {
padding: 16rpx 36rpx;
background: linear-gradient(135deg, #3498db, #2ecc71);
color: white;
border-radius: 40rpx;
font-size: 26rpx;
font-weight: 600;
box-shadow: 0 6rpx 24rpx rgba(52, 152, 219, 0.4);
transition: all 0.2s;
}
.tag-item:active {
transform: scale(0.95);
box-shadow: 0 4rpx 16rpx rgba(52, 152, 219, 0.3);
}
/* 加载中 */
.loading-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, #0f172a 0%, #1a1e2c 100%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 2000;
}
.loading-spinner {
position: relative;
width: 140rpx;
height: 140rpx;
margin-bottom: 50rpx;
}
.spinner-circle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
border: 10rpx solid transparent;
border-top-color: #3498db;
border-right-color: #3498db;
border-radius: 50%;
animation: spinnerRotate 1.2s linear infinite;
box-shadow: 0 0 20rpx rgba(52, 152, 219, 0.3);
}
@keyframes spinnerRotate {
0% {
transform: translate(-50%, -50%) rotate(0deg);
}
100% {
transform: translate(-50%, -50%) rotate(360deg);
}
}
.loading-text {
font-size: 32rpx;
color: rgba(255, 255, 255, 0.8);
letter-spacing: 3rpx;
font-weight: 500;
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
}
/* 错误提示 */
.error-container {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 2000;
background: linear-gradient(135deg, rgba(15, 23, 42, 0.95), rgba(26, 30, 44, 0.95));
padding: 80rpx 60rpx;
border-radius: 40rpx;
backdrop-filter: blur(40rpx);
border: 1rpx solid rgba(255, 255, 255, 0.1);
min-width: 500rpx;
box-shadow:
0 20rpx 80rpx rgba(0, 0, 0, 0.5),
inset 0 1rpx 0 rgba(255, 255, 255, 0.1);
}
.error-icon {
width: 140rpx;
height: 140rpx;
margin-bottom: 40rpx;
filter: brightness(1.5) drop-shadow(0 4rpx 12rpx rgba(0, 0, 0, 0.3));
}
.error-text {
font-size: 36rpx;
color: #fff;
margin-bottom: 50rpx;
font-weight: 700;
text-align: center;
text-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.3);
}
.retry-btn {
padding: 24rpx 80rpx;
background: linear-gradient(135deg, #3498db, #2980b9);
color: white;
border-radius: 50rpx;
font-size: 32rpx;
font-weight: 700;
box-shadow:
0 12rpx 40rpx rgba(52, 152, 219, 0.5),
inset 0 1rpx 0 rgba(255, 255, 255, 0.3);
transition: all 0.2s;
letter-spacing: 2rpx;
}
.retry-btn:active {
transform: scale(0.95);
box-shadow:
0 6rpx 24rpx rgba(52, 152, 219, 0.4),
inset 0 1rpx 0 rgba(255, 255, 255, 0.2);
}
/* 响应式调整 */
@media screen and (max-width: 750rpx) {
.video-player-section {
height: 450rpx;
}
.video-info-section {
height: calc(100vh - 450rpx);
}
.video-title {
font-size: 36rpx;
}
.video-description {
font-size: 28rpx;
}
.bottom-controls {
gap: 60rpx;
padding: 25rpx 40rpx;
max-width: 650rpx;
}
.center-play-btn {
width: 140rpx;
height: 140rpx;
}
.play-large-icon {
width: 60rpx;
height: 60rpx;
}
.fullscreen-top-bar {
padding: 60rpx 30rpx 0;
}
.fullscreen-bottom-bar {
padding: 0 30rpx 60rpx;
}
}

402
pagesB/pages/training/training.js

@ -0,0 +1,402 @@
import http from '../../../utils/api'
const baseUrl = require('../../../utils/baseUrl')
Page({
data: {
currentTab: 0,
searchKeyword: '',
articleActiveCategory: 0,
videoActiveCategory: '全部',
baseUrl: baseUrl,
// 文章相关
allArticles: [],
filteredArticles: [],
articlePageNo: 1,
articlePageSize: 10,
articleTotal: 0,
articleHasMore: true,
articleLoading: false,
articleRequested: false, // 标记文章数据是否已请求
// 视频相关
allVideos: [],
filteredVideos: [],
videoPageNo: 1,
videoPageSize: 10,
videoTotal: 0,
videoHasMore: true,
videoLoading: false,
videoRequested: false, // 标记视频数据是否已请求
// 字典数据
wzzd: [],
videoType: []
},
onLoad() {
this.getarticleZd()
this.getvideoZd()
this.loadInitialData()
},
// 加载初始数据
loadInitialData() {
if (this.data.currentTab === 0) {
this.resetArticleParams()
this.getArticleList(true)
} else {
this.resetVideoParams()
this.getVideoList(true)
}
},
// 文章字典
getarticleZd() {
http.articleZd({
data: {
dictType: 'article_category'
},
success: res => {
this.setData({
wzzd: res.rows
})
}
})
},
// 视频字典
getvideoZd() {
http.videoZd({
data: {
dictType: 'video_category'
},
success: res => {
this.setData({
videoType: res.rows
})
}
})
},
// 获取文章列表(支持搜索和分类)
getArticleList(isRefresh = false) {
if (this.data.articleLoading && !isRefresh) return
this.setData({
articleLoading: true
})
const params = {
pageNo: this.data.articlePageNo,
pageSize: this.data.articlePageSize
}
// 添加搜索关键词
if (this.data.searchKeyword && this.data.searchKeyword.trim()) {
params.searchKey = this.data.searchKeyword.trim()
}
// 添加分类筛选
if (this.data.articleActiveCategory !== 0) {
const categoryDict = this.data.wzzd.find(item => item.dictSort === this.data.articleActiveCategory)
if (categoryDict) {
params.category = categoryDict.dictLabel
}
}
http.article({
data: params,
success: res => {
const newArticles = res.rows || []
const total = res.total || 0
let allArticles, filteredArticles
if (isRefresh) {
allArticles = newArticles
filteredArticles = newArticles
} else {
allArticles = [...this.data.allArticles, ...newArticles]
filteredArticles = [...this.data.filteredArticles, ...newArticles]
}
const hasMore = this.data.articlePageNo * this.data.articlePageSize < total
this.setData({
allArticles,
filteredArticles,
articleTotal: total,
articleHasMore: hasMore,
articleLoading: false,
articleRequested: true
})
// 如果是下拉刷新,停止刷新动画
if (isRefresh) {
wx.stopPullDownRefresh()
}
},
fail: () => {
this.setData({
articleLoading: false
})
wx.showToast({
title: '加载失败',
icon: 'error',
duration: 2000
})
}
})
},
// 获取视频列表(支持搜索和分类)
getVideoList(isRefresh = false) {
if (this.data.videoLoading && !isRefresh) return
this.setData({
videoLoading: true
})
const params = {
pageNo: this.data.videoPageNo,
pageSize: this.data.videoPageSize
}
// 添加搜索关键词
if (this.data.searchKeyword && this.data.searchKeyword.trim()) {
params.searchKey = this.data.searchKeyword.trim()
}
// 添加分类筛选
if (this.data.videoActiveCategory !== '全部') {
params.category = this.data.videoActiveCategory
}
http.videoList({
data: params,
success: res => {
const newVideos = res.rows || []
const total = res.total || 0
let allVideos, filteredVideos
if (isRefresh) {
allVideos = newVideos
filteredVideos = newVideos
} else {
allVideos = [...this.data.allVideos, ...newVideos]
filteredVideos = [...this.data.filteredVideos, ...newVideos]
}
const hasMore = this.data.videoPageNo * this.data.videoPageSize < total
this.setData({
allVideos,
filteredVideos,
videoTotal: total,
videoHasMore: hasMore,
videoLoading: false,
videoRequested: true
})
// 如果是下拉刷新,停止刷新动画
if (isRefresh) {
wx.stopPullDownRefresh()
}
},
fail: () => {
this.setData({
videoLoading: false
})
wx.showToast({
title: '加载失败',
icon: 'error',
duration: 2000
})
}
})
},
// 重置文章参数
resetArticleParams() {
this.setData({
articlePageNo: 1,
articleTotal: 0,
articleHasMore: true,
allArticles: [],
filteredArticles: []
})
},
// 重置视频参数
resetVideoParams() {
this.setData({
videoPageNo: 1,
videoTotal: 0,
videoHasMore: true,
allVideos: [],
filteredVideos: []
})
},
// 切换主选项卡
switchTab(e) {
const tab = parseInt(e.currentTarget.dataset.tab)
if (tab === this.data.currentTab) return
this.setData({
currentTab: tab,
searchKeyword: ''
})
// 延迟加载新tab的数据,确保切换动画完成
setTimeout(() => {
if (tab === 0) {
if (!this.data.articleRequested) {
this.resetArticleParams()
this.getArticleList(true)
}
} else {
if (!this.data.videoRequested) {
this.resetVideoParams()
this.getVideoList(true)
}
}
}, 300)
},
// 搜索输入
onSearchInput(e) {
const keyword = e.detail.value
this.setData({
searchKeyword: keyword
})
// 防抖处理,500ms后执行搜索
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => {
this.performSearch()
}, 500)
},
// 执行搜索
performSearch() {
if (this.data.currentTab === 0) {
this.resetArticleParams()
this.getArticleList(true)
} else {
this.resetVideoParams()
this.getVideoList(true)
}
},
// 选择文章分类
selectArticleCategory(e) {
const category = Number(e.currentTarget.dataset.category)
if (category === this.data.articleActiveCategory) return
this.setData({
articleActiveCategory: category
})
// 重置并重新加载数据
this.resetArticleParams()
this.getArticleList(true)
},
// 选择视频分类
selectVideoCategory(e) {
const category = e.currentTarget.dataset.category
if (category === this.data.videoActiveCategory) return
this.setData({
videoActiveCategory: category
})
// 重置并重新加载数据
this.resetVideoParams()
this.getVideoList(true)
},
// 查看文章详情
viewArticleDetail(e) {
const id = e.currentTarget.dataset.id
console.log('查看文章详情', id)
wx.navigateTo({
url: `/pagesB/pages/wzDetails/wzDetails?id=${id}`
})
},
// 播放视频
playVideo(e) {
const id = e.currentTarget.dataset.id
console.log('播放视频', id)
wx.navigateTo({
url: `/pagesB/pages/spDetails/spDetails?id=${id}`
})
},
// 跳转发布页
bindPublish(){
wx.navigateTo({
url: '/pagesB/pages/publishAdd/publishAdd',
})
},
// 下拉刷新
onPullDownRefresh() {
wx.showNavigationBarLoading()
if (this.data.currentTab === 0) {
this.resetArticleParams()
this.getArticleList(true)
} else {
this.resetVideoParams()
this.getVideoList(true)
}
// 重置搜索关键词
this.setData({
searchKeyword: ''
})
},
// 上拉加载更多
onReachBottom() {
if (this.data.currentTab === 0) {
if (!this.data.articleHasMore || this.data.articleLoading) {
wx.showToast({
title: '已加载全部',
icon: 'none',
duration: 1000
})
return
}
this.setData({
articlePageNo: this.data.articlePageNo + 1
})
this.getArticleList(false)
} else {
if (!this.data.videoHasMore || this.data.videoLoading) {
wx.showToast({
title: '已加载全部',
icon: 'none',
duration: 1000
})
return
}
this.setData({
videoPageNo: this.data.videoPageNo + 1
})
this.getVideoList(false)
}
},
// 页面显示时刷新数据
onShow() {
// 如果需要返回时刷新数据,可以在这里调用
}
})

4
pagesB/pages/training/training.json

@ -0,0 +1,4 @@
{
"navigationBarTitleText":"在线培训",
"usingComponents": {}
}

215
pagesB/pages/training/training.wxml

@ -0,0 +1,215 @@
<!-- pages/training/training.wxml -->
<view class="training-container">
<!-- 顶部标题 -->
<view class="header">
<view class="title">在线培训</view>
<view class="subtitle">专业学习资源,助您快速成长</view>
<view class="header-decoration">
<view class="decoration-circle circle-1"></view>
<view class="decoration-circle circle-2"></view>
<view class="decoration-circle circle-3"></view>
</view>
</view>
<!-- 主选项卡切换 -->
<view class="tabs">
<view class="tab-item {{currentTab === 0 ? 'active' : ''}}" bindtap="switchTab" data-tab="0">
<text>文章</text>
<view class="tab-highlight {{currentTab === 0 ? 'active' : ''}}"></view>
</view>
<view class="tab-item {{currentTab === 1 ? 'active' : ''}}" bindtap="switchTab" data-tab="1">
<text>视频</text>
<view class="tab-highlight {{currentTab === 1 ? 'active' : ''}}"></view>
</view>
<view class="tab-slider {{currentTab === 0 ? 'left' : 'right'}}"></view>
</view>
<!-- 文章板块 -->
<view class="content-section" wx:if="{{currentTab === 0}}">
<!-- 搜索框 -->
<view class="search-box">
<image class="search-icon" src="/pagesB/images/sou.png"></image>
<input class="search-input" placeholder="搜索文章..." placeholder-class="placeholder-style" bindinput="onSearchInput" value="{{searchKeyword}}" />
<view class="search-decoration">
<view class="search-wave"></view>
</view>
</view>
<!-- 文章分类筛选 -->
<scroll-view class="category-scroll" scroll-x scroll-with-animation>
<view class="category-list">
<view class="category-item {{articleActiveCategory === 0 ? 'active' : ''}}" bindtap="selectArticleCategory" data-category="0">
<text>全部</text>
<view class="category-indicator"></view>
</view>
<view class="category-item {{item.dictSort === articleActiveCategory? 'active' : ''}}" bindtap="selectArticleCategory" data-category="{{item.dictSort}}" wx:for="{{wzzd}}" wx:key="index">
<text>{{item.dictLabel}}</text>
<view class="category-indicator"></view>
</view>
</view>
</scroll-view>
<!-- 文章列表 -->
<view class="articles-list">
<view class="article-card" wx:for="{{filteredArticles}}" wx:key="id" bindtap="viewArticleDetail" data-id="{{item.id}}">
<!-- 封面图片 -->
<view class="article-cover-container">
<image class="article-cover" src="{{baseUrl+item.coverImage}}" mode="aspectFill"></image>
<view class="cover-overlay"></view>
<view class="category-tag">{{item.category}}</view>
<view class="article-hover-effect"></view>
</view>
<!-- 文章信息 -->
<view class="article-info">
<view class="article-title">{{item.title}}</view>
<view class="article-desc">{{item.subtitle}}</view>
<view class="article-meta">
<view class="meta-item">
<image class="meta-icon" src="{{baseUrl+item.expertAvatar}}"></image>
<text class="meta-text">{{item.expertName}}</text>
</view>
<view class="meta-item">
<text class="meta-text">{{item.publishTime}}</text>
</view>
</view>
<view class="article-stats">
<view class="stat-item">
<image class="stat-icon" src="/pagesB/images/lll.png"></image>
<text>{{item.viewCount}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 加载更多状态 -->
<view wx:if="{{currentTab === 0 && filteredArticles.length > 0}}">
<view class="load-more" wx:if="{{articleHasMore && !articleLoading}}">
<text>上拉加载更多</text>
</view>
<view class="loading-more" wx:if="{{articleLoading}}">
<view class="loading-dot"></view>
<view class="loading-dot"></view>
<view class="loading-dot"></view>
<text>加载中...</text>
</view>
<view class="no-more" wx:if="{{!articleHasMore && filteredArticles.length > 0}}">
<text>已加载全部</text>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" wx:if="{{filteredArticles.length === 0}}">
<view class="empty-animation">
<view class="empty-circle"></view>
<view class="empty-circle circle-2"></view>
<view class="empty-circle circle-3"></view>
</view>
<text class="empty-text">暂无相关文章</text>
<text class="empty-hint">换个关键词试试吧</text>
</view>
</view>
<!-- 视频板块 -->
<view class="content-section" wx:if="{{currentTab === 1}}">
<!-- 搜索框 -->
<view class="search-box">
<image class="search-icon" src="/pagesB/images/sou.png"></image>
<input class="search-input" placeholder="搜索视频..." placeholder-class="placeholder-style" bindinput="onSearchInput" value="{{searchKeyword}}" />
<view class="search-decoration">
<view class="search-wave"></view>
</view>
</view>
<!-- 视频分类筛选 -->
<scroll-view class="category-scroll" scroll-x scroll-with-animation>
<view class="category-list">
<view class="category-item {{videoActiveCategory === '全部' ? 'active' : ''}}" bindtap="selectVideoCategory" data-category="全部">
<text>全部视频</text>
<view class="category-indicator"></view>
</view>
<view wx:for="{{videoType}}" wx:key="index" class="category-item {{ item.dictLabel=== videoActiveCategory ? 'active' : ''}}" bindtap="selectVideoCategory" data-category="{{item.dictLabel}}">
<text>{{item.dictLabel}}</text>
<view class="category-indicator"></view>
</view>
</view>
</scroll-view>
<!-- 视频列表 -->
<view class="videos-grid">
<view class="video-card" wx:for="{{filteredVideos}}" wx:key="id" bindtap="playVideo" data-id="{{item.id}}">
<!-- 视频封面 -->
<view class="video-cover-container">
<image class="video-cover" src="{{baseUrl+item.coverImage}}" mode="aspectFill"></image>
<view class="video-duration">{{item.category}}</view>
<view class="cover-overlay"></view>
<view class="play-button">
<image class="play-icon" src="/pagesB/images/bo.png"></image>
<view class="play-ripple"></view>
</view>
<view class="video-hover-effect"></view>
</view>
<!-- 视频信息 -->
<view class="video-info">
<view class="video-title">{{item.title}}</view>
<view class="video-instructor">
<image class="instructor-avatar" src="{{baseUrl+item.publisherAvatar}}"></image>
<text class="instructor-name">{{item.publisherName}}</text>
</view>
<view class="video-meta">
<view class="video-meta-item">
<text>{{item.auditTime}}</text>
</view>
<view class="video-meta-item">
<text>{{item.viewCount}}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 加载更多状态 -->
<view wx:if="{{currentTab === 1 && filteredVideos.length > 0}}">
<view class="load-more" wx:if="{{videoHasMore && !videoLoading}}">
<text>上拉加载更多</text>
</view>
<view class="loading-more" wx:if="{{videoLoading}}">
<view class="loading-dot"></view>
<view class="loading-dot"></view>
<view class="loading-dot"></view>
<text>加载中...</text>
</view>
<view class="no-more" wx:if="{{!videoHasMore && filteredVideos.length > 0}}">
<text>已加载全部</text>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" wx:if="{{filteredVideos.length === 0}}">
<view class="empty-animation">
<view class="empty-circle"></view>
<view class="empty-circle circle-2"></view>
<view class="empty-circle circle-3"></view>
</view>
<text class="empty-text">暂无相关视频</text>
<text class="empty-hint">换个关键词试试吧</text>
</view>
</view>
<!-- 新增视频气泡按钮 -->
<view class="create-btn-container" bind:tap="bindPublish">
<view class="create-btn" bindtap="showCreateModal">
<image class="btn-icon" src="/pagesA/images/jh.png"></image>
<text class="btn-text">发布</text>
</view>
</view>
</view>

1105
pagesB/pages/training/training.wxss
File diff suppressed because it is too large
View File

99
pagesB/pages/wzDetails/wzDetails.js

@ -0,0 +1,99 @@
import http from '../../../utils/api'
const baseUrl = require('../../../utils/baseUrl')
Page({
data: {
baseUrl: baseUrl,
article: {}, // 文章详情
loading: true, // 加载状态
},
onLoad(options) {
this.getArticleDetails(options.id)
},
// 获取文章详情
getArticleDetails(id) {
this.setData({
loading: true
})
http.articleDetails({
data: { id },
success: res => {
console.log('文章详情:', res)
if (res.code === 200 && res.data) {
// 解析富文本内容
const article = res.data
// 这里可以处理富文本内容的样式
article.content = this.formatRichContent(article.content)
this.setData({
article: article,
loading: false
})
// 设置页面标题
wx.setNavigationBarTitle({
title: article.title.substring(0, 10) + (article.title.length > 10 ? '...' : '')
})
} else {
wx.showToast({
title: '文章不存在',
icon: 'error'
})
setTimeout(() => {
wx.navigateBack()
}, 2000)
}
},
fail: err => {
console.error('获取文章详情失败:', err)
this.setData({
loading: false
})
wx.showToast({
title: '加载失败',
icon: 'error'
})
}
})
},
// 格式化富文本内容
formatRichContent(content) {
// 这里可以添加自定义样式,比如给图片添加样式
return content.replace(/<img/g, '<img style="max-width:100%;height:auto;border-radius:15rpx;margin:20rpx 0;"')
},
// 滚动事件
onPageScroll(e) {
this.setData({
scrollTop: e.scrollTop
})
},
// 回到顶部
scrollToTop() {
wx.pageScrollTo({
scrollTop: 0,
duration: 300
})
},
// 下拉刷新
onPullDownRefresh() {
},
// 页面卸载
onUnload() {
}
})

4
pagesB/pages/wzDetails/wzDetails.json

@ -0,0 +1,4 @@
{
"navigationBarTitleText":"文章详情",
"usingComponents": {}
}

62
pagesB/pages/wzDetails/wzDetails.wxml

@ -0,0 +1,62 @@
<view class="article-detail-container">
<!-- 文章内容 -->
<scroll-view class="article-content" scroll-y>
<!-- 文章封面 -->
<view class="article-cover">
<image
class="cover-image"
src="{{baseUrl + article.coverImage}}"
mode="widthFix"
lazy-load
></image>
<view class="cover-overlay"></view>
<view class="cover-gradient"></view>
<view class="cover-category">{{article.category}}</view>
</view>
<!-- 文章主体 -->
<view class="article-body">
<!-- 标题区域 -->
<view class="title-section">
<view class="article-title">{{article.title}}</view>
<view class="article-subtitle">{{article.subtitle}}</view>
<!-- 专家信息 -->
<view class="expert-info">
<image class="expert-avatar" src="{{baseUrl + article.expertAvatar}}"></image>
<view class="expert-detail">
<view class="expert-name">{{article.expertName}}</view>
<view class="publish-time">{{article.publishTime}}</view>
</view>
<view class="view-count">
<image class="view-icon" src="/pagesB/images/lll.png"></image>
<text>{{article.viewCount}} 阅读</text>
</view>
</view>
</view>
<!-- 文章内容(富文本) -->
<view class="rich-content">
<rich-text nodes="{{article.content}}"></rich-text>
</view>
</view>
</scroll-view>
<!-- 加载中 -->
<view class="loading-container" wx:if="{{loading}}">
<view class="loading-spinner">
<view class="spinner-circle"></view>
<view class="spinner-circle circle-2"></view>
<view class="spinner-circle circle-3"></view>
</view>
<text class="loading-text">加载中...</text>
</view>
<!-- 回到顶部按钮 -->
<view class="back-to-top" wx:if="{{scrollTop > 400}}" catchtap="scrollToTop">
<image class="top-icon" src="/pagesB/images/top.png"></image>
</view>
</view>

322
pagesB/pages/wzDetails/wzDetails.wxss

@ -0,0 +1,322 @@
.article-detail-container {
min-height: 100vh;
background: #f8fafc;
position: relative;
}
/* 文章内容容器 */
.article-content {
height: 100vh;
position: relative;
}
/* 文章封面 */
.article-cover {
position: relative;
height: 500rpx;
overflow: hidden;
}
.cover-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.cover-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.1));
}
.cover-gradient {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 200rpx;
background: linear-gradient(to top, rgba(0, 0, 0, 0.6), transparent);
}
.cover-category {
position: absolute;
top: 40rpx;
right: 40rpx;
background: rgba(52, 152, 219, 0.95);
backdrop-filter: blur(10rpx);
color: white;
padding: 12rpx 28rpx;
border-radius: 25rpx;
font-size: 24rpx;
font-weight: 600;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.2);
z-index: 2;
}
/* 文章主体 */
.article-body {
background: white;
border-radius: 40rpx 40rpx 0 0;
margin-top: -40rpx;
position: relative;
z-index: 10;
padding-bottom: 50rpx;
}
.title-section {
padding: 50rpx 40rpx 40rpx;
border-bottom: 1rpx solid #f1f5f9;
}
.article-title {
font-size: 44rpx;
font-weight: 800;
color: #1e293b;
line-height: 1.4;
margin-bottom: 20rpx;
letter-spacing: 0.5rpx;
}
.article-subtitle {
font-size: 30rpx;
color: #64748b;
line-height: 1.6;
margin-bottom: 40rpx;
padding-bottom: 30rpx;
border-bottom: 1rpx dashed #e2e8f0;
}
/* 专家信息 */
.expert-info {
display: flex;
align-items: center;
gap: 20rpx;
margin-top: 30rpx;
}
.expert-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
border: 3rpx solid white;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
.expert-detail {
flex: 1;
}
.expert-name {
font-size: 28rpx;
font-weight: 600;
color: #1e293b;
margin-bottom: 8rpx;
}
.publish-time {
font-size: 24rpx;
color: #94a3b8;
}
.view-count {
display: flex;
align-items: center;
gap: 10rpx;
background: rgba(226, 232, 240, 0.3);
padding: 12rpx 20rpx;
border-radius: 25rpx;
font-size: 24rpx;
color: #64748b;
}
.view-icon {
width: 28rpx;
height: 28rpx;
opacity: 0.7;
}
/* 富文本内容 */
.rich-content {
padding: 40rpx;
font-size: 32rpx;
line-height: 1.8;
color: #334155;
}
.rich-content h1,
.rich-content h2,
.rich-content h3 {
color: #1e293b;
margin: 40rpx 0 20rpx;
font-weight: 700;
}
.rich-content h1 {
font-size: 40rpx;
}
.rich-content h2 {
font-size: 36rpx;
}
.rich-content h3 {
font-size: 32rpx;
}
.rich-content p {
margin-bottom: 30rpx;
}
.rich-content ul,
.rich-content ol {
margin: 20rpx 0 20rpx 40rpx;
}
.rich-content li {
margin-bottom: 15rpx;
position: relative;
}
.rich-content ul li:before {
content: '•';
color: #3498db;
font-weight: bold;
position: absolute;
left: -25rpx;
}
.rich-content strong {
color: #1e293b;
font-weight: 700;
}
.rich-content a {
color: #3498db;
text-decoration: underline;
}
/* 加载中 */
.loading-container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.95);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 2000;
}
.loading-spinner {
position: relative;
width: 120rpx;
height: 120rpx;
margin-bottom: 40rpx;
}
.spinner-circle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
border: 8rpx solid rgba(52, 152, 219, 0.1);
border-radius: 50%;
animation: spinnerRotate 2s linear infinite;
}
.spinner-circle.circle-2 {
width: 80%;
height: 80%;
border-width: 6rpx;
animation-delay: 0.2s;
}
.spinner-circle.circle-3 {
width: 60%;
height: 60%;
border-width: 4rpx;
animation-delay: 0.4s;
}
@keyframes spinnerRotate {
0% {
transform: translate(-50%, -50%) rotate(0deg);
}
100% {
transform: translate(-50%, -50%) rotate(360deg);
}
}
.loading-text {
font-size: 28rpx;
color: #64748b;
letter-spacing: 1rpx;
}
/* 回到顶部 */
.back-to-top {
position: fixed;
right: 40rpx;
bottom: 160rpx;
width: 80rpx;
height: 80rpx;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10rpx);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.15);
border: 1rpx solid rgba(226, 232, 240, 0.8);
transition: all 0.3s ease;
z-index: 90;
}
.back-to-top:active {
transform: scale(0.95);
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.2);
}
.top-icon {
width: 36rpx;
height: 36rpx;
}
/* 响应式调整 */
@media screen and (max-width: 750rpx) {
.article-cover {
height: 400rpx;
}
.article-title {
font-size: 38rpx;
}
.article-subtitle {
font-size: 28rpx;
}
.rich-content {
font-size: 30rpx;
}
.action-bar {
padding: 0 30rpx;
}
.comment-btn {
padding: 18rpx 30rpx;
}
}

123
utils/api.js

@ -21,92 +21,7 @@ function carouselDetail(params) {
http('/muhu/ads/' + params.data.id, 'get', params)
}
// 通知公告
function disaster(params) {
http('/muhu/warning/list', 'get', params)
}
// 通知公告详情
function disasterDetail(params) {
http('/muhu/warning/' + params.data.id, 'get', params)
}
// 地图导航药店诊所
function pharmacy(params) {
http('/muhu/info/list', 'get', params)
}
// 办事指南
function guidance(params) {
http('/muhu/guide/list', 'get', params)
}
// AI问诊快捷词列表
function inquiry(params) {
http('/system/base/list', 'get', params)
}
// AI问诊模糊搜索
function search(params) {
http('/system/base/search', 'get', params)
}
// 销售市场
function sales(params) {
http('/muhu/sales/list', 'get', params)
}
// 饲料市场
function feed(params) {
http('/muhu/feed/list', 'get', params)
}
// 市场趋势
function trend(params) {
http('/muhu/trend/list', 'get', params)
}
// 问兽医-问诊单列表
function wzd(params) {
http('/muhu/consultation/list', 'get', params)
}
// 问兽医-问诊单新增
function wzdAdd(params) {
http('/muhu/consultation', 'post', params)
}
// 问兽医-兽医回复详情
function wzdxq(params) {
http('/vet/comments/list', 'get', params)
}
// 专家列表
function expertsList(params) {
http('/vet/experts/list', 'get', params)
}
// 药品推荐列表
function recommendationList(params) {
http('/system/recommendation/list', 'get', params)
}
// 药品推荐详情
function recommendationXq(params) {
http('/system/recommendation/'+ params.data.id , 'get', params)
}
// 知识库查询列表
function queryList(params) {
http('/system/query/list', 'get', params)
}
// 知识库查询提示
function tipList(params) {
http('/system/tip/list', 'get', params)
}
// 在线培训文章发布
// 文章发布
function article(params) {
http('/vet/knowledge/published/list', 'get', params)
}
@ -121,20 +36,16 @@ function articleDetails(params) {
http('/vet/knowledge/published/' + params.data.id, 'get', params)
}
// 政策解读列表
function policyelucidation(params) {
http('/system/interpretation/published/list', 'get', params)
// 文章新增
function articleAdd(params) {
http('/vet/knowledge', 'post', params)
}
// 政策解读详情
function policyeDetails(params) {
http('/system/interpretation/published/' + params.data.id, 'get', params)
// 视频新增
function videoAdd(params) {
http('/vet/training', 'post', params)
}
// 政策解读类型字典
function policyeZd(params) {
http('/system/dict/data/list', 'get', params)
}
// 行政区划
function areaChildren(params) {
@ -166,6 +77,16 @@ function videoZd(params) {
http('/system/dict/data/list', 'get', params)
}
//在线问答列表
function forumList(params) {
http('/system/questions/list', 'get', params)
@ -221,10 +142,6 @@ function feedback(params) {
http('/muhu/feedback', 'post', params)
}
// 预警类型
function warningType(params) {
http('/system/dict/data/list', 'get', params)
}
// 个人中心今日问诊
function today(params) {
@ -233,10 +150,8 @@ function today(params) {
export default { // 暴露接口
login,carousel,disaster,pharmacy,guidance,getPhoneNumber,inquiry,policyeDetails,
search,trend,feed,sales,wzd,wzdxq,wzdAdd,expertsList,recommendationList,policyeZd,
recommendationXq,queryList,tipList,article,articleDetails,articleZd,policyelucidation,
login,carousel,getPhoneNumber,article,articleDetails,articleZd,
areaChildren,userCode,UserInfo,videoList,videoZd,videoDetails,forumList,forumAdd,forumDetails,
forumReply,commentReply,experience,experiencezd,experienceDetails,realName,revise,feedback,
warningType,disasterDetail,today,carouselDetail
today,carouselDetail,videoAdd,articleAdd
}
Loading…
Cancel
Save