master
panliang 2023-12-09 14:14:22 +08:00
parent 645112d4fe
commit 58c2fdb7a3
18 changed files with 678 additions and 110 deletions

View File

@ -1,3 +1,3 @@
ENV = 'production'
VUE_APP_BASE_API = 'http://www.xbzt.cc'
VUE_APP_BASE_API = 'http://local.party-rank.host'

8
public/.htaccess 100644
View File

@ -0,0 +1,8 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /h5/
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /h5/index.html [L]
</IfModule>

View File

@ -0,0 +1,3 @@
location /h5 {
try_files $uri $uri/h5 /h5/index.html?$query_string;
}

View File

@ -1,5 +1,11 @@
{
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/welcome",
"style": {
"navigationBarTitleText": "五星党建"
}
},
{
"path": "pages/index/index",
"style": {
@ -26,6 +32,21 @@
"navigationBarTitleText" : "填报"
}
},
{
"path" : "pages/score/list",
"style" :
{
"navigationBarTitleText" : "我的填报",
"enablePullDownRefresh": true
}
},
{
"path" : "pages/score/detail",
"style" :
{
"navigationBarTitleText" : "详细"
}
},
{
"path" : "pages/score/user-rank",
"style" :
@ -42,6 +63,13 @@
"navigationBarTextStyle": "black"
}
},
{
"path" : "pages/user/setting",
"style" :
{
"navigationBarTitleText" : "设置"
}
},
{
"path" : "pages/article/detail",
"style" :

View File

@ -5,7 +5,7 @@
</view>
<block v-else>
<view class="title">{{ title }}</view>
<view class="content">
<view class="content rich-text">
<rich-text :nodes="content" />
</view>
</block>

View File

@ -22,18 +22,23 @@
</template>
<script>
import { setToken } from '../../utils/index'
export default {
data() {
return {
username: '',
password: '',
redirect: ''
redirect: '',
openid: '',
open_type: '',
}
},
onLoad(e) {
if (e.redirect) {
this.redirect = e.redirect
}
this.openid = e.openid
this.open_type = e.open_type
},
methods: {
submit() {
@ -50,10 +55,15 @@
})
}
this.$ajax.post('/api/login', { username: this.username, password: this.password }).then(res => {
this.$ajax.post('/api/login', {
username: this.username,
password: this.password,
openid: this.openid,
open_type: this.open_type,
}).then(res => {
if (res.status == 0) {
const token = res.data.token
uni.setStorageSync('party_rank_auth_token', token)
setToken(token)
uni.reLaunch({
url: '/pages/index/index'
})
@ -70,6 +80,10 @@
padding-top: 150rpx;
padding-left: 60rpx;
padding-right: 60rpx;
position: absolute;
width: 100%;
height: 100%;
box-sizing: border-box;
}
.title {
background-color: white;
@ -97,7 +111,7 @@
}
.form .submit {
font-size: 34rpx;
margin-top: 200rpx;
margin: 200rpx 0;
font-weight: 700;
}
</style>

View File

@ -0,0 +1,27 @@
<template>
</template>
<script>
import { setToken } from '../../utils/index'
export default {
data() {
return {}
},
onLoad(e) {
if (e.token) {
setToken(e.token)
uni.reLaunch({
url: '/pages/index/index'
})
} else if (e.reLaunch) {
uni.reLaunch({
url: e.reLaunch
})
} else {
uni.reLaunch({
url: '/pages/auth/login'
})
}
},
}
</script>

View File

@ -2,56 +2,84 @@
<view class="page">
<swiper class="swiper" autoplay circular>
<swiper-item v-for="item in banners" :key="item.id">
<image :src="item.image" style="height: 300rpx;width: 100%;" />
<image :src="item.picture" style="height: 300rpx;width: 100%;" />
</swiper-item>
</swiper>
<view class="app">
<view class="row">
<view v-for="(item, index) in categories" :key="item.id" v-if="index < 2" class="item" @click="navigateTo">
<view class="icon">
<image :src="item.image" />
<block v-for="(item, index) in categories" :key="item.id">
<view v-if="index < 2" class="item" @click="navigateToForm(item.id)">
<view class="icon">
<image :src="item.image" />
</view>
<view class="title">{{ item.name }}</view>
</view>
<view class="title">{{ item.name }}</view>
</view>
</block>
</view>
<view class="row">
<view v-for="(item, index) in categories" :key="item.id" v-if="index >= 2" class="item">
<view class="icon">
<image :src="item.image" />
<block v-for="(item, index) in categories" :key="item.id">
<view v-if="index >= 2" class="item" @click="navigateToForm(item.id)">
<view class="icon">
<image :src="item.image" />
</view>
<view class="title">{{ item.name }}</view>
</view>
<view class="title">{{ item.name }}</view>
</view>
</block>
</view>
</view>
<view class="article">
<view class="article rich-text">
<rich-text :nodes="content" />
</view>
</view>
</template>
<script>
import { isLogin } from '../../utils/index'
export default {
data() {
return {
banners: [
{id: 1, 'image': 'https://via.placeholder.com/800x300.png?text=1'},
{id: 2, 'image': 'https://via.placeholder.com/800x300.png?text=2'},
{id: 3, 'image': 'https://via.placeholder.com/800x300.png?text=3'},
],
categories: [
{id: 1, name: '政治忠诚', image: 'https://via.placeholder.com/100x100.png?text=1'},
{id: 2, name: '政治定力', image: 'https://via.placeholder.com/100x100.png?text=1'},
{id: 3, name: '政治担当', image: 'https://via.placeholder.com/100x100.png?text=1'},
{id: 4, name: '政治能力', image: 'https://via.placeholder.com/100x100.png?text=1'},
{id: 5, name: '政治自律', image: 'https://via.placeholder.com/100x100.png?text=1'},
],
content: '<h1>富文本</h1><p>哈哈哈</p><img src="https://via.placeholder.com/100x100.png"/><p><b>哈哈哈</b></p>'
banners: [],
categories: [],
content: ''
}
},
onLoad() {
if (!isLogin()) {
return uni.showModal({
title: '请先登录',
showCancel: false,
success: () => {
uni.navigateTo({
url: '/pages/auth/login'
})
}
})
}
this.init()
},
methods: {
navigateTo() {
async init() {
uni.showLoading()
let res = await this.$ajax.get('/api/banner', { params: { key: 'banner_2' } })
if (res.status == 0) {
this.banners = res.data
}
res = await this.$ajax.get('/api/keyword', { params: { key: 'score_cate_' } })
if (res.status == 0) {
this.categories = res.data.map(item => ({
...item,
image: item.image ?? '../../static/images/bit2.png'
}))
}
res = await this.$ajax.get('/api/article/cate')
if (res.status == 0) {
this.content = res.data.content
}
uni.hideLoading()
},
navigateToForm(id) {
uni.navigateTo({
url: '/pages/score/form'
url: `/pages/score/form?type=${id}`
})
}
}
@ -77,8 +105,8 @@
}
.app .icon ::v-deep uni-image {
border-radius: 20rpx;
width: 200rpx;
height: 200rpx;
width: 150rpx;
height: 150rpx;
}
.article {
margin: 20rpx;

View File

@ -0,0 +1,49 @@
<template>
<view class="page">
<u-cell-group>
<u-cell title="分类" :value="info.type ? info.type.name : ''"></u-cell>
<u-cell title="主题" :label="info.title"></u-cell>
<u-cell title="内容" :label="info.content"></u-cell>
<u-cell title="图片">
<u-album slot="label" :urls="info.images" />
</u-cell>
<u-cell title="附件" :label="info.file"></u-cell>
<u-cell title="提交时间" :value="info.created_at"></u-cell>
<u-cell title="审核状态" :value="info.check_status_text"></u-cell>
<u-cell title="审核时间" :value="info.check_at"></u-cell>
<u-cell title="审核人" :value="info.check_user ? info.check_user.name : ''"></u-cell>
<u-cell v-if="info.check_status == 2" title="未通过原因" :value="info.check_remarks"></u-cell>
<u-cell v-if="info.check_status == 1" title="得分" :value="info.score"></u-cell>
</u-cell-group>
</view>
</template>
<script>
export default {
data() {
return {
id: '',
info: {}
}
},
onLoad(e) {
this.id = e.id
this.init()
},
methods: {
init() {
this.$ajax.get(`/api/user/score/${this.id}`, { custom: {loading: true}}).then(res => {
if (res.status == 0) {
this.info = res.data
}
})
}
}
}
</script>
<style>
::v-deep .u-cell-group {
background-color: white;
}
</style>

View File

@ -41,6 +41,9 @@
/>
</view>
</u-form-item>
<u-form-item v-if="reason" label="未通过原因" labelPosition="top" labelWidth="auto" borderBottom>
<u-text type="warning" :text="reason" margin="30rpx 0" />
</u-form-item>
<u-form-item>
<button class="btn-danger" @click="submit"></button>
</u-form-item>
@ -53,10 +56,41 @@
export default {
data() {
return {
id: '',
type: '',
title: '',
content: '',
images: [],
files: []
files: [],
reason: ''
}
},
onLoad(e) {
if (e.type) {
this.type = e.type
}
if (e.id) {
this.id = e.id
uni.setNavigationBarTitle({
title: '修改'
})
this.$ajax.get(`/api/user/score/${this.id}`).then(res => {
if (res.status == 0) {
this.title = res.data.title
this.content = res.data.content
if (res.data.images) {
this.images = res.data.images.map((value) => {
return {url: value}
})
}
if (res.data.file) {
this.files = [{ url: res.data.file }]
}
if (res.data.check_status == 2) {
this.reason = res.data.check_remarks
}
}
})
}
},
methods: {
@ -74,29 +108,32 @@
})
})
for (let i = 0; i < lists.length; i++) {
const result = await this.uploadFilePromise(lists[i].url)
const result = await this.$ajax.upload('/api/web/upload', {filePath: lists[i].url, name: 'file'})
let item = this.images[fileListLen]
this.images.splice(fileListLen, 1, Object.assign(item, {
status: 'success',
message: '',
url: result
url: result.data.file
}))
fileListLen++
}
},
uploadFile(event) {
this.files.push(event.file)
const file = event.file
file.status = 'uploading'
file.message = '上传中'
this.$ajax.upload('/api/web/upload', {filePath: file.url, name: 'file'}).then(res => {
if (res.status == 0) {
file.status = 'success'
file.message = ''
file.url = res.data.file
this.files.push(file)
}
})
},
deleteFile(event) {
this.files.splice(event.index, 1)
},
uploadFilePromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('https://via.placeholder.com/100x100.png')
}, 1000)
})
},
submit() {
if (!this.title) {
return uni.showToast({
@ -104,6 +141,24 @@
icon: 'error'
})
}
const params = {
type_id: this.type,
title: this.title,
content: this.content,
images: this.images.length > 0 ? this.images.map(item => { return item.url }) : null,
file: this.files.length > 0 ? this.files[0].url : null
}
this.$ajax.post('/api/user/score', params, { custom: {loading: true} }).then(res => {
if (res.status == 0) {
uni.showToast({
title: '提交成功',
icon: 'success'
})
setTimeout(() => {
uni.navigateBack()
}, 800)
}
})
}
}
}

View File

@ -0,0 +1,189 @@
<template>
<view class="page">
<u-sticky bgColor="#ffffff">
<u-subsection :list="options" mode="subsection" keyName="name" :current="current" @change="changeOption" />
</u-sticky>
<view v-if="list.length == 0" class="empty">
<u-empty />
</view>
<view v-if="list.length > 0" class="list">
<u-list :height="listHeight" @scrolltolower="reachBottom">
<u-list-item v-for="item in list" :key="item.id">
<u-cell>
<view class="title" slot="title">
<view class="name1">{{ item.title }}</view>
<view class="name2" :class="{
'text-gray': item.check_status == 0,
'text-warning': item.check_status == 2,
'text-success': item.check_status == 1,
}">{{ item.check_status_text }}</view>
</view>
<view slot="label">
<view class="labels">
<view class="label">提交时间: {{ item.created_at }}</view>
<view v-if="item.check_status > 0" class="label">: {{ item.check_at }}</view>
<view v-if="item.check_status == 1" class="label">得分: <text class="text-success">+{{ item.score }}</text></view>
<view v-if="item.check_status == 2" class="label">: <u-text type="error" :text="item.check_remarks" /></view>
</view>
<view class="options">
<u-button text="详细" type="info" @click="show(item.id)" />
<u-button v-if="item.check_status != 1" text="修改" type="error" @click="edit(item.id)" />
<u-button v-if="item.check_status != 1" text="删除" type="error" plain @click="deleteItem(item.id)" />
</view>
</view>
</u-cell>
</u-list-item>
</u-list>
</view>
</view>
</template>
<script>
export default {
data() {
return {
options: [
{name: '待审核', status: 0},
{name: '审核通过', status: 1},
{name: '未通过', status: 2}
],
current: 0,
list: [],
page: 1,
perPage: 20,
total: 0,
listHeight: 0,
}
},
onLoad() {
this.loadData(true)
uni.getSystemInfo({
success: (res) => {
this.listHeight = res.safeArea.height - 54
}
})
},
onPullDownRefresh() {
this.loadData(true)
},
methods: {
loadData(refresh) {
if (refresh) {
this.list = []
this.page = 1
}
const params = {
page: this.page,
perPage: this.perPage,
check_status: this.options[this.current].status,
}
this.$ajax.get('/api/user/score', { params , custom: {loading: true}}).then(res => {
uni.stopPullDownRefresh()
if (res.status == 0) {
this.list = this.list.concat(res.data)
this.total = res.meta.total
}
}).catch(error => {
uni.stopPullDownRefresh()
})
},
reachBottom() {
if (this.list.length < this.total) {
this.page++
this.loadData()
}
},
changeOption(index) {
this.current = index
this.loadData(true)
},
edit(id) {
uni.navigateTo({
url: `/pages/score/form?id=${id}`
})
},
show(id) {
uni.navigateTo({
url: `/pages/score/detail?id=${id}`
})
},
deleteItem(id) {
uni.showModal({
title: '删除记录',
content: '删除后不可恢复, 是否确定?',
success: (result) => {
if (result.confirm) {
console.log(id)
this.$ajax.delete(`/api/user/score/${id}`, { custom: {loading: true}}).then(res => {
if (res.status == 0) {
this.loadData(true)
}
})
}
}
})
}
}
}
</script>
<style>
.page ::v-deep .u-sticky {
padding: 20rpx;
}
.list ::v-deep .u-list-item {
background-color: white;
margin-top: 20rpx;
}
.list .title {
display: flex;
justify-content: space-between;
}
.list .name1 {
font-weight: bold;
}
.list .name2 {
width: 100rpx;
text-align: center;
margin-left: 5rpx;
}
.list .text-gray {
color: #999;
}
.list .text-warning {
color: #f0ad4e;
}
.list .text-success {
color: #4cd964;
}
.list .labels {
margin-top: 15rpx;
color: #999;
border-top: 1px solid #ECECEC;
padding: 10rpx 0;
}
.list .label {
margin-top: 10rpx;
}
.list .options {
border-top: 1px solid #ECECEC;
margin-top: 15rpx;
padding-top: 10rpx;
display: flex;
justify-content: end;
}
.list .u-button {
margin: 0 5px;
width: 120rpx;
}
.empty {
position: absolute;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
margin-top: 20rpx;
background-color: white;
}
</style>

View File

@ -6,14 +6,14 @@
<view class="bg2"></view>
</view>
<view class="box">
<view class="title">
<view class="title" @click="setting">
<view class="left">
<view class="avatar">
<image src="https://via.placeholder.com/64x64.png">
<image :src="user.avatar">
</view>
<view class="name">
<view class="name1">党员1</view>
<view class="name2">党支部1</view>
<view class="name1">{{ user.name }}</view>
<view class="name2">{{ user.cate_name }}</view>
</view>
</view>
<view class="icon flex">
@ -22,17 +22,17 @@
</view>
<view class="list">
<view class="item">
<view class="number">10</view>
<view class="number">{{ user.current_score }}</view>
<view class="text">当前得星</view>
</view>
<view class="border"></view>
<view class="item">
<view class="number">10</view>
<view class="number">{{ user.rank }}</view>
<view class="text">总排名</view>
</view>
<view class="border"></view>
<view class="item">
<view class="number">10</view>
<view class="number">{{ user.score }}</view>
<view class="text">累计得星</view>
</view>
</view>
@ -42,62 +42,120 @@
<view id="echart" style="height: 250px;width: 330px;"></view>
</view>
<view class="options">
<view class="item">
<view class="flex">
<view class="icon">
<image src="https://via.placeholder.com/64x64.png">
</view>
<view class="title">我的填报</view>
</view>
<view class="badge">
<image src="../../static/images/arrow-right.png" style="width: 20rpx; height: 20rpx;" />
</view>
</view>
<u-cell-group>
<u-cell title="我的填报" isLink @click="scoreList" />
</u-cell-group>
</view>
<view class="logout">
<u-button text="退出" type="error" @click="logout" />
</view>
</view>
</template>
<script>
import * as echarts from 'echarts';
import { setToken } from '../../utils/index'
export default {
data() {
return {
user: {
name: '',
cate_name: '',
avatar: '',
current_score: 0,
score: 0,
rank: '-'
}
}
},
onLoad() {
this.$nextTick(() => {
this.init()
})
this.init()
},
methods: {
init() {
async init() {
uni.showLoading()
let res = await this.$ajax.get('/api/user/profile')
let radarValue = {}
if (res.status == 0) {
this.user.name = res.data.name
this.user.cate_name = res.data.cate_name
this.user.avatar = res.data.avatar ?? '../../static/images/default-avatar.png'
this.user.current_score = res.data.current_score
this.user.score = res.data.score
radarValue = res.data.scores
}
res = await this.$ajax.get('/api/rank/current', { params: { type: 'user' } })
if (res.status == 0) {
this.user.rank = res.data.rank
}
res = await this.$ajax.get('/api/keyword', { params: { key: 'score_cate_' } })
let radarIndicator = [
{ name: '政治忠诚' },
{ name: '政治定力' },
{ name: '政治担当' },
{ name: '政治能力' },
{ name: '政治自律' },
]
let radarValues = []
if (res.status == 0) {
radarIndicator = res.data.map(item => {
radarValues.push(radarValue[item.key])
return {key: item.key, name: item.name}
})
}
uni.hideLoading()
var option = {
radar: {
indicator: [
{ name: '政治忠诚', max: 50 },
{ name: '政治定力', max: 50 },
{ name: '政治担当', max: 50 },
{ name: '政治能力', max: 50 },
{ name: '政治自律', max: 50 },
]
indicator: radarIndicator
},
series: [
{
type: 'radar',
areaStyle: {
opacity: 0.9
},
data: [
{
value: [33, 14, 28, 26, 42],
value: radarValues,
}
]
}
]
};
var chartElement = echarts.init(document.getElementById('echart'));
chartElement.setOption(option)
this.$nextTick(() => {
this.chart(option)
})
},
chart(option) {
if (document.getElementById('echart')) {
var chartElement = echarts.init(document.getElementById('echart'));
chartElement.setOption(option)
}
},
logout() {
uni.showModal({
title: '是否确定?',
content: '退出登录',
success: (res) => {
if (res.confirm) {
this.$ajax.get('/api/logout').then(res => {
if (res.status == 0) {
setToken('')
uni.reLaunch({
url: '/pages/auth/login'
})
}
})
}
}
})
},
setting() {
uni.navigateTo({
url: '/pages/user/setting'
})
},
scoreList() {
uni.navigateTo({
url: '/pages/score/list'
})
}
}
}
@ -190,21 +248,11 @@
}
.options {
margin-top: 10rpx;
}
.options .item {
padding: 10rpx;
background-color: white;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #dddddd;
}
.options .title {
margin-left: 15rpx;
}
.options .icon ::v-deep uni-image {
border-radius: 10rpx;
width: 60rpx;
height: 60rpx;
.logout {
margin-top: 20rpx;
padding: 0 20rpx;
}
</style>

View File

@ -0,0 +1,98 @@
<template>
<view class="page">
<u-cell-group>
<u-cell title="头像" isLink @click="chooseAvatar">
<view slot="value">
<u-avatar :src="user.avatar" />
</view>
</u-cell>
<u-cell title="姓名" :value="user.name" isLink @click="openModal('姓名', 'name')" />
<u-cell title="党支部" :value="user.cate_name" />
</u-cell-group>
<u-modal
:show="modal.show"
:title="modal.title"
:showCancelButton="true"
:closeOnClickOverlay="true"
:asyncClose="true"
@confirm="confirmModal"
@cancel="closeModal"
@close="closeModal"
>
<u--input v-model="modal.value" border="surround" />
</u-modal>
</view>
</template>
<script>
export default {
data() {
return {
user: {
avatar: '../../static/images/default-avatar.png',
name: '',
cate_name: '',
},
modal: {
type: 'text',
show: false,
title: '',
key: '',
value: ''
},
}
},
onLoad() {
this.$ajax.get('/api/user/profile', {custom: {loading: true}}).then(res => {
if (res.status == 0) {
this.user = res.data
}
})
},
methods: {
chooseAvatar() {
uni.chooseImage({
count: 1,
success: (result) => {
this.$ajax.upload('/api/web/upload', {filePath: result.tempFilePaths[0],name: 'file'}).then(res => {
if (res.status == 0) {
this.update('avatar', res.data.file)
}
})
}
})
},
openModal(title, name) {
this.modal.title = title
this.modal.key = name
this.modal.show = true
this.modal.value = this.user[name]
},
confirmModal() {
const key = this.modal.key
const value = this.modal.value
this.update(key, value)
this.modal.show = false
},
closeModal() {
this.modal.show = false
},
update(key, value) {
const params = {}
params[key] = value
this.$ajax.post('/api/user/profile', params, {custom: {loading: true}}).then(res => {
if (res.status == 0) {
this.user[key] = value
}
})
}
}
}
</script>
<style>
.page {
background-color: white;
}
</style>

View File

@ -3,10 +3,6 @@
}
.page {
background-color: #efefef;
/* position: absolute;
width: 100%;
height: 100%;
box-sizing: border-box; */
}
.flex {
@ -18,4 +14,14 @@
.btn-danger {
color: white;
background-color: #C20000;
}
}
.rich-text {
word-break: break-all;
overflow-wrap: break-word;
line-height: 1.6;
}
.rich-text img {
width: 100%;
height: 100%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1,3 +1,11 @@
export function isLogin() {
return !!uni.getStorageSync('party_rank_auth_token')
}
}
export function setToken(value) {
uni.setStorageSync('party_rank_auth_token', value)
}
export function getToken() {
return uni.getStorageSync('party_rank_auth_token')
}

View File

@ -1,4 +1,6 @@
// http 网络请求
// import { getToken } from './index'
const { getToken } = require('./')
module.exports = () => {
// 全局配置
@ -14,7 +16,7 @@ module.exports = () => {
// 请求拦截
uni.$u.http.interceptors.request.use(
(config) => {
const token = uni.getStorageSync('party_rank_auth_token')
const token = getToken()
if (token) {
config.header['Authorization'] = `Bearer ${token}`
}
@ -32,25 +34,30 @@ module.exports = () => {
// 响应拦截
uni.$u.http.interceptors.response.use(
(response) => {
uni.hideLoading()
if (response.config.custom.loading) {
uni.hideLoading()
}
const res = response.data
if (res.status == 401) {
return uni.reLaunch({
url: '/pages/auth/login'
})
}
if (response.config.custom.toast && res.status != 0 && res.doNotDisplayToast != 1) {
uni.showModal({
title: res.msg,
showCancel: false
})
}
if (res.code == 401) {
uni.reLaunch({
url: '/pages/auth/login'
})
}
return res
},
(response) => {
uni.hideLoading()
console.log(response)
if (response.config?.custom.loading) {
uni.hideLoading()
}
return Promise.reject(response)
}
)