ts_aimz_uni/pages/copyright/applyRepair/applyRepair.vue
2025-06-24 14:08:30 +08:00

613 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-container">
<swiper indicator-dots style="height: 120rpx;" autoplay indicator-active-color="#fff">
<swiper-item>
<image :src="imgAssets+'/banner_1.png'" style="width: 100vw;height: 120rpx;"></image>
</swiper-item>
<swiper-item>
<image :src="imgAssets+'/banner_2.png'" style="width: 100vw;height: 120rpx;"></image>
</swiper-item>
</swiper>
<view class="apply-box">
<text class="label">补正信息</text>
<view class="apply-item-row mt-20 ml-10">
<view class="apply-title star" style="align-self: center;">补正软著</view>
<view class="apply-content" @click="showSelProDialog">
<view :class="selPro == null? 'text-hint':'text-sel'">
{{selPro==null? '请选择需要补正的软著' :selPro.projName}}
</view>
<view class="icon-arrow-solid"></view>
</view>
</view>
<view class="apply-item-row mt-20 ml-10">
<view class="apply-title star" style="align-self: center;">补正种类</view>
<view class="apply-content" @click="showSelTypeDialog">
<view :class="selType==null?'text-hint':'text-sel'">{{selType==null?'请选择种类':selType.title}}
</view>
<view class="icon-arrow-solid"></view>
</view>
</view>
<view class="apply-item-column mt-20 ml-10">
<view class="apply-title star">补正原因</view>
<textarea @input="inputRemark" :value="remark" placeholder="请输入补正原因"
placeholder-style="font-size:28rpx;color:$text-gray-hint-color"
class="reason-content mt-10"></textarea>
</view>
<view class="apply-item-column mt-20 ml-10">
<view class="apply-title star">补正凭证</view>
<view class="mt-10">
<uni-file-picker ref="imgPicker" :value="files" :del-icon="true" limit="4" fileMediatype="image"
@delete="delImgs" :auto-upload="false" :image-styles="imageStyles"
@select="uploadImgToNet"></uni-file-picker>
</view>
<view class="hint">
*上传完整的补正通知书或者完整的补正通知书的截图,要求右上方的流水号和右下方的补正通知书的日期都得完整显示
</view>
</view>
</view>
<view class="bottom-fixed-footer">
<view class="bottom-btn-green" @click="doApply">提交</view>
</view>
<!-- 可以补正的项目dialog -->
<uni-popup ref="proDialog" type="bottom" background-color="#fff" border-radius="15rpx 15rpx 0rpx 0rpx">
<view class="bottom-dialog-container">
<view class="dialog-title-box">
<view class="search-container">
<input placeholder="请输入项目名称" :value="proKeywords" @input="inputSearchPro" class="search-input"
type="text" @confirm="doSearchKeyWord" confirm-type="search" />
</view>
<view class="icon-close size-48" @click="closeDialog"></view>
</view>
<view style="height: 600rpx;" class="mt-10">
<containerLoadingVue :loadingVisible="loadingState">
<scroll-view scroll-y style="height: 580rpx;" :lower-threshold="10" @doRefresh="doRefreshList"
refresher-background="#FFFFFF00" @scrolltolower="doLoadMore">
<view class="pro-list-box">
<radio-group @change="bindChangeSelPro">
<view v-for="(item,index) in proList" :key="index" class="pro-list-item"
:data-value="item">
<radio :value="item.projId"
:checked="tempSelPro != null && tempSelPro.projId==item.projId">
</radio>
<view class="pro-list-item-left" @click="choosePro" :data-value="item">
<view class="pro-list-item-left-title">
<view class="pro-list-name single-line">{{item.projName}}</view>
<rich-text class="pro-list-item-left-count"
:nodes="'已通过补正<span style=color:red;font-size:28rpx;font-weight:bold;>'+ item.approvedCount+'</span>次'"></rich-text>
</view>
<view class="pro-list-item-left-footer">
<view class="pro-list-item-left-tag">{{item.gmtCreate}}</view>
<view class="pro-list-item-left-tag single-line">
{{item.authorName}}
</view>
</view>
</view>
</view>
</radio-group>
<uni-load-more :status="hasMore"></uni-load-more>
</view>
</scroll-view>
</containerLoadingVue>
</view>
<view class="bottom-btn-green mb-20" @click="confirmSelPro">确定</view>
</view>
</uni-popup>
<!-- 类型 -->
<uni-popup ref="typeDialog" type="bottom" background-color="#fff" border-radius="15rpx 15rpx 0rpx 0rpx">
<view class="bottom-dialog-container">
<view class="dialog-title-box">
<view class="icon-close size-48" @click="closeDialog"></view>
<view class="dialog-title-txt has-icon">补正种类</view>
</view>
<view style="height: 600rpx;" class="mt-10">
<view class="pro-list-box">
<radio-group>
<block v-for="(item,index) in typeList" :key="index">
<view class="pro-list-item">
<radio :checked="tempSelType != null&& tempSelType.value==item.value"></radio>
<view class="pro-list-item-left" @click="chooseType" :data-value="item">
<view class="pro-list-item-left-title">
<view class="pro-list-name">{{item.title}}</view>
</view>
</view>
</view>
</block>
</radio-group>
</view>
</view>
<view class="bottom-btn-green" @click="confirmSelType">确定</view>
</view>
</uni-popup>
<uni-popup type="message" ref="msg">
<uni-popup-message :type="msgType" :message="msgHint" :duration="2000"></uni-popup-message>
</uni-popup>
</view>
</template>
<script>
import ProApi from '@/common/js/net/projectApi.js'
import containerLoadingVue from '../../../components/container-loading.vue'
import {
kindList
} from '@/common/js/data.js'
import {
uploadImgUrl,
previewUrl
} from '../../../common/js/net/mainUrl'
import {
get
} from '@/common/js/cache/storage.js'
import {
inject
} from 'vue';
export default {
components: {
containerLoadingVue
},
setup() {
const globalData = inject('globalData')
return {
globalData
}
},
data() {
return {
imgAssets: this.globalData.imgAssetsUrl,
msgHint: '',
msgType: '',
msgShow: false,
selPro: null,
selType: null,
files: [],
proList: [],
tempSelPro: null,
typeList: kindList,
showSelPro: false,
showSelType: false,
tempSelType: null,
remark: '',
proKeywords: '',
proPageData: {
page: 1,
rows: 10,
keywords: ''
},
listRefreshTrig: false,
loadingState: 'loading',
hasMore: 'more',
imageStyles: {
width: 72,
height: 72,
border: {
color: "#F5F5F5",
width: 1,
style: 'solid',
radius: '2px'
}
},
primaryColor: this.globalData.primaryColor,
};
},
onLoad(options) {
uni.setNavigationBarTitle({
title: "补正申请",
});
uni.setNavigationBarColor({
frontColor: "#000000",
backgroundColor: "#F0F0F0",
animation: {
duration: 500,
timingFunc: "easeIn",
},
});
},
methods: {
inputSearchPro(e) {
this.proKeywords = e.detail.value
},
inputRemark(e) {
this.remark = e.detail.value
},
showSelProDialog() {
const _self = this
_self.doRefreshList()
_self.tempSelPro = _self.selPro
_self.$refs.proDialog.open()
},
showSelTypeDialog() {
this.tempSelType = this.selType
this.$refs.typeDialog.open()
},
chooseType(e) {
this.tempSelType = e.currentTarget.dataset.value
},
closeDialog() {
this.$refs.proDialog.close()
this.$refs.typeDialog.close()
},
confirmSelPro() {
if (this.tempSelPro == null) {
this.msgHint = '请选择补正项目'
this.msgType = 'error'
this.$refs.msg.open()
} else {
this.$refs.proDialog.close()
this.selPro = this.tempSelPro
this.tempSelPro = null
}
},
//确定种类
confirmSelType() {
this.selType = this.tempSelType
this.tempSelType = null
this.$refs.typeDialog.close()
},
doSearchKeyWord() {
this.doRefreshList()
},
//刷新
doRefreshList() {
const _self = this
_self.loadingState = 'loading'
_self.hasMore = 'more'
_self.isLoadMore = false
_self.proPageData.page = 1
_self.proPageData.keywords = _self.proKeywords
_self.getCanRefundList(true)
},
//加载更多
doLoadMore() {
//判断是否正在加载中 与是否存在更多数据
const _self = this
if (_self.isLoadMore || _self.hasMore == 'noMore') {
return
}
_self.isLoadMore = true
_self.hasMore = 'loading'
_self.proPageData.page = ++_self.proPageData.page
_self.proPageData.keywords = _self.proKeywords
_self.getCanRefundList(false)
},
getCanRefundList(isRefresh) {
const _self = this
_self.proList = isRefresh ? [] : _self.proList
_self.loadingState = isRefresh ? 'loading' : ''
ProApi.doGetCanProRepairList(_self.proPageData)
.then(res => {
console.log(res)
var status = 'success'
status = res.rows && res.rows.length > 0 ? 'success' : 'empty'
_self.loadingState = isRefresh ? status : ''
_self.proList = _self.proList.concat(res.rows)
_self.isLoadMore = false
_self.hasMore = _self.proList.length < res.total ? 'more' : 'noMore'
})
.catch(err => {
_self.loadingState = 'error'
_self.isLoadMore = false
_self.hasMore = 'more'
})
},
bindChangeSelPro(e) {
const id = e.detail.value;
const selectedItem = this.proList.find(item => item.projId === id);
this.tempSelPro = selectedItem
},
choosePro(e) {
this.tempSelPro = e.currentTarget.dataset.value
},
//删除图片
delImgs(e) {
console.log('删除凭证', e)
this.files.splice(e.index, 1)
},
//上传图片
async uploadImgToNet(e) {
uni.showLoading({
title: '上传中...'
})
const tempFilePaths = e.tempFilePaths;
const token = get('token');
const header = token ? {
Auth: `Bearer ${token}`
} : {};
const that = this;
try {
// 创建一个数组存储上传结果
const results = [];
// 串行上传(一个完成后再上传下一个)
for (let i = 0; i < tempFilePaths.length; i++) {
const filePath = tempFilePaths[i];
// 使用 Promise 封装 uni.uploadFile
const result = await new Promise((resolve, reject) => {
uni.uploadFile({
url: uploadImgUrl,
header: header,
filePath: filePath,
name: 'image',
success(res) {
if (res.statusCode === 200) {
let data = res.data;
if (typeof data === 'string') {
data = JSON.parse(data);
}
resolve(data.data);
} else {
reject(new Error('上传失败状态码非200'));
}
},
fail(err) {
reject(err);
}
});
});
// 按顺序添加到结果数组
result.url = previewUrl + result.fileId
result.name = result.fileName
let lastDot = result.fileName.lastIndexOf('.')
result.extname = result.fileName.substring(lastDot + 1);
results.push(result);
}
// 全部上传成功后更新文件列表
that.files = that.files.concat(results);
uni.hideLoading();
} catch (error) {
uni.hideLoading();
that.msgHint = '凭证上传失败,请稍后重试';
that.msgType = 'error';
that.$refs.msg.open();
// 清空已选择的文件
that.$refs.imgPicker.clearFiles();
console.error('上传错误:', error);
}
},
//提交申请
doApply() {
const legal = this.checkParams()
if (legal) {
const _self = this
uni.showLoading({
title: '提交中...',
})
const ids = _self.files.map(item => item.fileId).join(',');
const data = {
correctionReason: _self.remark,
correctionType: _self.selType.value,
correctionVoucher: ids,
projId: _self.selPro.projId
}
ProApi.doApplyProRepair(data)
.then(res => {
uni.hideLoading()
_self.msgHint = '提交操作已顺利完成,我们会尽快审核,还请耐心等待'
_self.msgType = 'success'
_self.$refs.msg.open()
setTimeout(()=>{
_self.backPageRefresh()
},1500)
})
.catch(err => {
uni.hideLoading()
_self.msgHint = err.msg ? err.msg : '提交失败,请稍后重试'
_self.msgType = 'error'
_self.$refs.msg.open()
})
}
},
checkParams() {
const _self = this
if (_self.selPro == null) {
_self.msgHint = '请选择补正软著'
_self.msgType = 'error'
_self.$refs.msg.open()
return false
}
if (_self.selType == null) {
_self.msgHint = '请选择补正种类'
_self.msgType = 'error'
_self.$refs.msg.open()
return false
}
if (_self.remark == '') {
_self.msgHint = '请输入补正原因'
_self.msgType = 'error'
_self.$refs.msg.open()
return false
}
if (_self.files.length <= 0) {
_self.msgHint = '请上传补正凭证'
_self.msgType = 'error'
_self.$refs.msg.open()
return false
}
return true
},
backPageRefresh() {
var pages = getCurrentPages()
let prevPage = pages[pages.length - 2];
prevPage.$vm.needRefresh = true
uni.navigateBack()
}
},
};
</script>
<style lang="scss" scoped>
.apply-box {
margin-top: 20rpx;
display: flex;
flex-direction: column;
padding: 30rpx;
background-color: $white-color;
border-radius: 10rpx;
}
.label {
font-size: 32rpx;
font-weight: bold;
}
.apply-item-row {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.apply-item-column {
display: flex;
flex-direction: column;
}
.apply-title {
font-size: 28rpx;
color: $text-color;
flex: 0.3;
}
.apply-content {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
flex: 0.7;
background-color: $bg-gray-input-color;
padding: 10rpx 15rpx;
font-size: 28rpx;
border-radius: 15rpx;
}
.reason-content {
border-radius: 15rpx;
height: 120rpx;
background-color: $bg-gray-input-color;
font-size: 28rpx;
padding: 20rpx;
}
.text-hint {
color: $text-gray-hint-color;
}
.text-sel {
color: $text-color;
}
.hint {
margin-top: 10rpx;
font-size: 26rpx;
color: $red-color;
}
.pro-list-box {
display: flex;
flex-direction: column;
}
.pro-list-item {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
border-radius: 10rpx;
padding: 30rpx;
margin: 10rpx;
border-bottom: 1rpx solid $divider-color;
}
.pro-list-item:nth-of-type(n+2) {
margin-top: 20rpx;
}
.pro-list-item:last-of-type {
border-bottom: none;
}
.pro-list-item-left {
display: flex;
flex-direction: column;
flex: 1;
margin-left: 30rpx;
}
.pro-list-item-left-title {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.pro-list-item-left-footer {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 20rpx;
}
.pro-list-item-left-count {
font-size: 24rpx;
color: $text-color;
flex-wrap: nowrap;
margin-top: 4rpx;
}
.pro-list-item-left-tag {
font-size: 24rpx;
color: $text-color;
flex: .5;
}
.pro-list-name {
font-size: 26rpx;
font-weight: bold;
flex: 1;
}
.search-container {
position: relative;
align-self: center;
border-radius: 5px;
background-color: $bg-gray-color;
padding: 5px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 100%;
margin-right: 20rpx;
}
.search-input {
box-sizing: border-box;
color: $text-color;
font-size: 28rpx;
text-align: center;
flex: 1;
background-color: $bg-gray-input-color;
border-radius: 10rpx;
}
.search-input::after {
content: '';
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
width: 20px;
height: 20px;
margin-top: -1px;
background-size: cover;
background-image: url('data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSI2NCA2NCA4OTYgODk2IiB3aWR0aD0iMTQiIGhlaWdodD0iMTkiIHN0eWxlPSIiIGZpbHRlcj0ibm9uZSI+CiAgICAKICAgIDxnPgogICAgPHBhdGggZD0iTTkwOS42IDg1NC41TDY0OS45IDU5NC44QzY5MC4yIDU0Mi43IDcxMiA0NzkgNzEyIDQxMmMwLTgwLjItMzEuMy0xNTUuNC04Ny45LTIxMi4xLTU2LjYtNTYuNy0xMzItODcuOS0yMTIuMS04Ny45cy0xNTUuNSAzMS4zLTIxMi4xIDg3LjlDMTQzLjIgMjU2LjUgMTEyIDMzMS44IDExMiA0MTJjMCA4MC4xIDMxLjMgMTU1LjUgODcuOSAyMTIuMUMyNTYuNSA2ODAuOCAzMzEuOCA3MTIgNDEyIDcxMmM2NyAwIDEzMC42LTIxLjggMTgyLjctNjJsMjU5LjcgMjU5LjZhOC4yIDguMiAwIDAgMCAxMS42IDBsNDMuNi00My41YTguMiA4LjIgMCAwIDAgMC0xMS42ek01NzAuNCA1NzAuNEM1MjggNjEyLjcgNDcxLjggNjM2IDQxMiA2MzZzLTExNi0yMy4zLTE1OC40LTY1LjZDMjExLjMgNTI4IDE4OCA0NzEuOCAxODggNDEyczIzLjMtMTE2LjEgNjUuNi0xNTguNEMyOTYgMjExLjMgMzUyLjIgMTg4IDQxMiAxODhzMTE2LjEgMjMuMiAxNTguNCA2NS42UzYzNiAzNTIuMiA2MzYgNDEycy0yMy4zIDExNi4xLTY1LjYgMTU4LjR6IiBmaWxsPSJyZ2JhKDIwNCwyMDQsMjA0LDEpIj48L3BhdGg+CiAgICA8L2c+CiAgPC9zdmc+');
}
.pro-list-item-left-count {
font-size: 24rpx;
color: $text-color;
flex-wrap: nowrap;
margin-top: 4rpx;
}
:deep(.file-picker__progress) {
display: none !important;
}
</style>