39 changed files with 2003 additions and 1172 deletions
@ -1,149 +0,0 @@ |
|||
--- |
|||
kind: pipeline |
|||
type: docker |
|||
name: dev |
|||
|
|||
# 挂载的主机卷,可以映射到docker容器中 |
|||
volumes: |
|||
# maven构建缓存(宿主机目录) |
|||
- name: ssh_key |
|||
host: |
|||
path: /root/.ssh/ |
|||
- name: cache |
|||
host: |
|||
path: /var/lib/cache |
|||
- name: data |
|||
host: |
|||
path: /var/lib/data |
|||
|
|||
steps: |
|||
# - name: restore-cache |
|||
# image: drillster/drone-volume-cache |
|||
# volumes: |
|||
# - name: cache |
|||
# path: /cache |
|||
# settings: |
|||
# restore: true |
|||
# mount: |
|||
# - ./node_modules |
|||
|
|||
- name: build |
|||
image: node:latest |
|||
pull: if-not-exists # default always |
|||
# volumes: |
|||
# - name: cache |
|||
# path: /root/.m2 |
|||
commands: |
|||
- npm config set registry http://registry.npm.taobao.org |
|||
- npm i |
|||
- npm run test |
|||
|
|||
# - name: rebuild-cache |
|||
# image: drillster/drone-volume-cache |
|||
# volumes: |
|||
# - name: cache |
|||
# path: /cache |
|||
# settings: |
|||
# rebuild: true |
|||
# mount: |
|||
# - ./node_modules |
|||
|
|||
- name: deploy-scp |
|||
image: appleboy/drone-scp |
|||
pull: if-not-exists |
|||
volumes: |
|||
- name: ssh_key |
|||
path: /root/.ssh/ |
|||
settings: |
|||
host: test.tall.wiki |
|||
port: 22 |
|||
username: root |
|||
key_path: /root/.ssh/id_rsa |
|||
rm: true # true则会删除目标目录重建 |
|||
target: /home/tall/v4.0.0 |
|||
source: dist/* |
|||
strip_components: 1 # 去除的目录层数,如果没有该选项,则拷贝过去是 target/xxx.jar,1代表去除target |
|||
|
|||
# - name: run-ssh |
|||
# image: appleboy/drone-ssh |
|||
# pull: if-not-exists |
|||
# volumes: |
|||
# - name: ssh_key |
|||
# path: /root/.ssh/ |
|||
# settings: |
|||
# settings: |
|||
# host: test.tall.wiki |
|||
# port: 22 |
|||
# username: root |
|||
# key_path: /root/.ssh/id_rsa |
|||
# script_stop: true # stop script after first failure |
|||
# #command_timeout: 30s # 30seconds, the maximum amount of time for the execute commands, default is 10 minutes. |
|||
# script: |
|||
# - cd /home/iacd-platform-drone |
|||
# - ./re.sh > /dev/null 2> /dev/null & |
|||
|
|||
- name: notify-email |
|||
image: drillster/drone-email |
|||
pull: if-not-exists |
|||
settings: |
|||
host: smtp.qiye.aliyun.com #例如 smtp.qq.com |
|||
port: 465 #例如QQ邮箱端口465 |
|||
username: devops@ccsens.com #邮箱用户名 |
|||
password: #邮箱密码 |
|||
from_secret: orgsecret_password_mail_devops |
|||
from: devops@ccsens.com |
|||
recipients: weizezhao@ccsens.com #收件人,多个用,隔开 |
|||
when: #执行条件 |
|||
status: |
|||
- success |
|||
- changed |
|||
- failure |
|||
|
|||
- name: notify-wechatwork |
|||
image: fifsky/drone-wechat-work |
|||
pull: if-not-exists |
|||
settings: |
|||
url: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=b2b93e9a-128b-41d4-8dce-12004e3f48b9 |
|||
msgtype: markdown |
|||
content: | |
|||
{{if eq .Status "success" }} |
|||
#### 🎉 ${DRONE_REPO} 构建成功 |
|||
> Commit: [${DRONE_COMMIT_MESSAGE}](${DRONE_COMMIT_LINK}) |
|||
> Author: ${DRONE_COMMIT_AUTHOR} |
|||
> [点击查看](${DRONE_BUILD_LINK}) |
|||
{{else}} |
|||
#### ❌ ${DRONE_REPO} 构建失败 |
|||
> Commit: [${DRONE_COMMIT_MESSAGE}](${DRONE_COMMIT_LINK}) |
|||
> Author: ${DRONE_COMMIT_AUTHOR} |
|||
> 请立即修复!!! |
|||
> [点击查看](${DRONE_BUILD_LINK}) |
|||
{{end}} |
|||
when: |
|||
status: |
|||
- failure |
|||
- success |
|||
|
|||
trigger: |
|||
branch: feat |
|||
# - name: notify-dingtalk |
|||
# image: lddsb/drone-dingtalk-message |
|||
# environment: |
|||
# PASSWORD: |
|||
# from_secret: password_mail_devops |
|||
# settings: |
|||
# token: your-dingtalk-robot-access-token |
|||
# type: markdown |
|||
# message_color: true |
|||
# message_pic: true |
|||
# sha_link: true |
|||
|
|||
# -name: notify-slack |
|||
# image: plugins/slack |
|||
# webhook: https://hooks.slack.com/ www.dijiuyy.com services/xxx/xxx/xxx |
|||
# channel: dev |
|||
# template: > |
|||
# {{#success build.status}} |
|||
# build {{build.number}} succeeded. Good job. |
|||
# {{else}} |
|||
# build {{build.number}} failed. Fix me please. |
|||
# {{/success}} |
|||
@ -0,0 +1,10 @@ |
|||
import store from '@/store/index'; |
|||
|
|||
const fullPath = store.getters['finance/fullPath']; |
|||
console.log('fullPath: ', fullPath); |
|||
|
|||
export function setupFinance(app) { |
|||
uni.$u.api = { ...uni.$u.api } || {}; |
|||
// 根据任务id获取财务条信息
|
|||
uni.$u.api.getFinanceByTask = taskDetailId => uni.$u.post(`${fullPath}/getByTask`, { taskDetailId }); |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
import Config from '@/common/js/config.js'; |
|||
|
|||
const { apiUrl } = Config; |
|||
const defaultwbs = `${apiUrl}/defaultwbs`; |
|||
|
|||
export function setupMock(app) { |
|||
uni.$u.api = { ...uni.$u.api } || {}; |
|||
|
|||
// 删除交付物
|
|||
uni.$u.api.deleteDeliver = param => |
|||
new Promise((resolve, reject) => { |
|||
setTimeout(() => { |
|||
resolve(); |
|||
}, 100); |
|||
}); |
|||
|
|||
// uni.$u.api.getFinanceByTask = taskDetailId => new Promise((resolve, reject) => {
|
|||
// setTimeout(() => {
|
|||
// resolve({
|
|||
// financeId: '123',
|
|||
// budget: 1000 * 1000,
|
|||
// bonus: 200 * 1000,
|
|||
// projectExpend: 500 * 1000,
|
|||
// dailyExpend: 500 * 1000,
|
|||
// });
|
|||
// }, 100);
|
|||
// });
|
|||
} |
|||
@ -1,38 +1,88 @@ |
|||
// 默认主题文件 |
|||
.theme-default { |
|||
background-color: #F3F3F3; |
|||
background-color: #007aff; |
|||
// color: #fff; |
|||
background-color: #f3f3f3; |
|||
.u-card { |
|||
font-size: 16px !important; |
|||
background-color: #F3F3F3 !important; |
|||
.deliverHead{ |
|||
align-items: center; |
|||
} |
|||
.btns u-button{ |
|||
margin: 0 !important; |
|||
} |
|||
.active{ |
|||
background-color: #2979FF; |
|||
color: #FFFFFF; |
|||
} |
|||
.mask{ |
|||
position:absolute; |
|||
top: 0; |
|||
left:0; |
|||
width: 100%; |
|||
height: 100%; |
|||
z-index: 100; |
|||
} |
|||
background-color: #f3f3f3 !important; |
|||
|
|||
.mask { |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
z-index: 100; |
|||
} |
|||
} |
|||
.u-navbar { |
|||
background-color: #007aff !important; |
|||
color: #fff; |
|||
.uicon-nav-back { |
|||
color: #fff !important; |
|||
// 弹出层 内容盒子 |
|||
.modal-content-wrap { |
|||
position: absolute; |
|||
left: 50rpx; |
|||
top: 50%; |
|||
width: 650rpx; |
|||
transform: translate3d(0, -50%, 0); |
|||
background-color: #fff; |
|||
|
|||
.modal-content-head { |
|||
text-align: center; |
|||
margin-top: 40rpx; |
|||
margin-bottom: 20rpx; |
|||
font-size: 16px; |
|||
font-weight: 600; |
|||
} |
|||
.modal-content-body { |
|||
padding: 32rpx; |
|||
|
|||
// 审核插件 |
|||
.common-list { |
|||
height: 12.5rem; |
|||
overflow-y: scroll; |
|||
view { |
|||
border-bottom: 1px solid #e5e7eb; |
|||
|
|||
&:last-child { |
|||
border-bottom: none; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.modal-content-foot { |
|||
display: flex; |
|||
border-top: 1px solid #d1d5db; |
|||
|
|||
.cancel, |
|||
.confirm { |
|||
flex: 1; |
|||
text-align: center; |
|||
@extend .leading-12; |
|||
} |
|||
.cancel { |
|||
border-right: 1px solid #d1d5db; |
|||
} |
|||
.confirm { |
|||
@extend .text-blue-700; |
|||
} |
|||
// .leading-12 flex-1 text-center delete-modal-border |
|||
} |
|||
|
|||
uni-textarea { |
|||
width: 596rpx; |
|||
height: 140rpx; |
|||
box-sizing: border-box !important; |
|||
} |
|||
} |
|||
button{ |
|||
border: none!important; |
|||
|
|||
.link-box { |
|||
:deep(.u-input__input) { |
|||
color: #60a5fa; |
|||
} |
|||
} |
|||
|
|||
.progress-dot { |
|||
width: 50rpx; |
|||
height: 50rpx; |
|||
border-radius: 50%; |
|||
line-height: 50rpx; |
|||
background-color: #fa8c16; |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,13 @@ |
|||
<template> |
|||
<view @click="openLink" class="break-all text-blue-400 text-xs my-1"> {{ link }} </view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
const props = defineProps({ link: String }); |
|||
|
|||
function openLink() { |
|||
uni.navigateTo({ |
|||
url: `/pages/detailWebview/detailWebview?url=${props.link}`, |
|||
}); |
|||
} |
|||
</script> |
|||
@ -1,91 +1,66 @@ |
|||
<template> |
|||
<view class="deliverFoot border border-solid border-gray-300 rounded-md mt-3 p-2"> |
|||
<view class="top flex justify-between"> |
|||
<view class="mr-3"> |
|||
审核人 |
|||
</view> |
|||
<!-- 展示选择的审核人 --> |
|||
<view class="flex approver item-center truncate justify-end flex-1 text-sm" v-show="isUicon"> |
|||
<view v-for="item in computedDelivers"> |
|||
<view v-show="item.checked" class="mx-1"> |
|||
{{item.name}} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 点击更换图标 --> |
|||
<view> |
|||
<u-icon v-if="isUicon" name="arrow-down" @click="changeIcon"></u-icon> |
|||
<u-icon v-else="isUicon" name="arrow-up" @click="changeIcon"></u-icon> |
|||
</view> |
|||
</view> |
|||
<!-- 隐藏的审核人选项 --> |
|||
<view v-show="!isUicon" class="foot mt-2 flex flex-wrap"> |
|||
<u-button |
|||
v-for="item in delivers" |
|||
size="mini" class="my-1 mx-2" |
|||
@click="item.checked = !item.checked" |
|||
:class="item.checked ? 'active' : '' " |
|||
> |
|||
{{item.name}} |
|||
</u-button> |
|||
</view> |
|||
</view> |
|||
<view class="border border-solid border-gray-300 rounded-md mt-3 p-2" @click="collapsed = !collapsed"> |
|||
<view class="top flex justify-between"> |
|||
<view class="mr-3 text-sm">审核人</view> |
|||
<!-- 展示选择的审核人 --> |
|||
<view class="flex item-center justify-end flex-1 text-sm"> |
|||
<view v-for="item in showCheckers" class="mx-1"> |
|||
<!-- <u-badge :is-dot="true" is-center></u-badge> --> |
|||
{{ item.name }} |
|||
</view> |
|||
<view class="mx-1" v-show="checkedCheckers.length > 3">...</view> |
|||
</view> |
|||
|
|||
<!-- 点击更换图标 --> |
|||
<u-icon :name="collapsed ? 'arrow-down' : 'arrow-up'"></u-icon> |
|||
</view> |
|||
|
|||
<!-- 隐藏的审核人选项 --> |
|||
<view v-show="!collapsed" class="foot mt-2 flex flex-wrap"> |
|||
<u-button |
|||
v-for="item in checkers" |
|||
:type="checkedCheckers.find(checker => checker.memberId === item.memberId) ? 'primary' : 'default'" |
|||
size="mini" |
|||
class="my-1 mx-2" |
|||
@click="handleSelectChecker(item)" |
|||
> |
|||
{{ item.name }} |
|||
</u-button> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed, defineExpose } from 'vue'; |
|||
import { useStore } from 'vuex'; |
|||
|
|||
import {ref , reactive , computed }from 'vue' |
|||
// 图标切换 |
|||
let isUicon = ref('true') |
|||
// 审核人员列表 |
|||
const delivers = reactive([ |
|||
{ |
|||
checked:true, |
|||
name:'冯教授' |
|||
}, |
|||
{ |
|||
checked:false, |
|||
name:'陈历珺' |
|||
}, |
|||
{ |
|||
checked:false, |
|||
name:'张野' |
|||
}, |
|||
{ |
|||
checked:false, |
|||
name:'宋瑞芳' |
|||
}, |
|||
{ |
|||
checked:false, |
|||
name:'张斌' |
|||
}, |
|||
{ |
|||
checked:false, |
|||
name:'孙方圆' |
|||
} |
|||
]) |
|||
const store = useStore(); |
|||
// 图标切换 |
|||
const collapsed = ref(true); |
|||
|
|||
// 显示已选择的审核人 |
|||
const computedDelivers = computed(()=>{ |
|||
let arr = []; |
|||
delivers.forEach((item)=>{ |
|||
if(item.checked){ |
|||
arr.push(item) |
|||
} |
|||
if(arr.length>3){ |
|||
arr = arr.splice(0,3) |
|||
arr[3] = {checked:true,name:'...'} |
|||
} |
|||
}) |
|||
return arr |
|||
}) |
|||
// 审核人员列表 从store获取真实的项目成员列表 |
|||
// 项目加载之初 就已经获取了 |
|||
const checkers = computed(() => store.state.role.members); |
|||
|
|||
// 点击切换箭头图标 |
|||
function changeIcon(){ |
|||
isUicon.value = !isUicon.value |
|||
} |
|||
</script> |
|||
// 所有选中的审核人 |
|||
const checkedCheckers = ref([]); |
|||
|
|||
<style lang="scss"> |
|||
// 折叠状态 显示的选中的检查人 |
|||
const showCheckers = computed(() => (checkedCheckers.value.length > 3 ? checkedCheckers.value.slice(0, 3) : checkedCheckers.value)); |
|||
|
|||
</style> |
|||
defineExpose({ checkedCheckers, collapsed }); |
|||
|
|||
/** |
|||
* 点击成员 切换检查人的选中状态 |
|||
* @param {object} member 成员对象 |
|||
*/ |
|||
function handleSelectChecker(member) { |
|||
const target = checkedCheckers.value.find(item => item.memberId === member.memberId); |
|||
if (target) { |
|||
// 已经选中 将此项移除选中的数组中 |
|||
checkedCheckers.value = checkedCheckers.value.filter(item => item.memberId !== member.memberId); |
|||
} else { |
|||
checkedCheckers.value.push(member); |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
@ -0,0 +1,226 @@ |
|||
<template> |
|||
<view v-if="showViewToken" class="ring-timing" :style="containerStyles"> |
|||
<!-- #ifndef APP-NVUE --> |
|||
<view class="ring-timing-half ring-timing-left" :style="leftStyles" @transitionend="onTimingEnd" /> |
|||
<view class="ring-timing-half ring-timing-right" :style="rightStyles" /> |
|||
<!-- #endif --> |
|||
<!-- #ifdef APP-NVUE --> |
|||
<view :ref="`leftHalf${showViewToken}`" class="ring-timing-half ring-timing-left" :style="leftStyles" /> |
|||
<view :ref="`rightHalf${showViewToken}`" class="ring-timing-half ring-timing-right" :style="rightStyles" /> |
|||
<!-- #endif --> |
|||
<view class="ring-timing-center" :style="centerStyles"><slot /></view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
// #ifdef APP-NVUE |
|||
const animation = weex.requireModule('animation') |
|||
// #endif |
|||
|
|||
/** |
|||
* zwp-ring-timing 圆环计时器,不使用canvas和定时器,仅css |
|||
* @property {String} *mode 模式,可选值:timing定时器,chart当作图表用于展示数据(图表模式仅限看看,真要做图表还是用canvas好) |
|||
* @property {String} activeColor 进度条走过的颜色 |
|||
* @property {String} defaultColor 进度条底色 |
|||
* @property {String} centerBgColor 圆环中间区域的背景色 |
|||
* @property {Number} radius 圆形半径或整个组件的一半尺寸(包含了圆环的宽度) |
|||
* @property {Number} barWidth 圆环宽度 |
|||
* @property {Number} startDeg 进度开始的角度 |
|||
* @property {Number} duration timing模式的定时时间 |
|||
* @property {Number} value chart模式的值(1~100) |
|||
* @event {Function} timingEnd timing模式下定时完成的回调 |
|||
*/ |
|||
|
|||
export default { |
|||
props: { |
|||
mode: { |
|||
validator: value => ['timing', 'chart'].includes(value), |
|||
default: 'timing' |
|||
}, |
|||
activeColor: { |
|||
type: String, |
|||
default: '#42b983' |
|||
}, |
|||
defaultColor: { |
|||
type: String, |
|||
default: '#EEEEEE' |
|||
}, |
|||
centerBgColor: { |
|||
type: String, |
|||
default: '#FFFFFF' |
|||
}, |
|||
radius: { |
|||
type: Number, |
|||
default: 100 |
|||
}, |
|||
barWidth: { |
|||
type: Number, |
|||
default: 10 |
|||
}, |
|||
startDeg: { |
|||
type: Number, |
|||
default: 0 |
|||
}, |
|||
duration: { |
|||
type: Number, |
|||
default: 1 |
|||
}, |
|||
value: Number |
|||
}, |
|||
|
|||
data() { |
|||
return { |
|||
isStart: false, |
|||
showViewToken: Date.now() // nvue用来重置进度的 |
|||
} |
|||
}, |
|||
|
|||
computed: { |
|||
containerStyles() { |
|||
const { radius, startDeg, activeColor } = this |
|||
return { |
|||
borderRadius: `${radius}rpx`, |
|||
height: `${radius * 2}rpx`, |
|||
width: `${radius * 2}rpx`, |
|||
transform: `rotate(${startDeg}deg)`, |
|||
backgroundColor: activeColor |
|||
} |
|||
}, |
|||
leftStyles() { |
|||
const { mode, radius, defaultColor, isStart, duration, value } = this |
|||
return { |
|||
height: `${radius * 2}rpx`, |
|||
width: `${radius}rpx`, |
|||
backgroundColor: defaultColor, |
|||
borderTopLeftRadius: `${radius}rpx`, |
|||
borderBottomLeftRadius: `${radius}rpx`, |
|||
...(mode == 'timing' ? { |
|||
// #ifndef APP-NVUE |
|||
transitionDuration: `${isStart ? duration : 0}s`, |
|||
transform: `rotate(${isStart ? 180 : -180}deg)` |
|||
// #endif |
|||
} : { |
|||
transform: `rotate(${-180 + value * 3.6}deg)` |
|||
}) |
|||
} |
|||
}, |
|||
rightStyles() { |
|||
const { mode, radius, activeColor, defaultColor, isStart, duration, value } = this |
|||
return { |
|||
height: `${radius * 2}rpx`, |
|||
width: `${radius}rpx`, |
|||
backgroundColor: defaultColor, |
|||
borderTopRightRadius: `${radius}rpx`, |
|||
borderBottomRightRadius: `${radius}rpx`, |
|||
...(mode == 'timing' ? { |
|||
// #ifndef APP-NVUE |
|||
backgroundColor: isStart ? activeColor : defaultColor, |
|||
transitionDelay: `${isStart ? duration / 2 : 0}s`, |
|||
transform: `rotate(${isStart ? 0 : -180}deg)` |
|||
// #endif |
|||
} : { |
|||
backgroundColor: value >= 50 ? activeColor : defaultColor, |
|||
transform: `rotate(${value >= 50 ? 0 : -180}deg)`, |
|||
}) |
|||
} |
|||
}, |
|||
centerStyles() { |
|||
const { radius, centerBgColor, barWidth, startDeg } = this |
|||
return { |
|||
borderRadius: `${radius - barWidth}rpx`, |
|||
height: `${(radius - barWidth) * 2}rpx`, |
|||
width: `${(radius - barWidth) * 2}rpx`, |
|||
transform: `translate(-50%, -50%) rotate(-${startDeg}deg)`, |
|||
backgroundColor: centerBgColor, |
|||
left: `${radius}rpx`, |
|||
top: `${radius}rpx` |
|||
} |
|||
} |
|||
}, |
|||
|
|||
methods: { |
|||
// #ifdef APP-NVUE |
|||
createAnimation(direction, styles, callback = () => {}) { |
|||
let { showViewToken, duration } = this |
|||
let isLeft = direction == 'left' |
|||
animation.transition( |
|||
this.$refs[`${direction}Half${showViewToken}`], |
|||
{ |
|||
styles, |
|||
duration: isLeft ? duration * 1000 : 0, |
|||
delay: !isLeft ? (duration / 2) * 1000 : 0, |
|||
timingFunction: 'linear' |
|||
}, |
|||
callback |
|||
) |
|||
}, |
|||
// #endif |
|||
start() { |
|||
if (this.mode == 'chart') return |
|||
// #ifndef APP-NVUE |
|||
this.isStart = true |
|||
// #endif |
|||
// #ifdef APP-NVUE |
|||
const { createAnimation, activeColor, onTimingEnd } = this |
|||
createAnimation('left', { |
|||
transform: 'rotate(180deg)' |
|||
}, onTimingEnd) |
|||
createAnimation('right', { |
|||
backgroundColor: activeColor, |
|||
transform: 'rotate(0)' |
|||
}) |
|||
// #endif |
|||
}, |
|||
end() { |
|||
if (this.mode == 'chart') return |
|||
// #ifndef APP-NVUE |
|||
this.isStart = false |
|||
// #endif |
|||
// #ifdef APP-NVUE |
|||
this.showViewToken = 0 |
|||
this.$nextTick(() => { |
|||
this.showViewToken = Date.now() |
|||
}) |
|||
// #endif |
|||
}, |
|||
onTimingEnd() { |
|||
this.$emit('timingEnd') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.ring-timing { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
flex-direction: row; |
|||
position: relative; |
|||
} |
|||
.ring-timing-half { |
|||
flex: 1; |
|||
/* #ifndef APP-NVUE */ |
|||
transition-property: transform, background-color; |
|||
transition-timing-function: linear; |
|||
/* #endif */ |
|||
/* #ifdef APP-NVUE */ |
|||
transform: rotate(-180deg); |
|||
/* #endif */ |
|||
} |
|||
.ring-timing-left { |
|||
transform-origin: right center; |
|||
} |
|||
.ring-timing-right { |
|||
transform-origin: left center; |
|||
} |
|||
.ring-timing-center { |
|||
/* #ifndef APP-NVUE */ |
|||
display: flex; |
|||
/* #endif */ |
|||
justify-content: center; |
|||
align-items: center; |
|||
overflow: hidden; |
|||
position: absolute; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,8 @@ |
|||
// 上传文件的扩展名
|
|||
export const UPLOAD_EXTENSION = ['.xls', '.xlsx', '.zip', '.exe', '.pdf', '.doc', '.docx', '.ppt', '.pptx']; |
|||
|
|||
// 审核的快捷用语
|
|||
export const quickWords = { |
|||
RESOLVE: ['加油,再接再厉!', '很棒!', '不错,很详细!', '加油,再接再厉'], // 审核通过常用的审批语
|
|||
REJECT: ['不详细', '还有需要改进的地方', '驳回审批1', '驳回审批2'], // 审核驳回常用的审批语
|
|||
}; |
|||
@ -0,0 +1,20 @@ |
|||
// 环境 (development|production)
|
|||
export const SCENE = 'development'; |
|||
|
|||
// 一些特殊的API区分生产测试环境
|
|||
export const api = { |
|||
baseUrl: { |
|||
development: 'https://test.tall.wiki', |
|||
production: 'https://www.tall.wiki', |
|||
}, |
|||
msgUrl: { |
|||
development: 'wss://test.tall.wiki/websocket/message/v4.0/ws', |
|||
production: 'wss://www.tall.wiki/websocket/message/v4.0/ws', |
|||
}, |
|||
upload: { |
|||
development: 'https://test.tall.wiki/filedeal/file/upload/multiple', |
|||
production: 'http://101.201.226.21/filedeal/file/upload/multiple', |
|||
}, |
|||
}; |
|||
|
|||
export const UPLOAD_URL = api.upload[SCENE]; // 多文件上传路径
|
|||
@ -0,0 +1,5 @@ |
|||
<template> |
|||
<div class="404">404</div> |
|||
</template> |
|||
|
|||
<script setup></script> |
|||
@ -0,0 +1,53 @@ |
|||
<template> |
|||
<theme class="pt-1 h-full"> |
|||
<view class="h-full overflow-y-scroll bg-white rounded-md p-3 text-gray-400"> |
|||
<view v-for="item in checkerList" class="flex justify-between"> |
|||
<view> |
|||
<view class="mb-1 text-gray-800"> |
|||
{{ item.checkerName }} |
|||
</view> |
|||
<view class="mb-1 text-xs"> |
|||
{{ item.remark }} |
|||
</view> |
|||
<view class="text-xs" v-if="+item.checkTime > 0"> |
|||
{{ dayjs(+item.checkTime).format('MM-DD HH:mm') }} |
|||
</view> |
|||
</view> |
|||
<view class="flex flex-col justify-center"> |
|||
<view class="mb-1 text-green-600" v-if="item.status === 1"> 已通过 </view> |
|||
<view class="mb-1 text-red-600" v-if="item.status === 2"> 已驳回 </view> |
|||
<view v-if="+item.score > 0"> |
|||
<zwp-ring-timing mode="chart" :value="item.score" active-color="#F59E0B" radius="30" bar-width="4"> |
|||
<text class="text-yellow-500 font-medium">{{ item.score }}</text> |
|||
</zwp-ring-timing> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</theme> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue'; |
|||
import { onLoad } from '@dcloudio/uni-app'; |
|||
import dayjs from 'dayjs'; |
|||
|
|||
const checkerList = ref([]); |
|||
|
|||
onLoad(options => { |
|||
getQueryCheckLog(options); |
|||
}); |
|||
|
|||
async function getQueryCheckLog(options) { |
|||
try { |
|||
const param = { deliverRecordId: options.deliverRecordId }; |
|||
const data = await uni.$u.api.queryCheckLog(param); |
|||
checkerList.value = data; |
|||
} catch (error) { |
|||
console.log('error: ', error); |
|||
uni.$ui.showToast('获取检查交付物历史失败'); |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"></style> |
|||
@ -0,0 +1,25 @@ |
|||
<template> |
|||
<web-view :src="src"></web-view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue'; |
|||
import { onLoad } from '@dcloudio/uni-app'; |
|||
|
|||
const src = ref(''); |
|||
|
|||
onLoad(options => { |
|||
if (!options) { |
|||
uni.redirectTo({ url: '/pages/404/404' }); |
|||
return; |
|||
} |
|||
if (options.url) { |
|||
src.value = options.url; |
|||
} |
|||
if (options.name) { |
|||
uni.setNavigationBarTitle({ |
|||
title: options.name || '详情页', |
|||
}); |
|||
} |
|||
}); |
|||
</script> |
|||
@ -1,195 +1,195 @@ |
|||
<template> |
|||
<theme :style="{ height: height }" class="flex flex-col overflow-hidden u-font-14"> |
|||
<!-- 标题栏 --> |
|||
<Title /> |
|||
|
|||
<view class="container flex flex-col flex-1 mx-auto overflow-hidden bg-gray-100"> |
|||
<!-- 角色栏 --> |
|||
<Roles /> |
|||
|
|||
<swiper :current="roleIndex" class="swiper container flex flex-col flex-1 mx-auto overflow-hidden bg-gray-100" :indicator-dots="false" :autoplay="false" :circular="false" @change="tabsChange"> |
|||
<swiper-item v-for="(task,index) in allTasks" :key="index"> |
|||
<!-- 日常任务面板 --> |
|||
<Globals :globals="task.global" /> |
|||
|
|||
<!-- 定期任务面板 --> |
|||
<TimeLine :tasks="task.task" @getTasks="getTasks" class="flex-1 overflow-hidden" /> |
|||
</swiper-item> |
|||
</swiper> |
|||
|
|||
<!-- TODO: DEBUG: --> |
|||
<u-button @click="$store.commit('setTheme', 'theme-test')">测试切换主题</u-button> |
|||
</view> |
|||
</theme> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed, watch, onMounted } from 'vue'; |
|||
import { useStore } from 'vuex'; |
|||
import useInit from '@/hooks/project/useInit'; |
|||
import useGetTasks from '@/hooks/project/useGetTasks'; |
|||
import dayjs from 'dayjs'; |
|||
|
|||
const initHook = useInit(); |
|||
const getTasksHook = useGetTasks(); |
|||
const store = useStore(); |
|||
const projectId = computed(() => store.getters['project/projectId']); |
|||
const userId = computed(() => store.getters['user/userId']); |
|||
const roleId = computed(() => store.state.role.roleId); // 当前展示查看的角色id |
|||
const roleIndex = computed(() => store.state.role.roleIndex); // 时间轴角色索引 |
|||
const visibleRoles = computed(() => store.state.role.visibleRoles); // 展示的角色信息 |
|||
const timeNode = computed(() => store.state.task.timeNode); // 时间基准点 |
|||
const timeUnit = computed(() => store.state.task.timeUnit); // 时间颗粒度 |
|||
const newProjectInfo = computed(() => store.state.task.newProjectInfo); |
|||
const showScrollTo = computed(() => store.state.task.showScrollTo); // 是否可以设置时间轴自动滚动的位置 |
|||
const allTasks = computed(() => store.state.task.allTasks); // 所有任务 |
|||
const globals = computed(() => store.getters['task/globals']); // 所有的日常任务 永久 + 可变 日常任务 |
|||
const timeGranularity = computed(() => store.getters['task/timeGranularity']); // 计算颗粒度 对应的 dayjs add 的单位 |
|||
const height = ref(null); // 页面高度 |
|||
|
|||
onMounted(() => { |
|||
const system = uni.getSystemInfoSync(); |
|||
height.value = `${system.windowHeight}px`; |
|||
}); |
|||
|
|||
/** |
|||
* 当角色发生变化时 |
|||
* 重新查询永久日常任务和普通日常任务 |
|||
* 注意: 切换角色后 重新设置了时间基准点 时间基准点一定会变 |
|||
* 所以监听时间基准点获取 可变日常任务即可 这里不用获取 避免重复获取 |
|||
*/ |
|||
watch(roleId, newValue => { |
|||
if (newValue) { |
|||
// 判断如果allTasks里有就不用加了 |
|||
if (allTasks.value.length && allTasks.value[roleIndex.value].global && allTasks.value[roleIndex.value].task) |
|||
return; |
|||
|
|||
console.log('当角色发生变化时', newValue); |
|||
store.commit('task/setTimeNode', Date.now()); |
|||
// 根据角色查找永久的日常任务 |
|||
const params = { |
|||
roleId: newValue, |
|||
projectId: projectId.value, |
|||
}; |
|||
store.dispatch('task/getPermanent', params); |
|||
} |
|||
}); |
|||
|
|||
/** |
|||
* 当时间基准点发生变化时 |
|||
* 重新根据时间和角色查询普通日常任务 |
|||
* 永久日常任务不发生 改变 |
|||
*/ |
|||
watch(timeNode, newValue => { |
|||
if (newValue && roleId.value) { |
|||
console.log('当时间基准点发生变化时'); |
|||
clearTasksData(); |
|||
// 查任务 |
|||
getGlobalData(); // 查可变日常任务 |
|||
getTasksHook.initPlanTasks(); // 处理定期任务 |
|||
|
|||
// 滚动到对应位置 |
|||
let timer = null; |
|||
timer = setInterval(() => { |
|||
if (showScrollTo.value) { |
|||
clearInterval(timer); |
|||
setScrollPosition(); |
|||
} |
|||
}, 300); |
|||
} |
|||
}); |
|||
|
|||
/** |
|||
* 当收到打开新项目消息状态时 |
|||
* 重新根据时间和角色查询普通日常任务 |
|||
* 永久日常任务不发生改变 |
|||
*/ |
|||
watch(newProjectInfo, newValue => { |
|||
console.log('当收到打开新项目消息状态时'); |
|||
if (newValue && newValue.value.projectId && newValue.value.url) { |
|||
uni.$u.route('/', { |
|||
u: userId.value, |
|||
p: newValue.value.projectId, |
|||
url: newValue.value.url, |
|||
}); |
|||
clearTasksData(); |
|||
store.commit('role/setRoleId', ''); |
|||
const options = uni.$route.query; |
|||
|
|||
initHook.init(options); |
|||
<template> |
|||
<theme :style="{ height: height }" class="flex flex-col overflow-hidden u-font-14"> |
|||
<!-- 标题栏 --> |
|||
<Title /> |
|||
|
|||
<view class="container flex flex-col flex-1 mx-auto overflow-hidden bg-gray-100"> |
|||
<!-- 角色栏 --> |
|||
<Roles /> |
|||
|
|||
<swiper |
|||
:current="roleIndex" |
|||
class="swiper container flex flex-col flex-1 mx-auto overflow-hidden bg-gray-100" |
|||
:indicator-dots="false" |
|||
:autoplay="false" |
|||
:circular="false" |
|||
@change="tabsChange" |
|||
> |
|||
<swiper-item v-for="(task, index) in allTasks" :key="index"> |
|||
<!-- 日常任务面板 --> |
|||
<Globals :globals="task.global" /> |
|||
|
|||
<!-- 定期任务面板 --> |
|||
<TimeLine :tasks="task.task" @getTasks="getTasks" class="flex-1 overflow-hidden" /> |
|||
</swiper-item> |
|||
</swiper> |
|||
|
|||
<!-- TODO: DEBUG: --> |
|||
<!-- <u-button @click="$store.commit('setTheme', 'theme-test')">测试切换主题</u-button> --> |
|||
</view> |
|||
</theme> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed, watch, onMounted } from 'vue'; |
|||
import { useStore } from 'vuex'; |
|||
import dayjs from 'dayjs'; |
|||
import useInit from '@/hooks/project/useInit'; |
|||
import useGetTasks from '@/hooks/project/useGetTasks'; |
|||
|
|||
const initHook = useInit(); |
|||
const getTasksHook = useGetTasks(); |
|||
const store = useStore(); |
|||
const projectId = computed(() => store.getters['project/projectId']); |
|||
const userId = computed(() => store.getters['user/userId']); |
|||
const roleId = computed(() => store.state.role.roleId); // 当前展示查看的角色id |
|||
const roleIndex = computed(() => store.state.role.roleIndex); // 时间轴角色索引 |
|||
const visibleRoles = computed(() => store.state.role.visibleRoles); // 展示的角色信息 |
|||
const timeNode = computed(() => store.state.task.timeNode); // 时间基准点 |
|||
const timeUnit = computed(() => store.state.task.timeUnit); // 时间颗粒度 |
|||
const newProjectInfo = computed(() => store.state.task.newProjectInfo); |
|||
const showScrollTo = computed(() => store.state.task.showScrollTo); // 是否可以设置时间轴自动滚动的位置 |
|||
const allTasks = computed(() => store.state.task.allTasks); // 所有任务 |
|||
const globals = computed(() => store.getters['task/globals']); // 所有的日常任务 永久 + 可变 日常任务 |
|||
const timeGranularity = computed(() => store.getters['task/timeGranularity']); // 计算颗粒度 对应的 dayjs add 的单位 |
|||
const height = ref(null); // 页面高度 |
|||
|
|||
onMounted(() => { |
|||
const system = uni.getSystemInfoSync(); |
|||
height.value = `${system.windowHeight}px`; |
|||
}); |
|||
|
|||
/** |
|||
* 当角色发生变化时 |
|||
* 重新查询永久日常任务和普通日常任务 |
|||
* 注意: 切换角色后 重新设置了时间基准点 时间基准点一定会变 |
|||
* 所以监听时间基准点获取 可变日常任务即可 这里不用获取 避免重复获取 |
|||
*/ |
|||
watch(roleId, newValue => { |
|||
if (newValue) { |
|||
// 判断如果allTasks里有就不用加了 |
|||
if (allTasks.value.length && allTasks.value[roleIndex.value].global && allTasks.value[roleIndex.value].task) return; |
|||
|
|||
console.log('当角色发生变化时', newValue); |
|||
store.commit('task/setTimeNode', Date.now()); |
|||
// 根据角色查找永久的日常任务 |
|||
const params = { |
|||
roleId: newValue, |
|||
projectId: projectId.value, |
|||
}; |
|||
store.dispatch('task/getPermanent', params); |
|||
} |
|||
}); |
|||
|
|||
/** |
|||
* 当时间基准点发生变化时 |
|||
* 重新根据时间和角色查询普通日常任务 |
|||
* 永久日常任务不发生 改变 |
|||
*/ |
|||
watch(timeNode, newValue => { |
|||
if (newValue && roleId.value) { |
|||
console.log('当时间基准点发生变化时'); |
|||
clearTasksData(); |
|||
// 查任务 |
|||
getGlobalData(); // 查可变日常任务 |
|||
getTasksHook.initPlanTasks(); // 处理定期任务 |
|||
|
|||
// 滚动到对应位置 |
|||
let timer = null; |
|||
timer = setInterval(() => { |
|||
if (showScrollTo.value) { |
|||
clearInterval(timer); |
|||
setScrollPosition(); |
|||
} |
|||
}, 300); |
|||
} |
|||
}); |
|||
|
|||
/** |
|||
* 当收到打开新项目消息状态时 |
|||
* 重新根据时间和角色查询普通日常任务 |
|||
* 永久日常任务不发生改变 |
|||
*/ |
|||
watch(newProjectInfo, newValue => { |
|||
console.log('当收到打开新项目消息状态时'); |
|||
if (newValue && newValue.value.projectId && newValue.value.url) { |
|||
uni.$u.route('/', { |
|||
u: userId.value, |
|||
p: newValue.value.projectId, |
|||
url: newValue.value.url, |
|||
}); |
|||
clearTasksData(); |
|||
store.commit('role/setRoleId', ''); |
|||
const options = uni.$route.query; |
|||
|
|||
initHook.init(options); |
|||
} |
|||
}); |
|||
|
|||
// 获取可变全局任务 |
|||
function getGlobalData() { |
|||
if (!allTasks.value[roleIndex]) { |
|||
const param = { |
|||
roleId: roleId.value, |
|||
timeNode: timeNode.value, |
|||
timeUnit: timeUnit.value, |
|||
projectId: projectId.value, |
|||
}; |
|||
store.dispatch('task/getGlobal', param); |
|||
} |
|||
// 添加到allTasks里 |
|||
const index = visibleRoles.value.findIndex(role => role.id === roleId.value); |
|||
const arr = [...allTasks.value]; |
|||
arr[index].global = [...globals.value]; |
|||
store.commit('task/setAllTasks', arr); |
|||
} |
|||
|
|||
// 清除已有的任务数据 |
|||
function clearTasksData() { |
|||
// 清空日常任务的数据 |
|||
store.commit('task/setPermanents', []); |
|||
store.commit('task/setDailyTasks', []); |
|||
// 清空定期任务数据 |
|||
store.commit('task/clearTasks'); |
|||
// 到顶的标志复位 |
|||
// 到底的标志复位 |
|||
store.commit('task/clearEndFlag'); |
|||
} |
|||
|
|||
function getTasks(params) { |
|||
getTasksHook.initPlanTasks(params); // 处理定期任务 |
|||
} |
|||
|
|||
// tabs通知swiper切换 |
|||
function tabsChange(e) { |
|||
const { id } = visibleRoles.value[e.detail.current]; |
|||
store.commit('role/setRoleIndex', e.detail.current); |
|||
store.commit('role/setRoleId', id); |
|||
} |
|||
|
|||
// 设置自动滚动位置 |
|||
function setScrollPosition() { |
|||
// 如果storage里有taskId 滚动到这个id的任务 |
|||
const taskId = uni.$storage.getStorageSync('taskId'); |
|||
if (taskId) { |
|||
store.commit('task/setScrollToTaskId', `a${taskId}`); |
|||
uni.$storage.setStorageSync('taskId', ''); // 记录后即刻清除本地存储 |
|||
} else { |
|||
const item = allTasks.value[roleIndex.value].task.find(task => task.detailId); |
|||
if (item) { |
|||
store.commit('task/setScrollToTaskId', `a${item.id}`); |
|||
} else { |
|||
// 没有本地记录的taskId |
|||
// 找到当前时间基准线的任务id 记录 并滚动到当前时间基准线 |
|||
const task = allTasks.value[roleIndex.value].task.find(item => dayjs(+item.planStart).isSame(timeNode.value, timeGranularity.value)); |
|||
task && store.commit('task/setScrollToTaskId', `a${task.id}`); // 有这个task 就记录他的id |
|||
} |
|||
}); |
|||
|
|||
// 获取可变全局任务 |
|||
function getGlobalData() { |
|||
if (!allTasks.value[roleIndex]) { |
|||
const param = { |
|||
roleId: roleId.value, |
|||
timeNode: timeNode.value, |
|||
timeUnit: timeUnit.value, |
|||
projectId: projectId.value, |
|||
}; |
|||
store.dispatch('task/getGlobal', param); |
|||
} |
|||
// 添加到allTasks里 |
|||
const index = visibleRoles.value.findIndex(role => role.id === roleId.value); |
|||
const arr = [...allTasks.value]; |
|||
arr[index].global = [...globals.value]; |
|||
store.commit('task/setAllTasks', arr); |
|||
} |
|||
|
|||
// 清除已有的任务数据 |
|||
function clearTasksData() { |
|||
// 清空日常任务的数据 |
|||
store.commit('task/setPermanents', []); |
|||
store.commit('task/setDailyTasks', []); |
|||
// 清空定期任务数据 |
|||
store.commit('task/clearTasks'); |
|||
// 到顶的标志复位 |
|||
// 到底的标志复位 |
|||
store.commit('task/clearEndFlag'); |
|||
} |
|||
|
|||
|
|||
|
|||
function getTasks(params) { |
|||
getTasksHook.initPlanTasks(params); // 处理定期任务 |
|||
} |
|||
|
|||
// tabs通知swiper切换 |
|||
function tabsChange(e) { |
|||
const { |
|||
id |
|||
} = visibleRoles.value[e.detail.current]; |
|||
store.commit('role/setRoleIndex', e.detail.current); |
|||
store.commit('role/setRoleId', id); |
|||
|
|||
} |
|||
|
|||
// 设置自动滚动位置 |
|||
function setScrollPosition() { |
|||
// 如果storage里有taskId 滚动到这个id的任务 |
|||
const taskId = uni.$storage.getStorageSync('taskId'); |
|||
if (taskId) { |
|||
store.commit('task/setScrollToTaskId', `a${taskId}`); |
|||
uni.$storage.setStorageSync('taskId', ''); // 记录后即刻清除本地存储 |
|||
} else { |
|||
const item = allTasks.value[roleIndex.value].task.find(task => task.detailId); |
|||
if (item) { |
|||
store.commit('task/setScrollToTaskId', `a${item.id}`); |
|||
} else { |
|||
// 没有本地记录的taskId |
|||
// 找到当前时间基准线的任务id 记录 并滚动到当前时间基准线 |
|||
const task = allTasks.value[roleIndex.value].task.find(item => dayjs(+item.planStart).isSame(timeNode.value, |
|||
timeGranularity.value)); |
|||
task && store.commit('task/setScrollToTaskId', `a${task.id}`); // 有这个task 就记录他的id |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.border-b { |
|||
border-bottom: 1px solid #e4e7ed; |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.border-b { |
|||
border-bottom: 1px solid #e4e7ed; |
|||
} |
|||
</style> |
|||
|
|||
@ -0,0 +1,68 @@ |
|||
<template> |
|||
<theme> |
|||
<view class="h-full w-full px-3 pt-1 overflow-y-scroll"> |
|||
<view class="bg-white my-2 rounded-md p-3 text-gray-400" v-for="item in listRef"> |
|||
<!-- 插件名称和提交时间显示 --> |
|||
<view class="flex justify-between mb-2"> |
|||
<view class="text-gray-800">{{ deliverName }}</view> |
|||
<view class="text-xs">{{ dayjs(+item.submitTime).format('MM-DD HH:mm') }}</view> |
|||
</view> |
|||
<!-- 提交的链接 --> |
|||
<DeliverLink v-if="item.details[0]" :link="item.details[0]" /> |
|||
<!-- 该插件物的审核人 --> |
|||
<view class="mb-1 mt-3">审核人</view> |
|||
<view class="flex justify-between mb-2" v-for="checkItem in item.checkerList"> |
|||
<view> |
|||
<view class="mb-1 text-gray-800 font-semibold"> |
|||
{{ checkItem.checkerName }} |
|||
</view> |
|||
<view class="mb-1 text-xs"> |
|||
{{ checkItem.remark }} |
|||
</view> |
|||
<view class="mb-1 text-xs" v-if="+checkItem.checkTime > 0"> |
|||
{{ dayjs(+checkItem.checkTime).format('MM-DD HH:mm') }} |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="text-center text-xs"> |
|||
<view v-if="checkItem.status == null" class="text-gray-400">待审核</view> |
|||
<view v-else-if="checkItem.status === 1"> |
|||
<view class="text-green-600 mb-1">已通过</view> |
|||
|
|||
<zwp-ring-timing mode="chart" :value="checkItem.score" active-color="#F59E0B" radius="30" bar-width="4"> |
|||
<text class="text-yellow-500 font-medium">{{ checkItem.score }}</text> |
|||
</zwp-ring-timing> |
|||
</view> |
|||
<view class="text-red-600" v-else>已驳回</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</theme> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref } from 'vue'; |
|||
import { onLoad } from '@dcloudio/uni-app'; |
|||
import dayjs from 'dayjs'; |
|||
|
|||
const listRef = ref([]); |
|||
const deliverName = ref(''); |
|||
|
|||
onLoad(options => { |
|||
// 根据交付物id获取上传记录 |
|||
(async function getHistory() { |
|||
try { |
|||
const param = { deliverId: options.deliverId }; |
|||
const data = await uni.$u.api.getDeliverHistory(param); |
|||
deliverName.value = data.deliverName; |
|||
listRef.value = data.deliverRecordList; |
|||
} catch (error) { |
|||
console.log('error: ', error); |
|||
uni.$ui.showToast('获取交付物历史失败'); |
|||
} |
|||
})(); |
|||
}); |
|||
</script> |
|||
|
|||
<style lang="scss"></style> |
|||
@ -1,26 +0,0 @@ |
|||
<template> |
|||
<theme class="h-full w-full pt-1"> |
|||
<view class="bg-white m-5 rounded-md p-3"> |
|||
<view class="flex justify-between text-gray-400 mb-2"> |
|||
<view>插件名</view> <view>提交时间</view> |
|||
</view> |
|||
<view class="text-blue-400 mb-2"> |
|||
链接 |
|||
</view> |
|||
<view class="mb-2">审核人</view> |
|||
</view> |
|||
</theme> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
}; |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
|
|||
</style> |
|||
@ -0,0 +1,84 @@ |
|||
<template> |
|||
<!-- 审核通过的modal --> |
|||
<u-mask :show="data.mode !== 'HIDE'" @click="handleHide"> |
|||
<view class="modal-content-wrap" @click.stop> |
|||
<!-- 通过modal的标题 --> |
|||
<view class="modal-content-head"> {{ data.mode === 'RESOLVE' ? '审核通过' : '审核驳回' }} </view> |
|||
|
|||
<view class="modal-content-body"> |
|||
<!-- 评分 --> |
|||
<view class="flex justify-between mb-4" v-show="data.mode === 'RESOLVE'"> |
|||
<u-number-box v-model="score" size="30" input-width="50" :max="100" :min="0" :step="1"></u-number-box> |
|||
<view class="w-32 pt-4"> |
|||
<u-slider v-model="score" active-color="#34D399" :max="100" :min="0" :step="1"></u-slider> |
|||
</view> |
|||
</view> |
|||
|
|||
<u-input v-model="commit" type="textarea" :border="true" :auto-height="true" /> |
|||
|
|||
<view class="common-list"> |
|||
<view v-for="item in words" class="leading-12" @click="commit = item"> |
|||
{{ item }} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="modal-content-foot"> |
|||
<view class="cancel" @click="handleHide"> 取消 </view> |
|||
<view class="confirm" @click="handleSubmit(data.mode)"> 确定 </view> |
|||
</view> |
|||
</view> |
|||
</u-mask> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed } from 'vue'; |
|||
import { useStore } from 'vuex'; |
|||
import { quickWords } from '@/config/deliver'; |
|||
|
|||
const props = defineProps({ |
|||
data: { type: Object, default: {} }, |
|||
}); |
|||
const emits = defineEmits(['hide', 'submit-end']); |
|||
const store = useStore(); |
|||
const words = computed(() => quickWords[props.data.mode]); // 快捷用语 |
|||
const projectId = computed(() => store.getters['project/projectId']); |
|||
|
|||
const commit = ref(''); // 提交的信息 |
|||
const score = ref(100); // 评分 |
|||
|
|||
/** |
|||
* 提交评审信息 |
|||
* 提交成功后隐藏modal 重置表单控件 |
|||
* 给父组件信息 更新值 |
|||
* @param {string} mode 'RESOLVE'|'REJECT' |
|||
*/ |
|||
async function handleSubmit(mode) { |
|||
try { |
|||
const deliverRecordId = props.data.deliverRecordId(); |
|||
const param = { |
|||
projectId: projectId.value, |
|||
deliverRecordId, |
|||
type: mode === 'RESOLVE' ? 1 : 2, |
|||
remark: commit.value, |
|||
score: mode === 'RESOLVE' ? score.value : '', |
|||
}; |
|||
await uni.$u.api.checkDeliver(param); |
|||
handleHide(); // 隐藏 + 重置 |
|||
uni.$ui.showToast('审核信息提交成功'); |
|||
// 通知父组件评审成功 更新信息 |
|||
emits('submit-end', param); |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
uni.$ui.showToast('审核信息提交失败, 请稍后重试'); |
|||
} |
|||
} |
|||
|
|||
// 隐藏及 重置 |
|||
function handleHide() { |
|||
emits('hide'); |
|||
// 重置相关数据 |
|||
score.value = 100; |
|||
commit.value = ''; |
|||
} |
|||
</script> |
|||
@ -0,0 +1,225 @@ |
|||
<template> |
|||
<!-- 是自己的任务 且该任务有交付物 才显示提交组件 --> |
|||
<view class="bg-white px-2 rounded-md relative" @longpress.prevent="showMask = true"> |
|||
<!-- 插件名称输入和提交 --> |
|||
<view class="flex item-center justify-between py-2"> |
|||
<view class="flex-1"> |
|||
<text v-if="deliver.deliverName"> |
|||
{{ deliver.deliverName }} |
|||
</text> |
|||
</view> |
|||
|
|||
<!-- 提交 --> |
|||
<u-button |
|||
type="primary" |
|||
size="mini" |
|||
@click="submit" |
|||
class="self-center" |
|||
:disabled="submitState" |
|||
:ripple="true" |
|||
:loading="submitBtnLoading" |
|||
> |
|||
提交 |
|||
</u-button> |
|||
|
|||
<!-- 查看提交历史的按钮 --> |
|||
<u-icon name="arrow-right" class="ml-3" @click="openDeliverHistory"></u-icon> |
|||
</view> |
|||
|
|||
<!-- 插件上传方式 --> |
|||
<view> |
|||
<view class="link-box"> |
|||
<u-input v-model="linkValue" type="text" :border="true" placeholder="请输入交付物地址/链接" class="input"></u-input> |
|||
</view> |
|||
<view class="mt-3"> |
|||
<u-button size="mini" :plain="true" type="primary" class="mr-3" @click="paste">粘贴</u-button> |
|||
<u-button size="mini" :plain="true" type="primary" class="mr-3" @click="uploadFile">文件</u-button> |
|||
<u-button size="mini" :plain="true" type="primary" class="mr-3" @click="uploadPhoto">拍照</u-button> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 编辑和删除的遮罩层 --> |
|||
<view class="mask flex items-center justify-center bg-grey" v-show="showMask" @click="showMask = false"> |
|||
<view class="bg-yellow-500 text-white w-12 h-12 text-center leading-12 rounded-w-12 mx-8" @click.stop="showEditModal = true"> |
|||
修改 |
|||
</view> |
|||
<view class="bg-red-500 text-white w-12 h-12 text-center leading-12 rounded-w-12 mx-8" @click.stop="showDeleteModal = true"> |
|||
删除 |
|||
</view> |
|||
<!-- 删除的二次提示modal --> |
|||
<u-modal v-model="showDeleteModal" :content="content" :show-cancel-button="true" @confirm="confirmDelete"></u-modal> |
|||
</view> |
|||
|
|||
<!-- 编辑交付物标题的modal --> |
|||
<u-mask :show="showEditModal" @click="showEditModal = false"> |
|||
<view class="modal-content-wrap" @click.stop> |
|||
<view class="modal-content-head">交付物标题名称</view> |
|||
<view class="modal-content-body"> |
|||
<u-input :border="true" placeholder="请输入交付物名称" v-model="newInputRef"></u-input> |
|||
</view> |
|||
|
|||
<view class="modal-content-foot"> |
|||
<view class="cancel" @click="showEditModal = false">取消</view> |
|||
<view class="confirm" @click="confirmEditDeliverName">确定</view> |
|||
</view> |
|||
</view> |
|||
</u-mask> |
|||
|
|||
<!-- 插件审核人员选择 --> |
|||
<Reviewer ref="reviewerRef" /> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, computed, inject } from 'vue'; |
|||
import { useStore } from 'vuex'; |
|||
import { UPLOAD_URL } from '@/config/index'; |
|||
import { UPLOAD_EXTENSION } from '@/config/deliver'; |
|||
|
|||
const deliver = inject('deliver'); |
|||
const task = inject('task'); |
|||
const store = useStore(); |
|||
const emits = defineEmits(['upload-success']); |
|||
|
|||
const reviewerRef = ref(null); |
|||
const submitBtnLoading = ref(false); |
|||
const linkValue = ref(''); // 链接的值 |
|||
const showMask = ref(false); // 编辑和删除页面 |
|||
const showEditModal = ref(false); // 编辑交付物标题的modal |
|||
const newInputRef = ref(''); // 修改的插件名的值 |
|||
const showDeleteModal = ref(false); // 删除二次提示的modal |
|||
const content = '是否确定删除'; |
|||
const showBadge = ref(false); // u-badge的显示与隐藏 |
|||
|
|||
// 判断提交按钮的状态 |
|||
const submitState = computed(() => !linkValue.value); |
|||
const projectId = computed(() => store.getters['project/projectId']); |
|||
|
|||
// 验证提交的交付物信息格式 |
|||
function validateDeliverForm(checkedCheckers) { |
|||
const reg = /^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- ./?%&=]*)?$/; |
|||
if (!reg.test(linkValue.value)) { |
|||
// 显示toast信息 |
|||
uni.$ui.showToast('请输入正确的链接'); |
|||
return false; |
|||
} |
|||
// 没有检查人 提示选择检查人 |
|||
if (!checkedCheckers || !checkedCheckers.length) { |
|||
uni.$ui.showToast('请选择检查人'); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
// 提交交付物信息 |
|||
async function submit() { |
|||
const { checkedCheckers } = reviewerRef.value; // 拿到选择检查人组件中选中的检查人 |
|||
|
|||
// 提交前的验证 |
|||
if (!validateDeliverForm(checkedCheckers)) return; |
|||
submitBtnLoading.value = true; // 显示loading |
|||
// 验证成功后进行请求 |
|||
try { |
|||
const checkerList = []; |
|||
checkedCheckers.forEach(item => { |
|||
checkerList.push(item.memberId); |
|||
}); |
|||
const param = { |
|||
projectId: projectId.value, |
|||
deliverId: deliver.value.deliverId, |
|||
fileList: [linkValue.value], |
|||
checkerList, |
|||
}; |
|||
await uni.$u.api.submitDeliverInfo(param); |
|||
uni.$ui.showToast('提交交付物信息成功'); |
|||
resetControlState(); // 重置控件的初始状态 |
|||
emits('upload-success'); |
|||
} catch (error) { |
|||
console.log('error: ', error); |
|||
uni.$ui.showToast('提交交付物信息失败'); |
|||
} |
|||
} |
|||
|
|||
// 重置控件的初始状态 |
|||
function resetControlState() { |
|||
submitBtnLoading.value = false; // 隐藏loading |
|||
linkValue.value = ''; // 清空输入框内容 |
|||
reviewerRef.value.collapsed = true; // 折叠检查人面板 |
|||
} |
|||
|
|||
// 查看历史记录 |
|||
function openDeliverHistory() { |
|||
const { deliverId } = deliver.value; |
|||
// console.log(deliverId) |
|||
uni.navigateTo({ url: `/pages/submitLog/submitLog?deliverId=${deliverId}` }); |
|||
} |
|||
|
|||
// 粘贴上传 |
|||
function paste() { |
|||
uni.getClipboardData({ |
|||
success(res) { |
|||
linkValue.value = res.data; |
|||
}, |
|||
}); |
|||
} |
|||
|
|||
// 文件上传 |
|||
async function uploadFile() { |
|||
try { |
|||
const data = await uni.$upload.chooseAndUpload(UPLOAD_URL, {}, UPLOAD_EXTENSION, 'files'); |
|||
// console.log(data[0]); |
|||
linkValue.value = data[0].visitUrl; |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
} |
|||
} |
|||
|
|||
// TODO: 拍照上传 |
|||
async function uploadPhoto() { |
|||
try { |
|||
const data = await uni.$upload.chooseAndUpload(UPLOAD_URL, {}, UPLOAD_EXTENSION, 'files'); |
|||
// console.log(data[0]) |
|||
linkValue.value = data[0].visitUrl; |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
} |
|||
} |
|||
|
|||
// 确定修改交付物名称 |
|||
async function confirmEditDeliverName() { |
|||
// TODO: 发请求 请求成功后更新task里的交付物信息 |
|||
if (!newInputRef.value) { |
|||
uni.$ui.showToast('输入不能为空'); |
|||
} |
|||
try { |
|||
const param = { |
|||
projectId: projectId.value, |
|||
taskId: task.id, |
|||
deliverName: newInputRef.value, |
|||
}; |
|||
await uni.$u.api.editDeliverName(param); |
|||
// uni.$ui.showToast('修改交付物名称成功'); |
|||
// 请求成功 才会清空 请求失败保留 |
|||
showEditModal.value = false; |
|||
showMask.value = false; |
|||
showBadge.value = false; |
|||
newInputRef.value = ''; |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
uni.$ui.showToast('修改交付物名称失败'); |
|||
} |
|||
} |
|||
|
|||
// 二次确认后删除 |
|||
async function confirmDelete() { |
|||
try { |
|||
showDeleteModal.value = true; |
|||
deliverRef.value = false; |
|||
await uni.$u.api.deleteDeliver(); |
|||
uni.$ui.showToast('删除交付物成功'); |
|||
} catch (error) { |
|||
console.error('error: ', error); |
|||
uni.$ui.showToast('删除交付物失败'); |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,18 @@ |
|||
<template> |
|||
<div class="flex justify-around"> |
|||
<button class="text-xs bg-blue-500 text-white leading-6" style="width: 250rpx" @click="openAudit">财务审批</button> |
|||
<button class="text-xs bg-blue-500 text-white leading-6" style="width: 250rpx" @click="openStatistical">财务统计</button> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
// DEBUG:打开财务审批详情页 |
|||
function openAudit() { |
|||
uni.$ui.openDetail({ url: 'https://www.taobao.com', name: '财务审批' }); |
|||
} |
|||
|
|||
// DEBUG:打开财务统计详情页 |
|||
function openStatistical() { |
|||
uni.$ui.openDetail({ url: 'https://www.taobao.com', name: '财务统计' }); |
|||
} |
|||
</script> |
|||
@ -0,0 +1,73 @@ |
|||
<!-- 财务条内置组件 --> |
|||
<template> |
|||
<view class="finance-wrap" v-if="data" @click="openFinance"> |
|||
<!-- 预算和奖金 --> |
|||
<view class="finance-row"> |
|||
<view class="finance-item" :style="{ width: `${(data.budget * 100) / (data.budget + data.bonus)}%`, 'background-color': '#93C5FD' }"> |
|||
预算{{ data.budget / 100 }} |
|||
</view> |
|||
<view class="finance-item" :style="{ width: `${(data.bonus * 100) / (data.budget + data.bonus)}%`, 'background-color': '#12c77e' }"> |
|||
奖金{{ data.bonus / 100 }} |
|||
</view> |
|||
</view> |
|||
<!-- 项目采购日常采购 --> |
|||
<view class="finance-row"> |
|||
<view |
|||
class="finance-item" |
|||
:style="{ width: `${(data.projectExpend * 100) / (data.projectExpend + data.dailyExpend)}%`, 'background-color': '#FBBF24' }" |
|||
> |
|||
项目采购{{ data.dailyExpend / 100 }} |
|||
</view> |
|||
<view |
|||
class="finance-item" |
|||
:style="{ width: `${(data.dailyExpend * 100) / (data.projectExpend + data.dailyExpend)}%`, 'background-color': '#a1fd93' }" |
|||
> |
|||
日常采购{{ data.dailyExpend / 100 }} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { ref, inject } from 'vue'; |
|||
|
|||
const task = inject('task'); |
|||
const data = ref(null); |
|||
|
|||
// 查询任务上的财务条数据 |
|||
async function getFinanceByTaskData() { |
|||
try { |
|||
console.log('task: ', task); |
|||
const detailId = task.detailId; |
|||
data.value = await uni.$u.api.getFinanceByTask(detailId); |
|||
} catch (error) { |
|||
console.log('getFinanceByTaskData error: ', error); |
|||
} |
|||
} |
|||
|
|||
getFinanceByTaskData(); |
|||
|
|||
// 打开详情页 |
|||
function openFinance() { |
|||
// DEBUG: 假数据 换成财务条详情页的地址 |
|||
uni.$ui.openDetail({ url: 'http://www.baidu.com', name: '财务' }); |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.finance-wrap { |
|||
.finance-row { |
|||
display: flex; |
|||
|
|||
.finance-item { |
|||
margin: 3rpx 5rpx; |
|||
font-size: 12px; |
|||
text-align: center; |
|||
border-radius: 8rpx; |
|||
white-space: nowrap; |
|||
text-overflow: ellipsis; |
|||
overflow-x: visible; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,11 @@ |
|||
<!-- 资源管理 --> |
|||
<template> |
|||
<button class="text-xs bg-blue-500 text-white leading-6" style="width: 500rpx" @click="openSourceManage">资源管理</button> |
|||
</template> |
|||
|
|||
<script setup> |
|||
function openSourceManage() { |
|||
// DEBUG: 假数据 换成财务条 资源管理的地址 |
|||
uni.$ui.openDetail({ url: 'http://m.jd.com', name: '资源管理' }); |
|||
} |
|||
</script> |
|||
@ -0,0 +1,108 @@ |
|||
@url=https://test.tall.wiki/gateway/defaultwbs |
|||
@type=content-type: application/json |
|||
@token=eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2NDI0MDU2ODcsInN1YiI6IjEyMTc2NDc2ODY1OTgxMzU4MDgiLCJhdXRoSWQiOiIxMTc3MTU4ODQ4ODg1MTY2MDgwIiwiZXhwIjoxNjQyNDkyMDg3fQ.GDHzvVN6kAF3mVanxYTxBBlZP1I08lCD4_zbazLX7AQ |
|||
|
|||
### login |
|||
# @name login |
|||
POST https://test.tall.wiki/gateway/tall3/v3.0/users/signin |
|||
{{type}} |
|||
|
|||
{ |
|||
"client": 1, |
|||
"data": { |
|||
"credential": "123456", |
|||
"identifier": "zy11" |
|||
}, |
|||
"type": 3 |
|||
} |
|||
|
|||
### 查看成员 |
|||
POST {{url}}/deliver/queryChecker |
|||
{{type}} |
|||
Authorization: Bearer {{token}} |
|||
|
|||
{ |
|||
"param":{ |
|||
"projectId": "1418109550141382656" |
|||
} |
|||
} |
|||
|
|||
### 修改编辑交付物名称 |
|||
POST {{url}}/deliver/saveDeliver |
|||
{{type}} |
|||
Authorization: Bearer {{token}} |
|||
|
|||
{ |
|||
"param":{ |
|||
"projectId": "1418109550141382656", |
|||
"taskId": "1418109566541111296", |
|||
"deliverName":"测试交付物1" |
|||
} |
|||
} |
|||
|
|||
### 查询交付物 |
|||
POST {{url}}/deliver/getDeliver |
|||
{{type}} |
|||
Authorization: Bearer {{token}} |
|||
|
|||
{ |
|||
"param":{ |
|||
"taskId": "1418109566541111296" |
|||
} |
|||
} |
|||
|
|||
### 提交交付物信息 |
|||
POST {{url}}/deliver/submitDeliver |
|||
{{type}} |
|||
Authorization: Bearer {{token}} |
|||
|
|||
{ |
|||
"param":{ |
|||
"projectId": "1418109550141382656", |
|||
"deliverId": "1482975132598411264", |
|||
"fileList": [ |
|||
"asdasd" |
|||
], |
|||
"checkerList":[ |
|||
"1418109552909623296", |
|||
"1418109555648503808" |
|||
] |
|||
} |
|||
} |
|||
|
|||
### 检查交付物 |
|||
POST {{url}}/deliver/checkDeliver |
|||
{{type}} |
|||
Authorization: Bearer {{token}} |
|||
|
|||
{ |
|||
"param":{ |
|||
"deliverRecordId": "1482980930758123520", |
|||
"projectId": "1418109550141382656", |
|||
"type": "2", |
|||
"remark": "我后悔了", |
|||
"score": "10.2" |
|||
} |
|||
} |
|||
|
|||
### 查看交付物提交历史 |
|||
POST {{url}}/deliver/queryRecord |
|||
{{type}} |
|||
Authorization: Bearer {{token}} |
|||
|
|||
{ |
|||
"param":{ |
|||
"deliverId": "1482975132598411264" |
|||
} |
|||
} |
|||
|
|||
### 查看检查记录 |
|||
POST {{url}}/deliver/queryCheckLog |
|||
{{type}} |
|||
Authorization: Bearer {{token}} |
|||
|
|||
{ |
|||
"param":{ |
|||
"deliverRecordId": "1482980930758123520" |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
export default { |
|||
namespaced: true, |
|||
state: { |
|||
deliverRecordId: '', // 交付物记录id
|
|||
}, |
|||
getters: {}, |
|||
mutations: { |
|||
/** |
|||
* 设置交付物记录id |
|||
* @param {object} state |
|||
* @param {string} recordId |
|||
*/ |
|||
setDeliverRecordId(state, recordId) { |
|||
state.deliverRecordId = recordId; |
|||
}, |
|||
}, |
|||
actions: {}, |
|||
}; |
|||
@ -0,0 +1,25 @@ |
|||
import { SCENE, api } from '@/config/index'; |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state: { |
|||
apiPath: '/ptccsens/v1.0/finance', // 财务条apiPath
|
|||
}, |
|||
getters: { |
|||
// 完整路径
|
|||
fullPath({ apiPath }) { |
|||
return `${api.baseUrl[SCENE]}${apiPath}`; |
|||
}, |
|||
}, |
|||
mutations: { |
|||
/** |
|||
* 设置apiPath |
|||
* @param {object} state |
|||
* @param {string} path 路径可能随着业务、项目变化 |
|||
*/ |
|||
setApiPath(state, path) { |
|||
state.apiPath = path; |
|||
}, |
|||
}, |
|||
actions: {}, |
|||
}; |
|||
@ -1,56 +1,74 @@ |
|||
export default { |
|||
/** |
|||
* 显示toast |
|||
* @param {string} title 提示内容 |
|||
* @param {number} duration 显示时间 默认2000 |
|||
*/ |
|||
showToast(title, duration = 2000) { |
|||
return uni.showToast({ |
|||
title, |
|||
icon: 'none', |
|||
duration, |
|||
mask: true, |
|||
}); |
|||
}, |
|||
|
|||
// 隐藏toast
|
|||
hideToast() { |
|||
return uni.hideToast(); |
|||
}, |
|||
|
|||
/** |
|||
* 显示加载雪花 |
|||
* @param {string} title |
|||
*/ |
|||
showLoading(title = '玩命加载中...') { |
|||
return uni.showLoading({ |
|||
title, |
|||
mask: true, |
|||
}); |
|||
}, |
|||
|
|||
// 隐藏loading
|
|||
hideLoading() { |
|||
return uni.hideLoading(); |
|||
}, |
|||
|
|||
/** |
|||
* 显示modal弹出框 |
|||
* @param {string} title 标题 |
|||
* @param {string} content 内容 |
|||
* @param {boolean} showCancel 是否显示取消按钮 默认true |
|||
*/ |
|||
showModal(title, content, showCancel = true) { |
|||
return new Promise(function(resolve, reject) { |
|||
uni.showModal({ |
|||
title, |
|||
content, |
|||
showCancel, |
|||
success: ({ confirm, cancel }) => { |
|||
confirm && resolve(); |
|||
cancel && reject(); |
|||
}, |
|||
}); |
|||
}); |
|||
}, |
|||
import { stringify } from 'qs'; |
|||
export default { |
|||
/** |
|||
* 显示toast |
|||
* @param {string} title 提示内容 |
|||
* @param {number} duration 显示时间 默认2000 |
|||
*/ |
|||
showToast(title, duration = 2000) { |
|||
return uni.showToast({ |
|||
title, |
|||
icon: 'none', |
|||
duration, |
|||
mask: true, |
|||
}); |
|||
}, |
|||
|
|||
// 隐藏toast
|
|||
hideToast() { |
|||
return uni.hideToast(); |
|||
}, |
|||
|
|||
/** |
|||
* 显示加载雪花 |
|||
* @param {string} title |
|||
*/ |
|||
showLoading(title = '玩命加载中...') { |
|||
return uni.showLoading({ |
|||
title, |
|||
mask: true, |
|||
}); |
|||
}, |
|||
|
|||
// 隐藏loading
|
|||
hideLoading() { |
|||
return uni.hideLoading(); |
|||
}, |
|||
|
|||
/** |
|||
* 显示modal弹出框 |
|||
* @param {string} title 标题 |
|||
* @param {string} content 内容 |
|||
* @param {boolean} showCancel 是否显示取消按钮 默认true |
|||
*/ |
|||
showModal(title, content, showCancel = true) { |
|||
return new Promise(function (resolve, reject) { |
|||
uni.showModal({ |
|||
title, |
|||
content, |
|||
showCancel, |
|||
success: ({ confirm, cancel }) => { |
|||
confirm && resolve(); |
|||
cancel && reject(); |
|||
}, |
|||
}); |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 打开详情页 |
|||
* @param {object} options |
|||
*/ |
|||
openDetail(options) { |
|||
if (!options) { |
|||
throw new Error('缺少参数'); |
|||
} |
|||
if (!options.url) { |
|||
throw new Error('缺少url参数'); |
|||
} |
|||
const query = stringify(options); |
|||
console.log('query: ', query); |
|||
const path = `/pages/detailWebview/detailWebview?${query}`; |
|||
uni.navigateTo({ url: path }); |
|||
}, |
|||
}; |
|||
|
|||
Loading…
Reference in new issue