9 changed files with 669 additions and 2 deletions
-
3app.json
-
191pagesA/pages/releaseSuffer/releaseSuffer.js
-
4pagesA/pages/releaseSuffer/releaseSuffer.json
-
109pagesA/pages/releaseSuffer/releaseSuffer.wxml
-
278pagesA/pages/releaseSuffer/releaseSuffer.wxss
-
7pagesB/pages/experienceList/experienceList.js
-
8pagesB/pages/experienceList/experienceList.wxml
-
61pagesB/pages/experienceList/experienceList.wxss
-
10utils/api.js
@ -0,0 +1,191 @@ |
|||||
|
import http from '../../../utils/api'; |
||||
|
const baseUrl = require('../../../utils/baseUrl'); |
||||
|
|
||||
|
Page({ |
||||
|
data: { |
||||
|
baseUrl: baseUrl, |
||||
|
// 表单数据
|
||||
|
formData: { |
||||
|
title: '', |
||||
|
summary: '', |
||||
|
categoryName: '', |
||||
|
tags: '', // 改为字符串格式,如 "传染病,疫苗"
|
||||
|
content: '' |
||||
|
}, |
||||
|
// 分类列表 - 直接从接口返回的 rows 赋值
|
||||
|
categoryList: [], |
||||
|
categoryIndex: -1, |
||||
|
// 标签列表 - 直接从接口返回的 rows 赋值
|
||||
|
tagList: [], |
||||
|
// 已选中的标签对象数组
|
||||
|
selectedTags: [], |
||||
|
// 提交状态
|
||||
|
submitting: false |
||||
|
}, |
||||
|
|
||||
|
onLoad(options) { |
||||
|
this.getCategoryList(); |
||||
|
this.getTagList(); |
||||
|
}, |
||||
|
|
||||
|
// 输入处理
|
||||
|
onInput(e) { |
||||
|
const { field } = e.currentTarget.dataset; |
||||
|
const { value } = e.detail; |
||||
|
this.setData({ |
||||
|
[`formData.${field}`]: value |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 获取文章分类 - 直接使用 res.rows
|
||||
|
getCategoryList() { |
||||
|
http.articleZd({ |
||||
|
data: { |
||||
|
dictType: 'vet_experience_category' |
||||
|
}, |
||||
|
success: (res) => { |
||||
|
// 直接使用 res.rows 赋值
|
||||
|
if (res.rows && Array.isArray(res.rows)) { |
||||
|
this.setData({ categoryList: res.rows }); |
||||
|
} else { |
||||
|
console.error('分类数据格式错误', res); |
||||
|
wx.showToast({ title: '分类加载失败', icon: 'none' }); |
||||
|
} |
||||
|
}, |
||||
|
fail: (err) => { |
||||
|
console.error('分类接口异常', err); |
||||
|
wx.showToast({ title: '网络错误', icon: 'none' }); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 获取文章标签 - 直接使用 res.rows
|
||||
|
getTagList() { |
||||
|
http.videoZd({ |
||||
|
data: { |
||||
|
dictType: 'vet_experience_tag' |
||||
|
}, |
||||
|
success: (res) => { |
||||
|
// 直接使用 res.rows 赋值
|
||||
|
if (res.rows && Array.isArray(res.rows)) { |
||||
|
this.setData({ tagList: res.rows }); |
||||
|
} else { |
||||
|
console.error('标签数据格式错误', res); |
||||
|
wx.showToast({ title: '标签加载失败', icon: 'none' }); |
||||
|
} |
||||
|
}, |
||||
|
fail: (err) => { |
||||
|
console.error('标签接口异常', err); |
||||
|
wx.showToast({ title: '网络错误', icon: 'none' }); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 分类选择
|
||||
|
onCategoryChange(e) { |
||||
|
const index = parseInt(e.detail.value, 10); |
||||
|
const selectedCategory = this.data.categoryList[index]; |
||||
|
this.setData({ |
||||
|
categoryIndex: index, |
||||
|
[`formData.categoryName`]: selectedCategory.dictLabel |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 标签点击切换
|
||||
|
toggleTag(e) { |
||||
|
const tagItem = e.currentTarget.dataset.item; |
||||
|
let selectedTags = [...this.data.selectedTags]; |
||||
|
const index = selectedTags.findIndex(t => t.dictValue === tagItem.dictValue); |
||||
|
|
||||
|
if (index > -1) { |
||||
|
selectedTags.splice(index, 1); |
||||
|
} else { |
||||
|
selectedTags.push(tagItem); |
||||
|
} |
||||
|
|
||||
|
// 生成逗号分隔的标签字符串,如 "传染病,疫苗"
|
||||
|
const tagString = selectedTags.map(item => item.dictLabel).join(','); |
||||
|
|
||||
|
this.setData({ |
||||
|
selectedTags: selectedTags, |
||||
|
[`formData.tags`]: tagString |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 表单提交
|
||||
|
formSubmit(e) { |
||||
|
const { title, categoryName, content } = this.data.formData; |
||||
|
|
||||
|
// 表单验证
|
||||
|
if (!title || title.trim() === '') { |
||||
|
this.showError('请填写文章标题'); |
||||
|
return; |
||||
|
} |
||||
|
if (!categoryName) { |
||||
|
this.showError('请选择文章分类'); |
||||
|
return; |
||||
|
} |
||||
|
if (this.data.selectedTags.length === 0) { |
||||
|
this.showError('请至少选择一个标签'); |
||||
|
return; |
||||
|
} |
||||
|
if (!content || content.trim() === '') { |
||||
|
this.showError('请填写文章内容'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.setData({ submitting: true }); |
||||
|
|
||||
|
// 构建提交数据 - tags 已经是字符串格式
|
||||
|
const postData = { |
||||
|
title: this.data.formData.title, |
||||
|
summary: this.data.formData.summary || '', |
||||
|
categoryName: this.data.formData.categoryName, |
||||
|
tags: this.data.formData.tags, // 已经是 "传染病,疫苗" 格式
|
||||
|
content: this.data.formData.content |
||||
|
}; |
||||
|
|
||||
|
console.log('提交数据:', postData); // 调试用
|
||||
|
|
||||
|
http.shareAdd({ |
||||
|
data: postData, |
||||
|
success: (res) => { |
||||
|
if(res.code == 200){ |
||||
|
wx.showToast({ |
||||
|
title: '发布成功', |
||||
|
icon: 'success', |
||||
|
duration: 2000, |
||||
|
success: () => { |
||||
|
setTimeout(() => { |
||||
|
wx.navigateBack(); |
||||
|
}, 1500); |
||||
|
} |
||||
|
}) |
||||
|
}else{ |
||||
|
console.error('发布失败', err); |
||||
|
this.showError('发布失败,请重试'); |
||||
|
this.setData({ submitting: false }); |
||||
|
} |
||||
|
}, |
||||
|
fail: (err) => { |
||||
|
console.error('发布失败', err); |
||||
|
this.showError('发布失败,请重试'); |
||||
|
this.setData({ submitting: false }); |
||||
|
}, |
||||
|
complete: () => { |
||||
|
setTimeout(() => { |
||||
|
this.setData({ submitting: false }); |
||||
|
}, 3000); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
// 错误提示
|
||||
|
showError(msg) { |
||||
|
wx.showToast({ |
||||
|
title: msg, |
||||
|
icon: 'none', |
||||
|
duration: 2000 |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
@ -0,0 +1,4 @@ |
|||||
|
{ |
||||
|
"navigationBarTitleText":"发布文章", |
||||
|
"usingComponents": {} |
||||
|
} |
||||
@ -0,0 +1,109 @@ |
|||||
|
<view class="page-wrapper"> |
||||
|
<form catchsubmit="formSubmit"> |
||||
|
<!-- 标题卡片--> |
||||
|
<view class="form-card"> |
||||
|
<view class="card-header"> |
||||
|
<text class="header-icon">📝</text> |
||||
|
<text class="header-title">文章标题</text> |
||||
|
<text class="required-badge">必填</text> |
||||
|
</view> |
||||
|
<view class="card-content no-padding"> |
||||
|
<view class="input-wrapper"> |
||||
|
<input type="text" placeholder="请输入吸引人的标题(最多50字)" |
||||
|
name="title" maxlength="50" value="{{formData.title}}" |
||||
|
bindinput="onInput" data-field="title" |
||||
|
placeholder-class="placeholder-style" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 摘要卡片 --> |
||||
|
<view class="form-card"> |
||||
|
<view class="card-header"> |
||||
|
<text class="header-icon">📋</text> |
||||
|
<text class="header-title">文章摘要</text> |
||||
|
<text class="optional-badge">选填</text> |
||||
|
</view> |
||||
|
<view class="card-content no-padding"> |
||||
|
<view class="textarea-wrapper"> |
||||
|
<textarea placeholder="简单描述文章要点,让读者快速了解内容(最多200字)" |
||||
|
name="summary" maxlength="200" auto-height |
||||
|
value="{{formData.summary}}" bindinput="onInput" |
||||
|
data-field="summary" placeholder-class="placeholder-style" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 分类卡片 --> |
||||
|
<view class="form-card"> |
||||
|
<view class="card-header"> |
||||
|
<text class="header-icon">📂</text> |
||||
|
<text class="header-title">文章分类</text> |
||||
|
<text class="required-badge">必填</text> |
||||
|
</view> |
||||
|
<view class="card-content"> |
||||
|
<picker mode="selector" range="{{categoryList}}" range-key="dictLabel" |
||||
|
bindchange="onCategoryChange" value="{{categoryIndex}}"> |
||||
|
<view class="picker-trigger {{categoryIndex > -1 ? 'selected' : ''}}"> |
||||
|
<text>{{categoryIndex > -1 ? categoryList[categoryIndex].dictLabel : '请选择文章分类'}}</text> |
||||
|
<text class="picker-arrow">▼</text> |
||||
|
</view> |
||||
|
</picker> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 标签卡片 --> |
||||
|
<view class="form-card"> |
||||
|
<view class="card-header"> |
||||
|
<text class="header-icon">🏷️</text> |
||||
|
<text class="header-title">文章标签</text> |
||||
|
<text class="required-badge">必填</text> |
||||
|
</view> |
||||
|
<view class="card-content"> |
||||
|
<view class="tag-group"> |
||||
|
<block wx:for="{{tagList}}" wx:key="dictValue"> |
||||
|
<view class="tag-item {{selectedTags.includes(item) ? 'active' : ''}}" |
||||
|
bindtap="toggleTag" data-item="{{item}}"> |
||||
|
{{item.dictLabel}} |
||||
|
</view> |
||||
|
</block> |
||||
|
</view> |
||||
|
<view class="selected-tags" wx:if="{{selectedTags.length}}"> |
||||
|
<text class="selected-label">已选标签:</text> |
||||
|
<view class="selected-tag-list"> |
||||
|
<view class="selected-tag-item" wx:for="{{selectedTags}}" wx:key="index"> |
||||
|
{{item.dictLabel}} |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 内容卡片 --> |
||||
|
<view class="form-card content-card"> |
||||
|
<view class="card-header"> |
||||
|
<text class="header-icon">📄</text> |
||||
|
<text class="header-title">文章内容</text> |
||||
|
<text class="required-badge">必填</text> |
||||
|
</view> |
||||
|
<view class="card-content no-padding"> |
||||
|
<view class="textarea-wrapper"> |
||||
|
<textarea placeholder="开始撰写您的文章吧...(支持最多5000字)" |
||||
|
name="content" maxlength="5000" auto-height |
||||
|
value="{{formData.content}}" bindinput="onInput" |
||||
|
data-field="content" placeholder-class="placeholder-style" |
||||
|
class="content-textarea" /> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
|
||||
|
<!-- 提交按钮区域 --> |
||||
|
<view class="submit-area"> |
||||
|
<button form-type="submit" class="submit-btn" loading="{{submitting}}" disabled="{{submitting}}"> |
||||
|
<text wx:if="{{!submitting}}">✨ 发布文章</text> |
||||
|
<text wx:else>发布中...</text> |
||||
|
</button> |
||||
|
<view class="tip-text">好的内容值得被更多人看见</view> |
||||
|
</view> |
||||
|
</form> |
||||
|
</view> |
||||
@ -0,0 +1,278 @@ |
|||||
|
.page-wrapper { |
||||
|
min-height: 100vh; |
||||
|
background: linear-gradient(135deg, #f5f7fa 0%, #e9edf5 100%); |
||||
|
padding: 30rpx; |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
|
||||
|
/* 卡片样式 */ |
||||
|
.form-card { |
||||
|
background: rgba(255, 255, 255, 0.95); |
||||
|
backdrop-filter: blur(10px); |
||||
|
border-radius: 32rpx; |
||||
|
margin-bottom: 30rpx; |
||||
|
box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.05), 0 4rpx 12rpx rgba(0, 0, 0, 0.03); |
||||
|
overflow: hidden; |
||||
|
border: 2rpx solid rgba(255, 255, 255, 0.8); |
||||
|
transition: all 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
/* 卡片头部 */ |
||||
|
.card-header { |
||||
|
padding: 28rpx 32rpx; |
||||
|
background: linear-gradient(90deg, #ffffff, #fafcff); |
||||
|
border-bottom: 2rpx solid rgba(7, 193, 96, 0.1); |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 12rpx; |
||||
|
margin-bottom: 20rpx; |
||||
|
} |
||||
|
|
||||
|
.header-icon { |
||||
|
font-size: 36rpx; |
||||
|
line-height: 1; |
||||
|
filter: drop-shadow(0 4rpx 6rpx rgba(7, 193, 96, 0.2)); |
||||
|
} |
||||
|
|
||||
|
.header-title { |
||||
|
font-size: 32rpx; |
||||
|
font-weight: 600; |
||||
|
color: #1a2b3c; |
||||
|
letter-spacing: 1rpx; |
||||
|
} |
||||
|
|
||||
|
/* 徽章样式 */ |
||||
|
.required-badge { |
||||
|
background: linear-gradient(135deg, #ff6b6b, #ff4757); |
||||
|
color: white; |
||||
|
font-size: 22rpx; |
||||
|
padding: 4rpx 16rpx; |
||||
|
border-radius: 30rpx; |
||||
|
margin-left: 16rpx; |
||||
|
box-shadow: 0 4rpx 10rpx rgba(255, 71, 87, 0.3); |
||||
|
} |
||||
|
|
||||
|
.optional-badge { |
||||
|
background: linear-gradient(135deg, #a0a0a0, #808080); |
||||
|
color: white; |
||||
|
font-size: 22rpx; |
||||
|
padding: 4rpx 16rpx; |
||||
|
border-radius: 30rpx; |
||||
|
margin-left: 16rpx; |
||||
|
opacity: 0.8; |
||||
|
} |
||||
|
|
||||
|
/* 卡片内容 */ |
||||
|
.card-content { |
||||
|
padding: 0 32rpx 32rpx 32rpx; |
||||
|
} |
||||
|
|
||||
|
.card-content.no-padding { |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
/* 输入框包装器 */ |
||||
|
.input-wrapper, |
||||
|
.textarea-wrapper { |
||||
|
background: #f8fafd; |
||||
|
border-radius: 24rpx; |
||||
|
margin: 0 32rpx 32rpx 32rpx; |
||||
|
border: 2rpx solid transparent; |
||||
|
transition: all 0.3s ease; |
||||
|
box-shadow: inset 0 2rpx 6rpx rgba(0, 0, 0, 0.02); |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
.input-wrapper:focus-within, |
||||
|
.textarea-wrapper:focus-within { |
||||
|
border-color: #07c160; |
||||
|
background: #ffffff; |
||||
|
box-shadow: 0 0 0 6rpx rgba(7, 193, 96, 0.1), inset 0 2rpx 6rpx rgba(0, 0, 0, 0.02); |
||||
|
} |
||||
|
|
||||
|
/* 输入框样式 */ |
||||
|
input, textarea { |
||||
|
width: 100%; |
||||
|
font-size: 30rpx; |
||||
|
color: #1e293b; |
||||
|
padding: 24rpx 28rpx; |
||||
|
background: transparent; |
||||
|
border: none; |
||||
|
outline: none; |
||||
|
} |
||||
|
|
||||
|
textarea { |
||||
|
min-height: 120rpx; |
||||
|
line-height: 1.6; |
||||
|
} |
||||
|
|
||||
|
.placeholder-style { |
||||
|
color: #aab8c5; |
||||
|
font-size: 28rpx; |
||||
|
} |
||||
|
|
||||
|
/* 分类选择器 */ |
||||
|
.picker-trigger { |
||||
|
background: #f8fafd; |
||||
|
padding: 24rpx 28rpx; |
||||
|
border-radius: 24rpx; |
||||
|
font-size: 30rpx; |
||||
|
color: #aab8c5; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
border: 2rpx solid transparent; |
||||
|
transition: all 0.3s ease; |
||||
|
box-shadow: inset 0 2rpx 6rpx rgba(0, 0, 0, 0.02); |
||||
|
} |
||||
|
|
||||
|
.picker-trigger.selected { |
||||
|
color: #1e293b; |
||||
|
border-color: #07c160; |
||||
|
background: #ffffff; |
||||
|
} |
||||
|
|
||||
|
.picker-arrow { |
||||
|
font-size: 28rpx; |
||||
|
color: #94a3b8; |
||||
|
transition: transform 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
/* 标签组 */ |
||||
|
.tag-group { |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
gap: 20rpx; |
||||
|
margin-bottom: 24rpx; |
||||
|
} |
||||
|
|
||||
|
.tag-item { |
||||
|
padding: 16rpx 36rpx; |
||||
|
background: #f1f5f9; |
||||
|
border-radius: 60rpx; |
||||
|
font-size: 28rpx; |
||||
|
color: #475569; |
||||
|
border: 2rpx solid #e2e8f0; |
||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); |
||||
|
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.02); |
||||
|
} |
||||
|
|
||||
|
.tag-item.active { |
||||
|
background: linear-gradient(135deg, #07c160, #059669); |
||||
|
color: white; |
||||
|
border-color: #07c160; |
||||
|
transform: translateY(-2rpx); |
||||
|
box-shadow: 0 10rpx 20rpx rgba(7, 193, 96, 0.3); |
||||
|
} |
||||
|
|
||||
|
/* 已选标签区域 */ |
||||
|
.selected-tags { |
||||
|
margin-top: 24rpx; |
||||
|
padding: 24rpx; |
||||
|
background: linear-gradient(135deg, #f0fdf4, #dcfce7); |
||||
|
border-radius: 24rpx; |
||||
|
border: 2rpx solid rgba(7, 193, 96, 0.2); |
||||
|
} |
||||
|
|
||||
|
.selected-label { |
||||
|
font-size: 26rpx; |
||||
|
color: #059669; |
||||
|
font-weight: 500; |
||||
|
display: block; |
||||
|
margin-bottom: 16rpx; |
||||
|
} |
||||
|
|
||||
|
.selected-tag-list { |
||||
|
display: flex; |
||||
|
flex-wrap: wrap; |
||||
|
gap: 16rpx; |
||||
|
margin-bottom: 16rpx; |
||||
|
} |
||||
|
|
||||
|
.selected-tag-item { |
||||
|
padding: 10rpx 28rpx; |
||||
|
background: white; |
||||
|
border-radius: 40rpx; |
||||
|
font-size: 26rpx; |
||||
|
color: #07c160; |
||||
|
border: 2rpx solid #07c160; |
||||
|
box-shadow: 0 4rpx 10rpx rgba(7, 193, 96, 0.1); |
||||
|
} |
||||
|
|
||||
|
/* 标签字符串预览 */ |
||||
|
.tag-string-preview { |
||||
|
font-size: 26rpx; |
||||
|
color: #475569; |
||||
|
padding: 16rpx; |
||||
|
background: rgba(255, 255, 255, 0.7); |
||||
|
border-radius: 16rpx; |
||||
|
border: 2rpx dashed #07c160; |
||||
|
} |
||||
|
|
||||
|
.tag-string-value { |
||||
|
color: #07c160; |
||||
|
font-weight: 500; |
||||
|
word-break: break-all; |
||||
|
} |
||||
|
|
||||
|
/* 内容区域特殊样式 */ |
||||
|
.content-card .content-textarea { |
||||
|
min-height: 300rpx; |
||||
|
} |
||||
|
|
||||
|
/* 提交区域 */ |
||||
|
.submit-area { |
||||
|
margin-top: 60rpx; |
||||
|
padding-bottom: 40rpx; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.submit-btn { |
||||
|
width: 100%; |
||||
|
height: 96rpx; |
||||
|
background: linear-gradient(135deg, #07c160, #059669); |
||||
|
border-radius: 60rpx; |
||||
|
color: white; |
||||
|
font-size: 36rpx; |
||||
|
font-weight: 600; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
border: none; |
||||
|
box-shadow: 0 20rpx 40rpx rgba(7, 193, 96, 0.3); |
||||
|
transition: all 0.3s ease; |
||||
|
} |
||||
|
|
||||
|
.submit-btn:active { |
||||
|
transform: translateY(-4rpx); |
||||
|
box-shadow: 0 30rpx 50rpx rgba(7, 193, 96, 0.4); |
||||
|
} |
||||
|
|
||||
|
.submit-btn[disabled] { |
||||
|
opacity: 0.7; |
||||
|
transform: none; |
||||
|
box-shadow: 0 10rpx 20rpx rgba(7, 193, 96, 0.2); |
||||
|
} |
||||
|
|
||||
|
.tip-text { |
||||
|
margin-top: 24rpx; |
||||
|
font-size: 26rpx; |
||||
|
color: #94a3b8; |
||||
|
letter-spacing: 2rpx; |
||||
|
} |
||||
|
|
||||
|
/* 动画效果 */ |
||||
|
@keyframes fadeIn { |
||||
|
from { |
||||
|
opacity: 0; |
||||
|
transform: translateY(20rpx); |
||||
|
} |
||||
|
to { |
||||
|
opacity: 1; |
||||
|
transform: translateY(0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.form-card { |
||||
|
animation: fadeIn 0.4s ease-out forwards; |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue