持续集成分支
100
library/project/fd/AppAnswer/Add.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div class="add">
|
||||
<textarea placeholder="请输入" :maxlength="500" v-model="content"></textarea>
|
||||
|
||||
<div class="answer-btn">
|
||||
<div @click="submit">提问</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
appName: '提问',
|
||||
|
||||
data () {
|
||||
return {
|
||||
id: '',
|
||||
content: ''
|
||||
}
|
||||
},
|
||||
|
||||
onLoad (query) {
|
||||
if (query.id) {
|
||||
this.id = query.id
|
||||
|
||||
this.getInfo(query.id)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo (id) {
|
||||
this.$http.post(`/app/applearningquestion/queryDetailById?id=${id}`).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.content = res.data.content
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
submit () {
|
||||
if (!this.content) {
|
||||
return this.$u.toast('请输入题目内容')
|
||||
}
|
||||
|
||||
this.$loading()
|
||||
this.$http.post(`/app/applearningquestion/addOrUpdate`, {
|
||||
content: this.content,
|
||||
id: this.id || ''
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$u.toast('提交成功')
|
||||
uni.$emit('update')
|
||||
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.add {
|
||||
padding-top: 32px;
|
||||
|
||||
textarea {
|
||||
width: 718px;
|
||||
height: 640px;
|
||||
margin: 0 auto;
|
||||
padding: 32px 16px;
|
||||
font-size: 32px;
|
||||
color: #333;
|
||||
border-radius: 32px;
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.answer-btn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 11;
|
||||
width: 100%;
|
||||
padding: 16px 32px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
background: #F3F5F9;
|
||||
|
||||
div {
|
||||
height: 88px;
|
||||
line-height: 88px;
|
||||
background: #3975C6;
|
||||
border-radius: 44px;
|
||||
font-size: 34px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
116
library/project/fd/AppAnswer/AppAnswer.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div class="AppAnswer">
|
||||
<div class="tab-wrapper">
|
||||
<div class="tab">
|
||||
<span :class="[component === 'List' ? 'active' : '']" @click="change('List')">问题</span>
|
||||
<span :class="[component === 'Ranking' ? 'active' : '']" @click="change('Ranking')">排行</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="AppAnswer-body">
|
||||
<component :is="component" :ref="component"></component>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import List from './component/List'
|
||||
import Ranking from './component/Ranking'
|
||||
|
||||
export default {
|
||||
name: 'AppAnswer',
|
||||
appName: '学习问答',
|
||||
data() {
|
||||
return {
|
||||
detail: {},
|
||||
list: [],
|
||||
wxLogin: 0,
|
||||
current: 1,
|
||||
total: 0,
|
||||
component: 'List'
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
List,
|
||||
Ranking
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
},
|
||||
|
||||
onLoad () {
|
||||
uni.$on('update', () => {
|
||||
this.$refs.List.update()
|
||||
})
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
|
||||
},
|
||||
|
||||
handleDetail (id) {
|
||||
if (!this.user.token) this.wxLogin++
|
||||
else uni.navigateTo({url: './voteDetail?id=' + id})
|
||||
},
|
||||
|
||||
change (type) {
|
||||
this.component = type
|
||||
}
|
||||
},
|
||||
|
||||
onReachBottom () {
|
||||
this.$refs[this.component].getMore()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnswer {
|
||||
min-height: 100vh;
|
||||
background: #F3F5F9;
|
||||
|
||||
.tab-wrapper {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 11;
|
||||
background: #3975C6;
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 112px;
|
||||
border-radius: 50px 50px 0 0;
|
||||
padding: 0 256px;
|
||||
background: #F3F5F9;
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
line-height: 1;
|
||||
color: #999999;
|
||||
font-size: 40px;
|
||||
|
||||
&.active {
|
||||
color: #000000;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
z-index: 0;
|
||||
opacity: 0.8;
|
||||
left: 50%;
|
||||
width: 80px;
|
||||
height: 12px;
|
||||
background-image: linear-gradient(90deg, #46C0FF 0%, #0C85FF 100%);
|
||||
transform: translateX(-50%);
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
112
library/project/fd/AppAnswer/IntegralDetail.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="integralDetail">
|
||||
<div class="item" v-for="(item, index) in list" :key="index">
|
||||
<div class="left">
|
||||
<h2>{{ item.changeDesc }}</h2>
|
||||
<p>{{ item.createTime }}</p>
|
||||
</div>
|
||||
<span>+{{ item.changeScore }}</span>
|
||||
</div>
|
||||
<AiEmpty v-if="!list.length && isMore"></AiEmpty>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
appName: '积分明细',
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 20
|
||||
},
|
||||
isMore: false,
|
||||
list: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
getList () {
|
||||
if (this.isMore) return
|
||||
this.$http.post(`/app/applearningquestion/scoreDetail`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
sysUserId: this.user.id
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (this.search.current > 1) {
|
||||
this.list = [...this.list, ...res.data.records]
|
||||
} else {
|
||||
this.list = res.data.records
|
||||
}
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
if (res.data.records.length < 20) {
|
||||
this.isMore = true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
this.search.current = this.search.current + 1
|
||||
} else {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}).catch(() => {
|
||||
uni.hideLoading()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onReachBottom () {
|
||||
this.current = this.current + 1
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.integralDetail {
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 20px 24px;
|
||||
border-bottom: 1px solid #eee;
|
||||
background: #fff;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
h2 {
|
||||
line-height: 1;
|
||||
margin-bottom: 12px;
|
||||
font-size: 34px;
|
||||
font-weight: 500;
|
||||
font-size: #333;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 28px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 36px;
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
265
library/project/fd/AppAnswer/Search.vue
Normal file
@@ -0,0 +1,265 @@
|
||||
<template>
|
||||
<div class="AppAnswerList">
|
||||
<div class="search-wrapper">
|
||||
<div class="search">
|
||||
<image src="./img/search.png" />
|
||||
<input placeholder="请输入" v-model="content" @confirm="onChange">
|
||||
<image v-if="content" src="./img/close.png" @click="content = '', onChange()" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-wrapper">
|
||||
<div class="item" v-for="(item, index) in list" :key="index" @click="linkTo('./answerList?id=' + item.id)">
|
||||
<div class="item-title">
|
||||
<i>{{ item.createUserId === user.id ? '我' : item.createUserName }} </i>
|
||||
<span>于{{ item.createTime }} 提问</span>
|
||||
</div>
|
||||
<p v-html="item.content"></p>
|
||||
<div class="item-bottom">
|
||||
<div class="left">
|
||||
<span>共</span>
|
||||
<i>{{ item.answerCount }}</i>
|
||||
<span>条回答</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span @click.stop="linkTo('./Add?id=' + item.id)" v-if="item.createUserId === user.id && item.answerCount === 0">修改问题</span>
|
||||
<span @click.stop="linkTo('./answerAdd')">去回答</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AiEmpty v-if="!list.length"></AiEmpty>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
appName: '学习问答',
|
||||
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
size: 10
|
||||
},
|
||||
content: '',
|
||||
isMore: false,
|
||||
list: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
},
|
||||
|
||||
mounted () {
|
||||
},
|
||||
|
||||
methods: {
|
||||
linkTo (url) {
|
||||
uni.navigateTo({
|
||||
url
|
||||
})
|
||||
},
|
||||
|
||||
onChange () {
|
||||
this.current = 1
|
||||
this.isMore = false
|
||||
|
||||
this.getList()
|
||||
},
|
||||
|
||||
getMore () {
|
||||
this.current = this.current + 1
|
||||
|
||||
this.getList()
|
||||
},
|
||||
|
||||
update () {
|
||||
this.current = 1
|
||||
this.isMore = false
|
||||
|
||||
this.getList()
|
||||
},
|
||||
|
||||
getList () {
|
||||
if (this.isMore) return
|
||||
this.$http.post(`/app/applearningquestion/list`, null, {
|
||||
params: {
|
||||
...this.search,
|
||||
content: this.content || ''
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (this.search.current > 1) {
|
||||
this.list = [...this.list, ...res.data.records.map(v => {
|
||||
if (v.content.indexOf(this.content) > -1) {
|
||||
v.content = v.content.replaceAll(this.content, `<i style="font-style: normal; color: #3975C6;" class="keyworld">${this.content}</i>`)
|
||||
}
|
||||
|
||||
return v
|
||||
})]
|
||||
} else {
|
||||
this.list = res.data.records.map(v => {
|
||||
if (v.content.indexOf(this.content) > -1) {
|
||||
v.content = v.content.replaceAll(this.content, `<i style="font-style: normal; color: #3975C6;" class="keyworld">${this.content}</i>`)
|
||||
}
|
||||
|
||||
return v
|
||||
})
|
||||
}
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
if (res.data.records.length < 10) {
|
||||
this.isMore = true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
this.search.current = this.search.current + 1
|
||||
} else {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}).catch(() => {
|
||||
uni.hideLoading()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onReachBottom () {
|
||||
this.current = this.current + 1
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnswerList {
|
||||
padding: 0 32px 20px;
|
||||
|
||||
.search-wrapper {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 11;
|
||||
padding: 20px 0;
|
||||
background: #F3F5F9;
|
||||
}
|
||||
|
||||
.search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 64px;
|
||||
padding: 0 32px;
|
||||
border-radius: 16px;
|
||||
background: #fff;
|
||||
|
||||
image {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
input {
|
||||
flex: 1;
|
||||
font-size: 26px;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
|
||||
.answer-btn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 11;
|
||||
width: 100%;
|
||||
padding: 16px 32px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
background: #F3F5F9;
|
||||
|
||||
div {
|
||||
height: 88px;
|
||||
line-height: 88px;
|
||||
background: #3975C6;
|
||||
border-radius: 44px;
|
||||
font-size: 34px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
.list-wrapper {
|
||||
padding-bottom: 40px;
|
||||
|
||||
.item {
|
||||
margin-bottom: 24px;
|
||||
padding: 24px;
|
||||
border-radius: 16px;
|
||||
background: #fff;
|
||||
|
||||
.keyworld {
|
||||
font-style: normal;
|
||||
color: #3975C6;
|
||||
}
|
||||
|
||||
.item-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 48px;
|
||||
|
||||
.right {
|
||||
span {
|
||||
height: 56px;
|
||||
line-height: 56px;
|
||||
margin-right: 24px;
|
||||
padding: 0 16px;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #FF883C;
|
||||
color: #FF883C;
|
||||
border-radius: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
color: #3975C6;
|
||||
border: 1px solid #3975C6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 28px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
color: #3975C6;;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.3;
|
||||
font-size: 34px;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
font-size: 28px;
|
||||
color: #999;
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
color: #3975C6;;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
117
library/project/fd/AppAnswer/answerAdd.vue
Normal file
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<div class="answerAdd">
|
||||
<div class="input_box">
|
||||
<u-input v-model="form.content" type="textarea" height="580" maxlength="10000"
|
||||
:clearable="false" placeholder="请输入回答内容" :auto-height="true" placeholder-style="color: '#AAAAAA';font-size: 16px" />
|
||||
</div>
|
||||
|
||||
<div class="upload">
|
||||
<h4>图片上传<span>(最多9张)</span></h4>
|
||||
<AiUploader :def.sync="form.files" multiple placeholder="上传图片" :limit="9" action="/admin/file/add2"></AiUploader>
|
||||
</div>
|
||||
|
||||
<div class="submitBtn">
|
||||
<div class="btn" @click="submit">提交</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "answerAdd",
|
||||
appName: "进行回答",
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
qid: '',
|
||||
content: '',
|
||||
files: []
|
||||
},
|
||||
flag: false,
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
if(this.flag) return
|
||||
|
||||
if(!this.form.content) {
|
||||
return this.$u.toast('请输入回答内容')
|
||||
}
|
||||
this.flag = true
|
||||
this.$loading()
|
||||
this.$http.post(`/app/applearningquestion/addOrUpdateAnswer`, {
|
||||
...this.form
|
||||
}).then(res=> {
|
||||
if(res?.code==0) {
|
||||
this.$u.toast('提交成功!')
|
||||
uni.$emit('update')
|
||||
setTimeout(()=> {
|
||||
uni.navigateBack()
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
onLoad(o) {
|
||||
if(o.qid) {
|
||||
this.form.qid = o?.qid
|
||||
}
|
||||
if(o.data) {
|
||||
this.form = JSON.parse(o?.data)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.answerAdd {
|
||||
padding: 32px 32px 130px 32px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.input_box,
|
||||
.upload {
|
||||
width: 100%;
|
||||
background: #FFF;
|
||||
border-radius: 32px;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.upload {
|
||||
margin-top: 24px;
|
||||
h4 {
|
||||
font-weight: 400;
|
||||
font-size: 32px;
|
||||
color: #666666;
|
||||
margin-bottom: 24px;
|
||||
span {
|
||||
color: #999999;
|
||||
font-size: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.submitBtn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
background: #F3F5F9;
|
||||
padding: 16px 32px;
|
||||
box-sizing: border-box;
|
||||
z-index: 9;
|
||||
.btn {
|
||||
background: #3975C6;
|
||||
width: 100%;
|
||||
border-radius: 44px;
|
||||
height: 88px;
|
||||
line-height: 88px;
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
font-size: 34px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
148
library/project/fd/AppAnswer/answerDetail.vue
Normal file
@@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<div class="answerDetail">
|
||||
<div class="head">
|
||||
<div class="left">
|
||||
<img :src="info.createUserAvatar" alt="">
|
||||
<div class="head_avtar">
|
||||
<h4>{{ info.createUserName }}</h4>
|
||||
<div class="col-999">{{ info.createUserDeptName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right col-999">{{ info.createTime }}</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
{{ info.content }}
|
||||
</div>
|
||||
<div class="picture">
|
||||
<img :src="item.url" v-for="(item,index) in info.files" :key="index" alt=""
|
||||
@click="preview(info.files, item.url)">
|
||||
</div>
|
||||
<div class="btn_box" v-if="info.createUserId == user.id">
|
||||
<div class="del" @click="deleteBtn(info.id)">删除</div>
|
||||
<div class="edit" @click="editBtn()">修改</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: "answerDetail",
|
||||
appName: "Ta的回答",
|
||||
data() {
|
||||
return {
|
||||
info: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
methods: {
|
||||
editBtn() {
|
||||
uni.navigateTo({
|
||||
url: './answerAdd?data=' + JSON.stringify(this.info)
|
||||
})
|
||||
},
|
||||
deleteBtn(id) {
|
||||
this.$confirm('确定要删除该回答吗?').then(()=> {
|
||||
this.$http.post(`/app/applearningquestion/deleteAnswer?id=${id}`).then(res=> {
|
||||
if(res?.code == 0) {
|
||||
this.$u.toast('删除成功!')
|
||||
setTimeout(()=> {
|
||||
uni.navigateBack()
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
preview(images, img) {
|
||||
uni.previewImage({
|
||||
urls: images.map(v => v.url),
|
||||
current: img
|
||||
})
|
||||
},
|
||||
},
|
||||
onLoad(o) {
|
||||
this.info = JSON.parse(o.data)
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.answerDetail {
|
||||
padding: 24px 32px 120px 32px;
|
||||
box-sizing: border-box;
|
||||
background: #FFF;
|
||||
|
||||
.head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.left {
|
||||
display: flex;
|
||||
width: calc(100% - 280px);
|
||||
img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin-right: 16px;
|
||||
border-radius: 40px;
|
||||
}
|
||||
.head_avtar {
|
||||
max-width: calc(100% - 96px);
|
||||
}
|
||||
}
|
||||
.col-999 {
|
||||
color: #999999;;
|
||||
}
|
||||
}
|
||||
|
||||
.content{
|
||||
width: 100%;
|
||||
word-break: break-all;
|
||||
font-size: 28px;
|
||||
color: #333;
|
||||
line-height: 44px;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.picture {
|
||||
margin-top: 24px;
|
||||
img {
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn_box {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
padding: 16px 32px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
background: #f3f5f7;
|
||||
z-index: 9;
|
||||
div {
|
||||
flex: 1;
|
||||
border-radius: 44px;
|
||||
text-align: center;
|
||||
line-height: 88px;
|
||||
font-size: 34px;
|
||||
}
|
||||
.del {
|
||||
margin-right: 30px;
|
||||
border: 1px solid #E23C3C;
|
||||
color: #E23C3C;
|
||||
}
|
||||
|
||||
.edit {
|
||||
border: 1px solid #3975C6;
|
||||
color: #3975C6;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
211
library/project/fd/AppAnswer/answerList.vue
Normal file
@@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<div class="answerList">
|
||||
<div class="answer_title">
|
||||
{{ info.content }}
|
||||
</div>
|
||||
<p class="answer_tips">已有<span>{{ answersArr.length }}</span>条回答</p>
|
||||
|
||||
<div class="answer_card" v-for="item in answersArr" :key="item.id">
|
||||
<div @click="toDetail(item)">
|
||||
<div class="card_head">
|
||||
<div class="left">
|
||||
<img :src="item.createUserAvatar" alt="">
|
||||
<div class="card_head_avtar">
|
||||
<h4>{{ item.createUserName }}</h4>
|
||||
<div>{{ item.createUserDeptName }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">{{ item.createTime }}</div>
|
||||
</div>
|
||||
<div class="card_body" :class="item.createUserId != user.id? 'card_radius':''">
|
||||
<div class="card_content">
|
||||
{{ item.content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card_btn" v-if="item.createUserId == user.id">
|
||||
<div @click="toEdit(item)">修改</div>
|
||||
<div @click="deleteBtn(item.id)">删除</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AiEmpty v-if="!answersArr.length" description="暂无数据"></AiEmpty>
|
||||
|
||||
<div class="btn" @click="toAdd(info.id)">去回答</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
name: 'answerList',
|
||||
appName: '学习问答',
|
||||
data() {
|
||||
return {
|
||||
id: '',
|
||||
info: {},
|
||||
answersArr: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['user'])
|
||||
},
|
||||
methods: {
|
||||
getDetail() {
|
||||
this.$http.post(`/app/applearningquestion/queryDetailById?id=${this.id}`).then(res=> {
|
||||
if(res?.data) {
|
||||
this.info = res.data
|
||||
this.answersArr = res.data.answers
|
||||
}
|
||||
})
|
||||
},
|
||||
toDetail(data) {
|
||||
uni.navigateTo({
|
||||
url: './answerDetail?data=' + JSON.stringify(data)
|
||||
})
|
||||
},
|
||||
deleteBtn(id) {
|
||||
this.$confirm('确定要删除该回答吗?').then(()=> {
|
||||
this.$http.post(`/app/applearningquestion/deleteAnswer?id=${id}`).then(res=> {
|
||||
if(res?.code == 0) {
|
||||
this.$u.toast('删除成功!')
|
||||
setTimeout(()=> {
|
||||
this.getDetail()
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
toEdit(data) {
|
||||
uni.navigateTo({
|
||||
url: './answerAdd?data=' + JSON.stringify(data)
|
||||
})
|
||||
},
|
||||
toAdd(id) {
|
||||
uni.navigateTo({url: `./answerAdd?qid=${id}`})
|
||||
},
|
||||
},
|
||||
onLoad(o) {
|
||||
this.id = o.id
|
||||
},
|
||||
onShow() {
|
||||
this.getDetail()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.answerList {
|
||||
padding: 32px 32px 120px 32px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.answer_title {
|
||||
font-weight: 500;
|
||||
font-size: 34px;
|
||||
color: #000000;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.answer_tips {
|
||||
font-size: 28px;
|
||||
font-weight: 400;
|
||||
color: #999999;
|
||||
padding: 8px 0 48px 0;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 2px solid #E4E5E6;
|
||||
span {
|
||||
color: #3975C6;
|
||||
}
|
||||
}
|
||||
|
||||
.answer_card {
|
||||
margin-top: 32px;
|
||||
.card_head {
|
||||
background: #FFF;
|
||||
padding: 24px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
border-radius: 16px 16px 0 0;
|
||||
.left {
|
||||
display: flex;
|
||||
width: calc(100% - 280px);
|
||||
img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 40px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
.card_head_avtar {
|
||||
max-width: calc(100% - 96px);
|
||||
h4,
|
||||
div {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
|
||||
.card_body {
|
||||
background: #FFF;
|
||||
padding: 0 24px 24px 24px;
|
||||
box-sizing: border-box;
|
||||
|
||||
|
||||
.card_content {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 5;
|
||||
}
|
||||
}
|
||||
|
||||
.card_radius {
|
||||
border-radius: 0 0 16px 16px;
|
||||
}
|
||||
|
||||
.card_btn {
|
||||
background: #FFF;
|
||||
height: 88px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 0 0 16px 16px;
|
||||
border-top: 2px solid #E4E5E6;
|
||||
div {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
font-size: 28px;
|
||||
color: #687DA6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
left: 50%;
|
||||
transform: translate(-50%,0);
|
||||
width: 320px;
|
||||
height: 88px;
|
||||
line-height:88px;
|
||||
border-radius: 44px;
|
||||
background: #3975C6;
|
||||
text-align: center;
|
||||
font-weight: 500;
|
||||
font-size: 34px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
240
library/project/fd/AppAnswer/component/List.vue
Normal file
@@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<div class="AppAnswerList">
|
||||
<div class="search-wrapper">
|
||||
<div class="search" @click="linkTo('./Search')">
|
||||
<image src="../img/search.png" />
|
||||
<div>请输入</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-wrapper">
|
||||
<div class="item" v-for="(item, index) in list" :key="index" @click="linkTo('./answerList?id=' + item.id)">
|
||||
<div class="item-title">
|
||||
<i>{{ item.createUserId === user.id ? '我' : item.createUserName }} </i>
|
||||
<span>于{{ item.createTime }} 提问</span>
|
||||
</div>
|
||||
<p>{{ item.content }}</p>
|
||||
<div class="item-bottom">
|
||||
<div class="left">
|
||||
<span>共</span>
|
||||
<i>{{ item.answerCount }}</i>
|
||||
<span>条回答</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span @click.stop="linkTo('./Add?id=' + item.id)" v-if="item.createUserId === user.id && item.answerCount === 0">修改问题</span>
|
||||
<span @click.stop="linkTo(`./answerAdd?qid=${item.id}`)">去回答</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<AiEmpty v-if="!list.length && isMore"></AiEmpty>
|
||||
</div>
|
||||
<div class="answer-btn">
|
||||
<div @click="linkTo('./Add')">提问</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
title: '',
|
||||
size: 10
|
||||
},
|
||||
isMore: false,
|
||||
list: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$loading()
|
||||
this.getList()
|
||||
},
|
||||
|
||||
methods: {
|
||||
linkTo (url) {
|
||||
uni.navigateTo({
|
||||
url
|
||||
})
|
||||
},
|
||||
|
||||
getMore () {
|
||||
this.current = this.current + 1
|
||||
|
||||
this.getList()
|
||||
},
|
||||
|
||||
update () {
|
||||
this.current = 1
|
||||
this.isMore = false
|
||||
|
||||
this.getList()
|
||||
},
|
||||
|
||||
getList () {
|
||||
if (this.isMore) return
|
||||
this.$http.post(`/app/applearningquestion/list`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (this.search.current > 1) {
|
||||
this.list = [...this.list, ...res.data.records]
|
||||
} else {
|
||||
this.list = res.data.records
|
||||
}
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
if (res.data.records.length < 10) {
|
||||
this.isMore = true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
this.search.current = this.search.current + 1
|
||||
} else {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}).catch(() => {
|
||||
uni.hideLoading()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.AppAnswerList {
|
||||
padding: 0 32px 120px;
|
||||
|
||||
.search-wrapper {
|
||||
position: sticky;
|
||||
top: 112px;
|
||||
z-index: 11;
|
||||
padding: 0 0 20px 0;
|
||||
background: #F3F5F9;
|
||||
}
|
||||
|
||||
.search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 64px;
|
||||
padding: 0 32px;
|
||||
border-radius: 16px;
|
||||
background: #fff;
|
||||
|
||||
image {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
div {
|
||||
font-size: 26px;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
|
||||
.answer-btn {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 11;
|
||||
width: 100%;
|
||||
padding: 16px 32px;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
background: #F3F5F9;
|
||||
|
||||
div {
|
||||
height: 88px;
|
||||
line-height: 88px;
|
||||
background: #3975C6;
|
||||
border-radius: 44px;
|
||||
font-size: 34px;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
.list-wrapper {
|
||||
padding-bottom: 40px;
|
||||
|
||||
.item {
|
||||
margin-bottom: 24px;
|
||||
padding: 24px;
|
||||
border-radius: 16px;
|
||||
background: #fff;
|
||||
|
||||
.item-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 48px;
|
||||
|
||||
.right {
|
||||
span {
|
||||
height: 56px;
|
||||
line-height: 56px;
|
||||
margin-right: 24px;
|
||||
padding: 0 16px;
|
||||
background: #FFFFFF;
|
||||
border: 1px solid #FF883C;
|
||||
color: #FF883C;
|
||||
border-radius: 8px;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
color: #3975C6;
|
||||
border: 1px solid #3975C6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 28px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
color: #3975C6;;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
display: -webkit-box;
|
||||
line-height: 1.3;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
font-size: 34px;
|
||||
overflow: hidden;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
font-size: 28px;
|
||||
color: #999;
|
||||
|
||||
i {
|
||||
font-style: normal;
|
||||
color: #3975C6;;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
219
library/project/fd/AppAnswer/component/Ranking.vue
Normal file
@@ -0,0 +1,219 @@
|
||||
<template>
|
||||
<div class="ranking">
|
||||
<div class="list-data">
|
||||
<div class="item" v-for="(item, index) in list" :key="index">
|
||||
<div class="flex-left">
|
||||
<div class="item-rank">
|
||||
<img :src="imgList[index]" alt="" v-if="index < 3">
|
||||
<span v-else>{{index+1}}</span>
|
||||
</div>
|
||||
<div class="item-user">
|
||||
<img :src="item.avatar || 'https://cdn.cunwuyun.cn/wxmp/tianfuxing/avatar.png'" alt="">{{item.name}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-right">{{item.score}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<AiEmpty description="暂无数据" v-if="!list.length"/>
|
||||
<div class="list-data footer">
|
||||
<div class="item" @click="linkTo">
|
||||
<div class="flex-left">
|
||||
<div class="item-rank">
|
||||
<span>{{ info['积分排行'] }}</span>
|
||||
</div>
|
||||
<div class="item-user">
|
||||
<img :src="user.avatar || 'https://cdn.cunwuyun.cn/wxmp/tianfuxing/avatar.png'" alt="">{{ user.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-right">
|
||||
<span>{{ info['累计获取积分'] }}</span>
|
||||
<image class="right" src="../img/right.png" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
search: {
|
||||
current: 1,
|
||||
title: '',
|
||||
size: 100
|
||||
},
|
||||
isMore: false,
|
||||
barStyle: {
|
||||
'width': '24px',
|
||||
'height': '3px',
|
||||
'border-radius': '2px',
|
||||
'bottom': '0px',
|
||||
'background-color': '#3399FF'
|
||||
},
|
||||
activeStyle: {
|
||||
'font-weight' : '400',
|
||||
'color': '#000000'
|
||||
},
|
||||
imgList: [require('../img/top0.png'),require('../img/top1.png'),require('../img/top2.png')],
|
||||
info: {},
|
||||
list: []
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['user']),
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$loading()
|
||||
this.getList()
|
||||
this.getInfo()
|
||||
},
|
||||
|
||||
methods: {
|
||||
linkTo () {
|
||||
uni.navigateTo({
|
||||
url: './IntegralDetail'
|
||||
})
|
||||
},
|
||||
|
||||
getInfo () {
|
||||
this.$http.post(`/app/applearningquestion/myScore`).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.info = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getList () {
|
||||
if (this.isMore) return
|
||||
this.$http.post(`/app/applearningquestion/scoreRanking`, null, {
|
||||
params: {
|
||||
...this.search
|
||||
}
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
if (this.search.current > 1) {
|
||||
this.list = [...this.list, ...res.data.records]
|
||||
} else {
|
||||
this.list = res.data.records
|
||||
}
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
if (res.data.records.length < 100) {
|
||||
this.isMore = true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
this.search.current = this.search.current + 1
|
||||
} else {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}).catch(() => {
|
||||
uni.hideLoading()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onReachBottom () {
|
||||
this.current = this.current + 1
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.ranking {
|
||||
min-height: 100%;
|
||||
background-color: #F3F5F9;
|
||||
padding-bottom: 32px;
|
||||
|
||||
.list-data {
|
||||
padding: 32px;
|
||||
margin-bottom: 80px;
|
||||
.item {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 24px 48px 24px 32px;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
border-radius: 32px;
|
||||
margin-bottom: 16px;
|
||||
.flex-left {
|
||||
display: flex;
|
||||
.item-rank {
|
||||
width: 152px;
|
||||
img {
|
||||
padding-top: 12px;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
span {
|
||||
line-height: 80px;
|
||||
font-family: SFPro-SNaNpxiboldItalic;
|
||||
font-weight: SemiboldItalic;
|
||||
font-size: 40px;
|
||||
color: #DDD;
|
||||
}
|
||||
}
|
||||
.item-user {
|
||||
line-height: 80px;
|
||||
font-family: PingFangSC-Medium;
|
||||
font-weight: 500;
|
||||
font-size: 32px;
|
||||
color: #333;
|
||||
img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
margin-right: 16px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
.flex-right {
|
||||
font-family: SFPro-SNaNpxibold;
|
||||
font-weight: 600;
|
||||
font-size: 36px;
|
||||
color: #FF9343;
|
||||
line-height: 42px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
padding: 0;
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
||||
.item {
|
||||
border-radius: 0;
|
||||
margin-bottom: 0;
|
||||
padding: 24px 14px 24px 32px;
|
||||
|
||||
&:active {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
|
||||
.flex-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
BIN
library/project/fd/AppAnswer/img/avatar.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
library/project/fd/AppAnswer/img/close.png
Normal file
|
After Width: | Height: | Size: 838 B |
BIN
library/project/fd/AppAnswer/img/right.png
Normal file
|
After Width: | Height: | Size: 974 B |
BIN
library/project/fd/AppAnswer/img/search.png
Normal file
|
After Width: | Height: | Size: 806 B |
BIN
library/project/fd/AppAnswer/img/top0.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
library/project/fd/AppAnswer/img/top1.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
library/project/fd/AppAnswer/img/top2.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |