|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 799 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 215 B |
@ -1,28 +0,0 @@ |
|||||
<!DOCTYPE html> |
|
||||
<html lang="zh-CN"> |
|
||||
|
|
||||
<head> |
|
||||
<meta charset="utf-8"> |
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|
||||
<title> |
|
||||
<%= htmlWebpackPlugin.options.title %> |
|
||||
</title> |
|
||||
<script> |
|
||||
// document.addEventListener('DOMContentLoaded', function() { |
|
||||
// document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px' |
|
||||
// }) |
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)')) |
|
||||
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />') |
|
||||
</script> |
|
||||
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" /> |
|
||||
</head> |
|
||||
|
|
||||
<body> |
|
||||
<noscript> |
|
||||
<strong>Please enable JavaScript to continue.</strong> |
|
||||
</noscript> |
|
||||
<div id="app"></div> |
|
||||
<!-- built files will be auto injected --> |
|
||||
</body> |
|
||||
|
|
||||
</html> |
|
||||
@ -1,2 +0,0 @@ |
|||||
User-agent: * |
|
||||
Disallow: |
|
||||
@ -1,7 +0,0 @@ |
|||||
.min-0 { |
|
||||
min-width: 0; |
|
||||
} |
|
||||
|
|
||||
.flex-shrink-0 { |
|
||||
flex-shrink: 0; |
|
||||
} |
|
||||
@ -1,9 +1,22 @@ |
|||||
<template> |
<template> |
||||
<view>已测评</view> |
<view> |
||||
|
<view class="flex flex-nowrap items-center"> |
||||
|
<view class="flex-1 flex flex-nowrap items-center"> |
||||
|
<u-rate :count="count" v-model="count" :disabled="true" :size="26" :gutter="2" active-color="#333"></u-rate> |
||||
|
<text class="mx-2">数独</text> |
||||
|
<view class="rounded-full bg-blue-500 w-max u-font-xs text-white px-2 items-center">轻松完成</view> |
||||
|
</view> |
||||
|
<u-icon name="arrow-right" color="#909399"></u-icon> |
||||
|
</view> |
||||
|
</view> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
export default {}; |
export default { |
||||
|
data() { |
||||
|
return { count: 3 }; |
||||
|
}, |
||||
|
}; |
||||
</script> |
</script> |
||||
|
|
||||
<style></style> |
<style></style> |
||||
|
|||||
@ -1,149 +0,0 @@ |
|||||
<template> |
|
||||
<view class="u-font-14" style="height: 100%"> |
|
||||
<!-- <view v-if="pluginContent" @click="setStorage"> |
|
||||
<view |
|
||||
:data-did="task.detailId" |
|
||||
:data-param="param" |
|
||||
:data-pdu="task.planDuration" |
|
||||
:data-pid="projectId" |
|
||||
:data-pstart="task.planStart" |
|
||||
:data-rdu="task.realDuration" |
|
||||
:data-rid="roleId" |
|
||||
:data-tid="task.id" |
|
||||
:data-tname="task.name" |
|
||||
:data-token="token" |
|
||||
:data-rstart="task.realStart" |
|
||||
:data-uid="userId" |
|
||||
style="height: 100%" |
|
||||
v-html="pluginContent" |
|
||||
></view> |
|
||||
</view> --> |
|
||||
|
|
||||
<view @click="setStorage"> |
|
||||
<!-- <plugin-default /> --> |
|
||||
<!-- <component :task="task" :is="pluginComponent"></component> --> |
|
||||
<p-task-title :task="task" v-if="pluginId === '1'" /> |
|
||||
<p-task-description :task="task" v-if="pluginId === '2'" /> |
|
||||
<p-task-duration-delay :task="task" v-if="pluginId === '3'" /> |
|
||||
<p-task-start-time-delay :task="task" v-if="pluginId === '4'" /> |
|
||||
<p-upload-deliverable :task="task" v-if="pluginId === '5' && isMine" /> |
|
||||
<p-delivery-history :task="task" v-if="pluginId === '5' && !isMine" /> |
|
||||
<p-subtasks :task="task" v-if="pluginId === '6'" /> |
|
||||
<p-subproject :task="task" v-if="pluginId === '7'" /> |
|
||||
<!-- <p-task-countdown :task="task" v-if="pluginId === '8'" /> --> |
|
||||
<p-manage-project :task="task" v-if="pluginId === '9'" /> |
|
||||
<p-manage-role :task="task" v-if="pluginId === '10'" /> |
|
||||
<p-manage-member :task="task" v-if="pluginId === '11'" /> |
|
||||
<p-manage-task :task="task" v-if="pluginId === '12'" /> |
|
||||
<p-wbs-import :task="task" v-if="pluginId === '13' || pluginId === '14'" /> |
|
||||
<p-deliver-check :task="task" v-if="pluginId === '15'" /> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapGetters, mapState, mapActions } from 'vuex'; |
|
||||
|
|
||||
export default { |
|
||||
name: 'Plugin', |
|
||||
props: { |
|
||||
task: { default: () => {}, type: Object }, |
|
||||
pluginId: { default: '1', type: String }, |
|
||||
styleType: { default: 0, type: Number }, |
|
||||
pluginTaskId: { default: '', type: String }, |
|
||||
param: { type: String, default: '' }, |
|
||||
}, |
|
||||
|
|
||||
data() { |
|
||||
return { pluginContent: null }; |
|
||||
}, |
|
||||
|
|
||||
computed: { |
|
||||
...mapState('role', ['roleId']), |
|
||||
...mapState('user', ['token']), |
|
||||
...mapGetters('user', ['userId']), |
|
||||
...mapGetters('project', ['projectId']), |
|
||||
...mapGetters('role', ['isMine']), |
|
||||
|
|
||||
// 插件名称 |
|
||||
// pluginComponent() { |
|
||||
// const target = this.$t.plugin.defaults.find(item => item.id === +this.pluginId); |
|
||||
// if (!target) return ''; |
|
||||
// return target.component; |
|
||||
// }, |
|
||||
}, |
|
||||
|
|
||||
async created() { |
|
||||
if (this.pluginId === '5') { |
|
||||
// 根据项目id获取成员列表 |
|
||||
await this.getAllMembers({ projectId: this.projectId }); |
|
||||
} |
|
||||
await this.getPlugin(); |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
...mapActions('role', ['getAllMembers']), |
|
||||
// 获取插件信息 |
|
||||
async getPlugin() { |
|
||||
const { pluginId, styleType } = this; |
|
||||
const params = { pluginId, styleType }; |
|
||||
this.$t.$q.getOtherPlugin(params, (err, data) => { |
|
||||
if (err) { |
|
||||
console.error('err: ', err); |
|
||||
} else { |
|
||||
if (!data || !data.id) return; |
|
||||
const reg = /data-root=["|']?(\w+)["|']?/gi; |
|
||||
let uuid = ''; |
|
||||
// FIXME: 没有兼容 只有js, 没有html的情况 |
|
||||
if (data.html) { |
|
||||
// 查有没有data-root=“xxx” 有的话 将xxx替换为 pluginTaskId |
|
||||
|
|
||||
if (reg.test(data.html)) { |
|
||||
uuid = RegExp.$1; |
|
||||
const str = data.html.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`); |
|
||||
this.pluginContent = str; |
|
||||
} else { |
|
||||
this.pluginContent = data.html; |
|
||||
} |
|
||||
|
|
||||
const str = data.js.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`); |
|
||||
this.handleDom(str); |
|
||||
} |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
// if (data.js) { |
|
||||
// if (reg.test(data.js)) { |
|
||||
// const uuid = RegExp.$1; |
|
||||
// const str = data.js.replace(new RegExp(uuid, 'g'), `p${this.pluginTaskId}`); |
|
||||
// this.handleDom(str); |
|
||||
// } else { |
|
||||
// this.handleDom(data.js); |
|
||||
// } |
|
||||
// } |
|
||||
}, |
|
||||
|
|
||||
// 创建script dom |
|
||||
handleDom(js) { |
|
||||
const { pluginTaskId } = this; |
|
||||
let domList = Array.from(document.getElementsByTagName('script')); |
|
||||
const index = domList.findIndex(item => item.id === `p${pluginTaskId}`); |
|
||||
if (index >= 0) { |
|
||||
document.body.removeChild(document.getElementById(`p${pluginTaskId}`)); |
|
||||
} |
|
||||
const scriptDom = document.createElement('script'); |
|
||||
scriptDom.id = `p${pluginTaskId}`; |
|
||||
scriptDom.setAttribute('data-type', 'plugin'); |
|
||||
scriptDom.innerHTML = js; |
|
||||
this.$nextTick(() => { |
|
||||
document.body.append(scriptDom); |
|
||||
}); |
|
||||
}, |
|
||||
|
|
||||
// 点击时存储 storage |
|
||||
setStorage() { |
|
||||
this.$t.storage.setStorageSync('roleId', this.roleId); |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
@ -1,84 +0,0 @@ |
|||||
# skeleton组件 |
|
||||
|
|
||||
### 1.描述 |
|
||||
> 此组件用于加载数据时占位图显示,跟vant-ui骨架屏用法相似,但比vant-ui更灵活 |
|
||||
|
|
||||
|
|
||||
|
|
||||
### 2.用法 |
|
||||
|
|
||||
- 基本用法 |
|
||||
|
|
||||
代码: |
|
||||
```vue |
|
||||
//基本用法 |
|
||||
<skeleton :row="3" animate :loading="loading" > |
|
||||
<view> |
|
||||
content |
|
||||
</view> |
|
||||
</skeleton> |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
- **显示 title ——通过 **title 属性显示title占位图 |
|
||||
|
|
||||
代码: |
|
||||
```vue |
|
||||
//显示 title——通过 title 属性显示title占位图 |
|
||||
<skeleton :row="3" title animate :loading="loading"> |
|
||||
<view> |
|
||||
content |
|
||||
</view> |
|
||||
</skeleton> |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
- 显示头像(上面)——通过avatar=‘top’让头像的占位图上面显示 |
|
||||
|
|
||||
代码: |
|
||||
```vue |
|
||||
<skeleton :avatar="top" avatarAlign="left" :row="3" animate :loading="loading" style="margin-top:24rpx;"> |
|
||||
<view> |
|
||||
content |
|
||||
</view> |
|
||||
</skeleton> |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
- 显示头像(左边)——通过avatar=‘left’让头像的占位图左边显示 |
|
||||
|
|
||||
代码: |
|
||||
```vue |
|
||||
<skeleton title :avatar="left" :row="3" animate :loading="loading" style="margin-top:24rpx;"> |
|
||||
<view> |
|
||||
content |
|
||||
</view> |
|
||||
</skeleton> |
|
||||
``` |
|
||||
|
|
||||
|
|
||||
- 显示banner**——通过 **banner属性显示banner占位图(只显示banner,不显示内容占位图时设置row="0") |
|
||||
|
|
||||
代码: |
|
||||
```vue |
|
||||
<skeleton banner :row="0" animate :loading="loading" style="margin-top:24rpx;"> |
|
||||
<view> |
|
||||
content |
|
||||
</view> |
|
||||
</skeleton> |
|
||||
``` |
|
||||
### |
|
||||
### 3. API |
|
||||
### Props |
|
||||
| **属性名** | **说明** | **类型** | **默认值** | 可取值 | |
|
||||
| --- | --- | --- | --- | --- | |
|
||||
| loading | 是否显示骨架屏 | Boolean | true | true/false | |
|
||||
| row | 段落行数 | Number | String | 3 | 0表示不展现 | |
|
||||
| rowWidth | 段落行宽度 | Boolean | Number | '100%' | | |
|
||||
| title | 是否显示标题 | Boolean | String | false | | |
|
||||
| banner | 是否显示banner | Boolean | String | false | | |
|
||||
| animate | 是否开启动画 | Boolean | String | false | | |
|
||||
| avatar | 头像位置 | Boolean | String | ''空 | left/top | |
|
||||
| avatarSize | 头像大小 | String | - | | |
|
||||
| avatarShape | 头像形状 | String | circle | circle/round | |
|
||||
|
|
||||
@ -0,0 +1,10 @@ |
|||||
|
<template> |
||||
|
<view> 测试内容 </view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default {}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
</style> |
||||
@ -0,0 +1,10 @@ |
|||||
|
<template> |
||||
|
<view> 1.请记住以下物品 </view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default {}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
</style> |
||||
@ -1,460 +0,0 @@ |
|||||
<template> |
|
||||
<div class="new-projects-box"> |
|
||||
<div class="form"> |
|
||||
<!-- 项目名称 --> |
|
||||
<view class="mb-3 font-bold text-base flex justify-center">新建任务</view> |
|
||||
<div class="flex items-center mb-2"> |
|
||||
<div>名称<span class="text-red-500">*</span>:</div> |
|
||||
<u-input max-length="5" v-model="name" :type="type" :border="border" /> |
|
||||
</div> |
|
||||
<!-- 起止时间 --> |
|
||||
<div class="mb-2"> |
|
||||
<div>起止时间:</div> |
|
||||
<u-input placeholder="请选择起止时间" v-model="timeValue" :type="type" :border="border" @click="$emit('showTime')" /> |
|
||||
</div> |
|
||||
<!-- 多选框 --> |
|
||||
<div class="flex justify-between items-center"> |
|
||||
<div>负责人<span class="text-red-500">*</span>:</div> |
|
||||
<div class="flex-1" v-if="hasRole">{{ roleName }}</div> |
|
||||
<div label="负责人" class="flex-1" v-else> |
|
||||
<u-dropdown disabled ref="uDropdown" placeholder="请选择负责人"> |
|
||||
<u-dropdown-item :title="roleList"> |
|
||||
<view class="slot-content bg-white"> |
|
||||
<div |
|
||||
class="flex flex-row justify-between mb-1 drop-item" |
|
||||
v-for="(role, roleIndex) in roleOptions" |
|
||||
:key="roleIndex" |
|
||||
@click="change(roleIndex)" |
|
||||
> |
|
||||
<view v-model="role.id">{{ role.name }}</view> |
|
||||
<u-icon v-if="role.dropdownShow" name="checkbox-mark" color="#2979ff" size="28"></u-icon> |
|
||||
</div> |
|
||||
</view> |
|
||||
</u-dropdown-item> |
|
||||
</u-dropdown> |
|
||||
</div> |
|
||||
</div> |
|
||||
<!-- 下拉图标 --> |
|
||||
<div class="flex justify-center my-6"> |
|
||||
<u-icon v-if="arrow" name="arrow-down" size="28" @click="openDropdown"></u-icon> |
|
||||
<u-icon v-else name="arrow-up" size="28" @click="closeSecondDropdown"></u-icon> |
|
||||
</div> |
|
||||
<!-- 下拉框的内容 --> |
|
||||
<div v-if="show" class="mb-6"> |
|
||||
<!-- 描述 --> |
|
||||
<div class="flex items-center mb-2"> |
|
||||
<div>描述:</div> |
|
||||
<u-input v-model="description" max-length="48" type="textarea" height="36" auto-height :border="border" /> |
|
||||
</div> |
|
||||
<!-- 所属项目 --> |
|
||||
<div class="w flex items-center mb-2"> |
|
||||
<div>所属项目<span class="text-red-500">*</span>:</div> |
|
||||
<div>{{ project.name }}</div> |
|
||||
</div> |
|
||||
<!-- 所属任务 --> |
|
||||
<div class="w flex items-center mb-2" v-if="task && task.id"> |
|
||||
<div>所属任务:</div> |
|
||||
<div>{{ task.name }}</div> |
|
||||
</div> |
|
||||
<!-- 上道工序 --> |
|
||||
<div class="flex items-center mb-2"> |
|
||||
<div>上道工序:</div> |
|
||||
<InputSearch |
|
||||
@searchPrevTask="searchPrevTask" |
|
||||
:dataSource="allTasks" |
|
||||
@select="handleChange" |
|
||||
@clearAllTasks="clearAllTasks" |
|
||||
placeholder="请输入上道工序" |
|
||||
/> |
|
||||
</div> |
|
||||
<!-- 检查人多选框 --> |
|
||||
<div class="flex justify-between items-center"> |
|
||||
<div>检查人<span class="text-red-500">*</span>:</div> |
|
||||
<div label="检查人" class="flex-1"> |
|
||||
<u-dropdown ref="dropdown"> |
|
||||
<u-dropdown-item :title="checkerList"> |
|
||||
<view class="slot-content bg-white"> |
|
||||
<div |
|
||||
class="flex flex-row justify-between mb-1 drop-item" |
|
||||
v-for="(checkoutOption, Index) in checkoutOptions" |
|
||||
:key="Index" |
|
||||
@click="choose(Index)" |
|
||||
> |
|
||||
<view v-model="checkoutOption.value">{{ checkoutOption.name }}</view> |
|
||||
<u-icon v-if="checkoutOption.dropdownShow" name="checkbox-mark" color="#2979ff" size="28"></u-icon> |
|
||||
</div> |
|
||||
</view> |
|
||||
</u-dropdown-item> |
|
||||
</u-dropdown> |
|
||||
</div> |
|
||||
</div> |
|
||||
<!-- 是否是日常任务 --> |
|
||||
<div class="flex justify-between items-center mt-6"> |
|
||||
是否是日常任务: |
|
||||
<u-switch v-model="isGlobal" size="28"></u-switch> |
|
||||
</div> |
|
||||
<div class="mt-6"> |
|
||||
<div>交付物:</div> |
|
||||
<div v-for="(sort, sortIndex) in deliverSort" :key="sortIndex"> |
|
||||
<u-input |
|
||||
@blur="addDeliverInput" |
|
||||
v-model="sort.name" |
|
||||
:placeholder="`交付物名称${sortIndex + 1}`" |
|
||||
:type="type" |
|
||||
:border="border" |
|
||||
/> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="flex items-center mb-6"> |
|
||||
<u-button type="primary" size="medium" @click="setParameters">提交</u-button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapState, mapGetters, mapMutations } from 'vuex'; |
|
||||
|
|
||||
export default { |
|
||||
props: { |
|
||||
startTime: { |
|
||||
type: String, |
|
||||
default: '', |
|
||||
}, |
|
||||
endTime: { |
|
||||
type: String, |
|
||||
default: '', |
|
||||
}, |
|
||||
task: { |
|
||||
type: Object, |
|
||||
default: null, |
|
||||
}, |
|
||||
}, |
|
||||
data() { |
|
||||
return { |
|
||||
arrow: true, |
|
||||
show: false, |
|
||||
isGlobal: false, //是否日常任务 |
|
||||
name: '', //名称 |
|
||||
showChooseTime: false, |
|
||||
timeValue: '', //起止时间 |
|
||||
description: '', //描述 |
|
||||
projectShow: false, //所属项目模糊搜索展示 |
|
||||
processTaskId: '', //上道工序 |
|
||||
type: 'text', |
|
||||
border: true, |
|
||||
roleList: undefined, //负责人默认多选 |
|
||||
checkerList: undefined, //检查人默认多选 |
|
||||
roleOptions: [], // 负责人下拉多选列表 |
|
||||
checkoutOptions: [], // 检查人下拉多选列表 |
|
||||
roleIdList: [], // 选中的负责人id |
|
||||
checkerIdList: [], // 选中的检查人id |
|
||||
deliverables: [], // 交付物 |
|
||||
deliverSort: [{ name: '' }], // 交付物排序 |
|
||||
allTasks: [], |
|
||||
roleName: '', // 负责人名字 |
|
||||
hasRole: false, // 有没有负责人 |
|
||||
}; |
|
||||
}, |
|
||||
|
|
||||
computed: { |
|
||||
...mapState('role', ['visibleRoles', 'roleId']), |
|
||||
...mapState('project', ['project']), |
|
||||
...mapState('task', ['tasks']), |
|
||||
...mapGetters('project', ['projectId']), |
|
||||
}, |
|
||||
|
|
||||
watch: { |
|
||||
endTime(val) { |
|
||||
if (val) { |
|
||||
this.timeValue = this.startTime + ' 至 ' + val; |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
|
|
||||
mounted() { |
|
||||
// 获取负责人和检查人列表 |
|
||||
if (this.visibleRoles.length) { |
|
||||
this.visibleRoles.forEach(role => { |
|
||||
role.dropdownShow = false; |
|
||||
role.status = false; |
|
||||
}); |
|
||||
} |
|
||||
this.roleOptions = this.$u.deepClone(this.visibleRoles); |
|
||||
this.checkoutOptions = this.$u.deepClone(this.visibleRoles); |
|
||||
|
|
||||
// 判断有没有负责人 是不是添加子任务 |
|
||||
if (this.roleId) { |
|
||||
const item = this.visibleRoles.find(r => r.id === this.roleId); |
|
||||
if (item) { |
|
||||
this.roleName = item.name; |
|
||||
this.hasRole = true; |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
...mapMutations('task', ['updateTasks']), |
|
||||
|
|
||||
// 负责人下拉多选选中 |
|
||||
change(index) { |
|
||||
let arr = [...this.roleOptions]; |
|
||||
// 选择多选项图标的展示 |
|
||||
arr[index].dropdownShow = !arr[index].dropdownShow; |
|
||||
// 多选展示的改变 |
|
||||
this.roleList = arr[index].name; |
|
||||
let shows = ''; |
|
||||
// 遍历arr,如果选中,添加到多选展示框上 |
|
||||
arr.map(val => { |
|
||||
if (val.dropdownShow === true) { |
|
||||
shows += val.name + ','; |
|
||||
this.roleIdList.push(val.id); |
|
||||
} |
|
||||
}); |
|
||||
this.roleOptions = [...arr]; |
|
||||
// 删除最后的',' |
|
||||
this.roleList = shows.slice(0, shows.length - 1); |
|
||||
}, |
|
||||
|
|
||||
// 检查人下拉多选选中 |
|
||||
choose(index) { |
|
||||
let arr = [...this.checkoutOptions]; |
|
||||
// 选择多选项图标的展示 |
|
||||
arr[index].dropdownShow = !arr[index].dropdownShow; |
|
||||
// 多选展示的改变 |
|
||||
this.checkerList = arr[index].name; |
|
||||
let shows = ''; |
|
||||
// 遍历arr,如果选中,添加到多选展示框上 |
|
||||
arr.map(val => { |
|
||||
if (val.dropdownShow === true) { |
|
||||
shows += val.name + ','; |
|
||||
this.checkerIdList.push(val.id); |
|
||||
} |
|
||||
}); |
|
||||
this.checkoutOptions = [...arr]; |
|
||||
// 删除最后的',' |
|
||||
this.checkerList = shows.slice(0, shows.length - 1); |
|
||||
// this.roleList = arr[value - 1].name; |
|
||||
}, |
|
||||
|
|
||||
// 打开下拉框 |
|
||||
openDropdown() { |
|
||||
this.arrow = !this.arrow; |
|
||||
this.show = true; |
|
||||
}, |
|
||||
|
|
||||
// 关闭下拉框 |
|
||||
closeSecondDropdown() { |
|
||||
this.arrow = !this.arrow; |
|
||||
this.show = false; |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 模糊查询 查找项目下的任务 |
|
||||
* @param name 任务名 |
|
||||
* @param projectId 项目id |
|
||||
*/ |
|
||||
async searchPrevTask(val) { |
|
||||
try { |
|
||||
const params = { name: val, projectId: this.projectId }; |
|
||||
const data = await this.$u.api.queryTaskOfProject(params); |
|
||||
this.allTasks = data; |
|
||||
return data; |
|
||||
} catch (error) { |
|
||||
console.error('error: ', error); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
//用户点击获取的数据 |
|
||||
handleChange(data) { |
|
||||
console.log('data', data); |
|
||||
this.processTaskId = data.detailId; |
|
||||
}, |
|
||||
// 清空模糊查询信息 |
|
||||
clearAllTasks() { |
|
||||
this.allTasks = []; |
|
||||
}, |
|
||||
|
|
||||
// 数组最后一项有值 添加一条交付物输入框 |
|
||||
addDeliverInput() { |
|
||||
if (this.deliverSort[this.deliverSort.length - 1].name) { |
|
||||
this.deliverSort.push({ name: '' }); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
// 设置提交参数 |
|
||||
async setParameters() { |
|
||||
const { |
|
||||
projectId, |
|
||||
task, |
|
||||
name, |
|
||||
startTime, |
|
||||
endTime, |
|
||||
hasRole, |
|
||||
roleIdList, |
|
||||
roleId, |
|
||||
description, |
|
||||
processTaskId, |
|
||||
checkerIdList, |
|
||||
isGlobal, |
|
||||
} = this; |
|
||||
if (!name) { |
|
||||
this.$t.ui.showToast('请输入名称'); |
|
||||
return; |
|
||||
} |
|
||||
if ((!roleIdList || !roleIdList.length) && !hasRole) { |
|
||||
this.$t.ui.showToast('请选择负责人'); |
|
||||
return; |
|
||||
} |
|
||||
if (!checkerIdList || !checkerIdList.length) { |
|
||||
this.$t.ui.showToast('请选择检查人'); |
|
||||
return; |
|
||||
} |
|
||||
const deliverList = []; |
|
||||
this.deliverSort.forEach(item => { |
|
||||
if (item.name) { |
|
||||
deliverList.push(item.name); |
|
||||
} |
|
||||
}); |
|
||||
const params = { |
|
||||
name, |
|
||||
startTime: startTime ? this.$moment(startTime).format('x') - 0 : '', |
|
||||
endTime: endTime ? this.$moment(endTime).format('x') - 0 : '', |
|
||||
roleIdList: hasRole ? [roleId] : roleIdList, |
|
||||
description, |
|
||||
projectId, |
|
||||
parentTaskId: task && task.id ? task.id : '', // 父任务 |
|
||||
processTaskId, // 上道工序 TODO |
|
||||
checkerIdList, |
|
||||
global: isGlobal ? 1 : 0, |
|
||||
deliverList, |
|
||||
}; |
|
||||
await this.handleSubmit(params); |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 新建任务 |
|
||||
* @param name 任务名 |
|
||||
* @param startTime 开始时间 |
|
||||
* @param endTime 结束时间 |
|
||||
* @param roleIdList 负责人id(数组) |
|
||||
* @param description 描述 |
|
||||
* @param projectId 所属项目id |
|
||||
* @param parentTaskId 所属任务id |
|
||||
* @param processTaskId 上道工序(任务id) |
|
||||
* @param checkerIdList 检查人id(数组) |
|
||||
* @param global 是否日常任务 0否 1是 |
|
||||
* @param deliverList 交付物名字(数组) |
|
||||
*/ |
|
||||
async handleSubmit(params) { |
|
||||
try { |
|
||||
const data = await this.$u.api.saveTask(params); |
|
||||
// TODO 任务新建成功 继续 or 取消 |
|
||||
this.$emit('closeMask'); |
|
||||
const newTasks = { |
|
||||
data: data[0], |
|
||||
processTaskId: params.processTaskId, |
|
||||
}; |
|
||||
// 将新加的任务加到store |
|
||||
// 判断不是子任务 |
|
||||
if (!this.task || !this.task.id) { |
|
||||
this.addNewTasks(newTasks); |
|
||||
} |
|
||||
} catch (error) { |
|
||||
this.$emit('closeMask'); |
|
||||
console.error('error: ', error); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
// 添加任务后更新tasks |
|
||||
addNewTasks(data) { |
|
||||
const oldTasks = this.$u.deepClone(this.tasks); |
|
||||
let res = data.data; |
|
||||
// 判断有没有选择上道工序 |
|
||||
if (data.processTaskId) { |
|
||||
const index = oldTasks.find(item => item.detailId === data.processTaskId); |
|
||||
if (index) { |
|
||||
oldTasks.splice(index + 1, 0, res); |
|
||||
} |
|
||||
} else { |
|
||||
this.setAddPosition(res, oldTasks); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
// 设置添加位置 |
|
||||
setAddPosition(res, oldTasks) { |
|
||||
if (res.planStart - 0 < oldTasks[0].planStart - 0) { |
|
||||
// 开始时间小于列表的第一个 插入最前面 |
|
||||
oldTasks.splice(0, 0, res); |
|
||||
} else if (res.planStart - 0 === oldTasks[0].planStart - 0) { |
|
||||
// 开始时间等于列表的第一个 插入第二 |
|
||||
oldTasks.splice(1, 0, res); |
|
||||
} else if (res.planStart - 0 >= oldTasks[oldTasks.length - 1].planStart - 0) { |
|
||||
// 开始时间大等于列表的最后一个 插入最后 |
|
||||
oldTasks.splice(-1, 0, res); |
|
||||
} else { |
|
||||
// 判断开始时间在列表中间的哪个位置 |
|
||||
for (let i = 0; i < oldTasks.length; i++) { |
|
||||
const item = oldTasks[i]; |
|
||||
if (res.planStart - 0 > item.planStart - 0) { |
|
||||
if (res.planStart - 0 <= oldTasks[i + 1].planStart - 0) { |
|
||||
oldTasks.splice(i + 1, 0, res); |
|
||||
console.log('res: ', res); |
|
||||
return; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
// TODO: 不能全更新 |
|
||||
console.log('oldTasks: ', oldTasks); |
|
||||
this.updateTasks([...oldTasks]); |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<style lang="scss" scoped> |
|
||||
.form { |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
width: 100%; |
|
||||
max-height: 400px; |
|
||||
overflow-y: scroll; |
|
||||
} |
|
||||
|
|
||||
.drop-item { |
|
||||
border-bottom: 1px solid #f1f1f1; |
|
||||
padding: 16rpx; |
|
||||
} |
|
||||
|
|
||||
::v-deep.u-input--border { |
|
||||
border: none; |
|
||||
border-radius: 0; |
|
||||
} |
|
||||
::v-deep.u-dropdown__menu__item > uni-view { |
|
||||
border: none !important; |
|
||||
padding: 5px; |
|
||||
} |
|
||||
.u-input { |
|
||||
border-bottom: 1px solid #dcdfe6; |
|
||||
} |
|
||||
|
|
||||
.new-projects-box { |
|
||||
margin-top: 20px; |
|
||||
padding: 15px; |
|
||||
width: 100%; |
|
||||
overflow: hidden; |
|
||||
} |
|
||||
|
|
||||
.w { |
|
||||
width: 300px; |
|
||||
height: 39px; |
|
||||
} |
|
||||
|
|
||||
::v-deep .u-dropdown__menu__item .u-flex { |
|
||||
border: 0 !important; |
|
||||
border-bottom: 1px solid #dcdfe6 !important; |
|
||||
padding: 0 20rpx; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,35 +0,0 @@ |
|||||
<template> |
|
||||
<web-view :src="src" /> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
data() { |
|
||||
return { src: '' }; |
|
||||
}, |
|
||||
|
|
||||
onLoad(options) { |
|
||||
console.log('options: ', options); |
|
||||
if (!options) { |
|
||||
this.$t.ui.showModal('缺少参数, 请返回重试'); |
|
||||
} else { |
|
||||
const { p, u, pname, url } = options; |
|
||||
if (pname) { |
|
||||
uni.setNavigationBarTitle({ title: pname }); |
|
||||
} |
|
||||
if (!u) { |
|
||||
this.$t.ui.showToast('缺少用户信息, 请登录'); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (!p || !url) { |
|
||||
this.$t.ui.showToast('缺少项目信息, 请重新打开'); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
const baseUrl = process.env.VUE_APP_PROJECT_PATH; |
|
||||
this.src = `${baseUrl}/${this.$t.app.version}/#/?u=${u}&p=${p}&url=${url}&pname=${pname}`; |
|
||||
} |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
@ -1,5 +1,5 @@ |
|||||
<template> |
<template> |
||||
<view :style="{ height: height }" class="flex flex-col overflow-hidden u-font-14"> |
<view :style="{ height: height }" class="flex flex-col overflow-hidden u-font-16"> |
||||
<!-- 标题栏 --> |
<!-- 标题栏 --> |
||||
<Title /> |
<Title /> |
||||
|
|
||||
@ -0,0 +1,43 @@ |
|||||
|
<template> |
||||
|
<view class="flex flex-col p-3"> |
||||
|
<TestTitle /> |
||||
|
<u-line class="my-2" color="#c8c7cc" /> |
||||
|
<TestMain /> |
||||
|
<u-button class="my-10" type="primary">答题</u-button> |
||||
|
<u-button class="my-10" type="primary" @click="viewResults">查看测评结果</u-button> |
||||
|
</view> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import TestTitle from 'components/Test/TestTitle'; |
||||
|
import TestMain from 'components/Test/TestMain'; |
||||
|
import { mapState, mapGetters, mapMutations } from 'vuex'; |
||||
|
|
||||
|
export default { |
||||
|
components: { TestTitle, TestMain }, |
||||
|
|
||||
|
computed: { |
||||
|
...mapState('project', ['project']), |
||||
|
...mapGetters('user', ['userId']), |
||||
|
}, |
||||
|
|
||||
|
methods: { |
||||
|
...mapMutations('task', ['setIsEvaluated']), |
||||
|
|
||||
|
viewResults() { |
||||
|
this.setIsEvaluated(true); |
||||
|
|
||||
|
const { name, id, url } = this.project; |
||||
|
url && (uni.$t.domain = url); |
||||
|
this.$u.route('/pagesProject/project/project', { |
||||
|
u: this.userId, |
||||
|
p: id, |
||||
|
pname: name, |
||||
|
url: encodeURIComponent(url), |
||||
|
}); |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"></style> |
||||
@ -1,64 +0,0 @@ |
|||||
<template> |
|
||||
<!-- 上传交付物 --> |
|
||||
<view class="px-3 py-6 bg-white"> |
|
||||
<u-input :auto-height="autoHeight" :border="border" :height="height" :type="type" placeholder="输入备注" v-model="remark" /> |
|
||||
<view class="flex flex-row-reverse text-xs text-gray-400 mt-2">{{ wordNum }}/140</view> |
|
||||
<!-- 评分 --> |
|
||||
<view class="flex justify-between mt-3"> |
|
||||
<slider :value="score" @change="sliderChange" max="100" min="0" show-value style="width: 60%" /> |
|
||||
<u-input :border="border" :type="type1" @input="changeNumber" maxlength="100" placeholder="输入分数" v-model="score" /> |
|
||||
</view> |
|
||||
|
|
||||
<view class="flex flex-col justify-center mt-5"> |
|
||||
<u-button @click="submit" size="medium" type="primary">提交</u-button> |
|
||||
<u-button @click="$emit('closeScore')" class="mt-2" size="medium">取消</u-button> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
name: 'p-deliver-check', |
|
||||
data() { |
|
||||
return { |
|
||||
remark: '', |
|
||||
type: 'textarea', |
|
||||
border: true, |
|
||||
height: 100, |
|
||||
autoHeight: true, |
|
||||
wordNum: 0, |
|
||||
score: 0, |
|
||||
type1: 'number', |
|
||||
}; |
|
||||
}, |
|
||||
|
|
||||
watch: { |
|
||||
remark(val) { |
|
||||
this.wordNum = val.length; |
|
||||
}, |
|
||||
|
|
||||
score(val) { |
|
||||
this.score1 = val; |
|
||||
}, |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
// 提交交付物 |
|
||||
submit() { |
|
||||
this.$emit('submit', this.remark, this.score); |
|
||||
}, |
|
||||
|
|
||||
sliderChange(e) { |
|
||||
this.score = e.detail.value; |
|
||||
}, |
|
||||
|
|
||||
changeNumber(e) { |
|
||||
if (e > 100) { |
|
||||
this.score = 100; |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<style></style> |
|
||||
@ -1,140 +0,0 @@ |
|||||
<template> |
|
||||
<!-- 交付物 --> |
|
||||
<view class="mt-3"> |
|
||||
<view v-if="lists && lists.length"> |
|
||||
<view :key="list.id" v-for="list in lists"> |
|
||||
<view class="p-3 mt-3 shadow"> |
|
||||
<view class="text-gray-400 pb-2"> |
|
||||
<span class="mr-4">{{ list.name }}</span> |
|
||||
<span>{{ $moment(+list.time).format('YYYY-MM-DD HH:mm:ss') }}</span> |
|
||||
</view> |
|
||||
<view class="pb-2 flex flex-wrap overflow-hidden" v-if="list.content"> |
|
||||
<a :href="list.content" class="text-blue-500" target="_blank" v-if="CheckUrl(list.content)">{{ list.content }}</a> |
|
||||
<span v-else>{{ list.content }}</span> |
|
||||
</view> |
|
||||
<view :key="checker.checkerId" v-for="checker in list.checkerList" class="mb-2"> |
|
||||
<view class="flex justify-between"> |
|
||||
<view class="font-bold"> |
|
||||
{{ checker.checkerName }} |
|
||||
<span v-if="checker.isMine">(我)</span> |
|
||||
</view> |
|
||||
<view> |
|
||||
<span class="text-blue-500" v-if="checker.status === 1">通过</span> |
|
||||
<span class="text-red-500" v-if="checker.status === 2">驳回</span> |
|
||||
<span class="ml-4" v-if="checker.status !== 0">{{ checker.score }}分</span> |
|
||||
<span class="text-gray-400" v-if="checker.status === 0 && !checker.isMine">未审核</span> |
|
||||
<view v-if="checker.status === 0 && checker.isMine"> |
|
||||
<u-button @click="showScore(checker.checkId, 2)" class="mr-3" plain size="mini" type="error">驳回</u-button> |
|
||||
<u-button @click="showScore(checker.checkId, 1)" plain size="mini" type="primary">通过</u-button> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
<view class="text-gray-400 text-xs mt-1">{{ checker.remark }}</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
</view> |
|
||||
<u-empty icon-size="90" mode="history" text="暂未上传交付物" v-else></u-empty> |
|
||||
|
|
||||
<!-- 评分 --> |
|
||||
<uni-popup :maskClick="false" background-color="#fff" ref="popup" type="bottom"> |
|
||||
<PDeliverCheck @closeScore="closeScore" @submit="submit"></PDeliverCheck> |
|
||||
</uni-popup> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapGetters } from 'vuex'; |
|
||||
import UniPopup from '../../components/uni-popup/uni-popup.vue'; |
|
||||
import PDeliverCheck from '../p-deliver-check/p-deliver-check.vue'; |
|
||||
|
|
||||
export default { |
|
||||
name: 'p-delivery-history', |
|
||||
props: { task: { type: Object, default: null } }, |
|
||||
components: { PDeliverCheck, UniPopup }, |
|
||||
data() { |
|
||||
return { |
|
||||
lists: [], |
|
||||
show: false, |
|
||||
options: null, |
|
||||
loading: true, // 是否显示骨架屏组件 |
|
||||
}; |
|
||||
}, |
|
||||
|
|
||||
computed: mapGetters('project', ['projectId']), |
|
||||
|
|
||||
mounted() { |
|
||||
this.getDeliverOfTask(); |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
async getDeliverOfTask() { |
|
||||
try { |
|
||||
const { projectId, task } = this; |
|
||||
const params = { projectId, taskSubId: task.id }; |
|
||||
const data = await this.$u.api.queryDeliverOfTask(params); |
|
||||
this.lists = data; |
|
||||
} catch (error) { |
|
||||
console.error('p-delivery-history.vue getDeliverOfTask error: ', error); |
|
||||
this.$t.ui.showToast(error.msg || '提交失败'); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
showScore(checkId, status) { |
|
||||
// 通过组件定义的ref调用uni-popup方法 ,如果传入参数 ,type 属性将失效 ,仅支持 ['top','left','bottom','right','center'] |
|
||||
this.$refs.popup.open('bottom'); |
|
||||
this.options = { checkId, status }; |
|
||||
}, |
|
||||
|
|
||||
closeScore() { |
|
||||
this.$refs.popup.close('bottom'); |
|
||||
}, |
|
||||
|
|
||||
async submit(remark, score) { |
|
||||
try { |
|
||||
await this.checkDeliver(remark, score); |
|
||||
this.closeScore(); |
|
||||
} catch (error) { |
|
||||
console.error('error: ', error); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 检查交付物 |
|
||||
* @param {string} checkId 检查记录id |
|
||||
* @param {string} projectId 项目id |
|
||||
* @param {string} remark 评论 |
|
||||
* @param {number} score 分数 |
|
||||
* @param {number} status 检查状态(1-通过,2-驳回) |
|
||||
*/ |
|
||||
async checkDeliver(remark, score) { |
|
||||
try { |
|
||||
this.show = true; |
|
||||
const { projectId, options } = this; |
|
||||
const { checkId, status } = options; |
|
||||
const params = { checkId, projectId, status, remark, score }; |
|
||||
await this.$u.api.checkDeliver(params); |
|
||||
this.$t.ui.showToast('交付物检查成功'); |
|
||||
this.options = null; |
|
||||
this.getDeliverOfTask(); |
|
||||
} catch (error) { |
|
||||
console.error('p-delivery-history.vue checkDeliver error: ', error); |
|
||||
this.$t.ui.showToast('交付物检查失败,请稍后重试'); |
|
||||
this.options = null; |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
// 判断内容是不是链接 |
|
||||
CheckUrl(url) { |
|
||||
var reg = /^([hH][tT]{2}[pP]:\/\/|[hH][tT]{2}[pP][sS]:\/\/)(.)+$/; |
|
||||
if (!reg.test(url)) { |
|
||||
return false; |
|
||||
} else { |
|
||||
return true; |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<style></style> |
|
||||
@ -1,7 +0,0 @@ |
|||||
<template> |
|
||||
<view>成员管理</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default {}; |
|
||||
</script> |
|
||||
@ -1,7 +0,0 @@ |
|||||
<template> |
|
||||
<view>项目管理</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default {}; |
|
||||
</script> |
|
||||
@ -1,7 +0,0 @@ |
|||||
<template> |
|
||||
<view>角色管理</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default {}; |
|
||||
</script> |
|
||||
@ -1,7 +0,0 @@ |
|||||
<template> |
|
||||
<view>任务管理</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default {}; |
|
||||
</script> |
|
||||
@ -1,60 +0,0 @@ |
|||||
<template> |
|
||||
<!-- 子项目插件 --> |
|
||||
<view> |
|
||||
<view v-for="item in sonProject" :key="item.detailId"> |
|
||||
<span class="text-xs text-blue-500" @click="openProject(item)">{{ item.name }}</span> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapGetters } from 'vuex'; |
|
||||
|
|
||||
export default { |
|
||||
name: 'p-subproject', |
|
||||
props: { |
|
||||
task: { |
|
||||
type: Object, |
|
||||
default: () => {}, |
|
||||
}, |
|
||||
}, |
|
||||
data() { |
|
||||
return { sonProject: [] }; |
|
||||
}, |
|
||||
|
|
||||
computed: mapGetters('project', ['projectId']), |
|
||||
|
|
||||
mounted() { |
|
||||
this.getSonProject(); |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
async getSonProject() { |
|
||||
try { |
|
||||
const data = await this.$u.api.findSonProject({ projectId: this.task.detailId }); |
|
||||
this.sonProject = data; |
|
||||
} catch (error) { |
|
||||
console.error('p-subproject.vue getSonProject error: ', error); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
/** |
|
||||
* 打开项目 |
|
||||
* @param {object} project 所点击的项目的信息 |
|
||||
*/ |
|
||||
openProject(project) { |
|
||||
const { name, id, url } = project; |
|
||||
url && (uni.$t.domain = url); |
|
||||
this.$u.route('/pagesA/project/project', { |
|
||||
u: this.userId, |
|
||||
p: id, |
|
||||
pname: name, |
|
||||
url: encodeURIComponent(url), |
|
||||
}); |
|
||||
}, |
|
||||
}, |
|
||||
watch: {}, |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<style></style> |
|
||||
@ -1,39 +0,0 @@ |
|||||
<template> |
|
||||
<view> |
|
||||
<view v-for="item in sonTask" :key="item.detailId"> |
|
||||
<span class="text-xs text-gray-500">{{ item.name }}</span> |
|
||||
</view> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
name: 'p-subtasks', |
|
||||
props: { |
|
||||
task: { |
|
||||
type: Object, |
|
||||
default: () => {}, |
|
||||
}, |
|
||||
}, |
|
||||
data() { |
|
||||
return { sonTask: [] }; |
|
||||
}, |
|
||||
|
|
||||
created() { |
|
||||
this.getSonTask(); |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
async getSonTask() { |
|
||||
try { |
|
||||
const data = await this.$u.api.findSonTask({ detailId: this.task.detailId }); |
|
||||
this.sonTask = data; |
|
||||
} catch (error) { |
|
||||
console.error('p-subtasks.vue getSonTask error: ', error); |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<style></style> |
|
||||
@ -1,20 +0,0 @@ |
|||||
<template> |
|
||||
<!-- 任务倒计时插件 --> |
|
||||
<view>任务倒计时插件</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
name: 'p-task-countdown', |
|
||||
props: { item: { type: Object, default: null } }, |
|
||||
data() { |
|
||||
return {}; |
|
||||
}, |
|
||||
|
|
||||
computed: {}, |
|
||||
methods: {}, |
|
||||
watch: {}, |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<style></style> |
|
||||
@ -1,16 +0,0 @@ |
|||||
<template> |
|
||||
<!-- 任务描述 --> |
|
||||
<view>{{ task.description }}</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
name: 'p-task-description', |
|
||||
props: { |
|
||||
task: { |
|
||||
type: Object, |
|
||||
default: () => {}, |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
@ -1,34 +0,0 @@ |
|||||
<template> |
|
||||
<view v-if="realDuration && planDuration"> |
|
||||
<!-- 任务时长延迟插件 --> |
|
||||
<!-- 超时 --> |
|
||||
<span class="font-bold text-green-500" v-if="realDuration - 0 > planDuration - 0"> |
|
||||
+{{ $t.time.formatDuration(realDuration - planDuration) }} |
|
||||
</span> |
|
||||
<!-- 延时 --> |
|
||||
<span class="font-bold text-red-500" v-if="realDuration - 0 < planDuration - 0"> |
|
||||
-{{ $t.time.formatDuration(planDuration - realDuration) }} |
|
||||
</span> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
name: 'p-task-duration-delay', |
|
||||
props: { |
|
||||
task: { |
|
||||
type: Object, |
|
||||
default: () => {}, |
|
||||
}, |
|
||||
}, |
|
||||
|
|
||||
computed: { |
|
||||
realDuration() { |
|
||||
return this.task.realDuration; |
|
||||
}, |
|
||||
planDuration() { |
|
||||
return this.task.planDuration; |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
@ -1,23 +0,0 @@ |
|||||
<template> |
|
||||
<!-- <view>任务开始时间延迟插件</view> --> |
|
||||
<view v-if="realStart && planStart"> |
|
||||
<!-- 任务开始时间延迟插件 --> |
|
||||
<!-- 超时 --> |
|
||||
<span>{{ $t.time.formatDuration(+realStart - +planStart) }}</span> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
name: 'p-task-start-time-delay', |
|
||||
props: { task: { type: Object, default: () => {} } }, |
|
||||
computed: { |
|
||||
realStart() { |
|
||||
return this.task.realStart; |
|
||||
}, |
|
||||
planStart() { |
|
||||
return this.task.planStart; |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
@ -1,16 +0,0 @@ |
|||||
<template> |
|
||||
<!-- 任务名插件 --> |
|
||||
<view>{{ task.name }}</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
name: 'p-task-title', |
|
||||
props: { |
|
||||
task: { |
|
||||
type: Object, |
|
||||
default: () => {}, |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
@ -1,94 +0,0 @@ |
|||||
<template> |
|
||||
<!-- 上传交付物 --> |
|
||||
<view class="py-2"> |
|
||||
<u-input :auto-height="autoHeight" :border="border" :height="height" :type="type" v-model="content" width="100" /> |
|
||||
|
|
||||
<!-- 选择检查人 --> |
|
||||
<ChooseChecker ref="checker" :checkerList="checkerList" @setCheckerList="setCheckerList"></ChooseChecker> |
|
||||
|
|
||||
<view class="flex justify-between"> |
|
||||
<u-button @click="submit" class="m-0" size="mini" type="primary">提交</u-button> |
|
||||
<u-icon @click="changeShowHistory" name="arrow-up" v-if="showHistory"></u-icon> |
|
||||
<u-icon @click="changeShowHistory" name="arrow-down" v-else></u-icon> |
|
||||
</view> |
|
||||
|
|
||||
<p-delivery-history :task="task" v-if="showHistory" /> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import ChooseChecker from '@/components/ChooseChecker/ChooseChecker.vue'; |
|
||||
import { mapState, mapGetters } from 'vuex'; |
|
||||
|
|
||||
export default { |
|
||||
name: 'p-upload-deliverable', |
|
||||
components: { ChooseChecker }, |
|
||||
props: { task: { type: Object, default: null } }, |
|
||||
data() { |
|
||||
return { |
|
||||
content: '', |
|
||||
type: 'textarea', |
|
||||
border: true, |
|
||||
height: 30, |
|
||||
autoHeight: true, |
|
||||
checkerList: [], |
|
||||
showHistory: false, // 展开历史记录 |
|
||||
}; |
|
||||
}, |
|
||||
|
|
||||
computed: { |
|
||||
...mapState('role', ['members']), |
|
||||
...mapGetters('project', ['projectId']), |
|
||||
|
|
||||
checkers() { |
|
||||
const arr = []; |
|
||||
if (this.members.length) { |
|
||||
this.members.forEach(member => { |
|
||||
const item = { value: member.memberId, label: member.name }; |
|
||||
arr.push(item); |
|
||||
}); |
|
||||
} |
|
||||
return arr; |
|
||||
}, |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
// 设置检查人 |
|
||||
setCheckerList(checked, item) { |
|
||||
if (checked) { |
|
||||
this.checkerList.push(item.memberId); |
|
||||
} else { |
|
||||
const index = this.checkerList.findIndex(checker => checker === item.memberId); |
|
||||
this.checkerList.splice(index, 1); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
// 展开合上历史记录 |
|
||||
changeShowHistory() { |
|
||||
this.showHistory = !this.showHistory; |
|
||||
}, |
|
||||
|
|
||||
// 提交交付物 |
|
||||
async submit() { |
|
||||
try { |
|
||||
const { content, checkerList, projectId, task } = this; |
|
||||
if (!this.checkerList.length) { |
|
||||
this.$t.ui.showToast('请选择检查人'); |
|
||||
return; |
|
||||
} |
|
||||
const params = { content, checkerList, projectId, taskSubId: task.id }; |
|
||||
await this.$u.api.saveDeliver(params); |
|
||||
this.$t.ui.showToast('交付物提交成功'); |
|
||||
this.content = ''; |
|
||||
this.checkerList = []; |
|
||||
this.$refs.checker.clearChecked(); |
|
||||
} catch (error) { |
|
||||
console.error('p-upload-deliverable.vue submit error: ', error); |
|
||||
this.$t.ui.showToast('交付物提交失败,请稍后重试'); |
|
||||
} |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<style scoped lang="scss"></style> |
|
||||
@ -1,85 +0,0 @@ |
|||||
<template> |
|
||||
<view> |
|
||||
<view @click="handleUpload" v-if="task.name === '导入WBS新建项目'">{{ task.name }}</view> |
|
||||
<view @click="handleUpdate" v-if="task.name === '导入WBS更新项目'">{{ task.name }}</view> |
|
||||
<!-- 全局提示框 --> |
|
||||
<u-top-tips ref="uTips"></u-top-tips> |
|
||||
</view> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
import { mapGetters, mapMutations } from 'vuex'; |
|
||||
|
|
||||
export default { |
|
||||
name: 'p-wbs-import', |
|
||||
props: { |
|
||||
task: { |
|
||||
type: Object, |
|
||||
default: () => {}, |
|
||||
}, |
|
||||
}, |
|
||||
data() { |
|
||||
return {}; |
|
||||
}, |
|
||||
|
|
||||
computed: { |
|
||||
...mapGetters('user', ['userId']), |
|
||||
...mapGetters('project', ['projectId']), |
|
||||
}, |
|
||||
|
|
||||
methods: { |
|
||||
...mapMutations('project', ['setShowAlert']), |
|
||||
|
|
||||
// 导入wbs |
|
||||
async handleUpload() { |
|
||||
try { |
|
||||
const data = await this.$u.api.import(); |
|
||||
// 导入WBS成功后 |
|
||||
// 直接打开导入的项目 |
|
||||
this.onUploadSuccess(); |
|
||||
setTimeout(() => { |
|
||||
this.$u.route('/pagesA/project/project', { |
|
||||
u: this.userId, |
|
||||
p: data.id, |
|
||||
pname: data.pname, |
|
||||
url: data.url, |
|
||||
}); |
|
||||
}, 2000); |
|
||||
} catch (error) { |
|
||||
this.onUploadError(error); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
// 更新项目 |
|
||||
// TODO: 更新接口没写完 |
|
||||
async handleUpdate() { |
|
||||
try { |
|
||||
await this.$u.api.import({ projectId: this.projectId }); |
|
||||
// 导入WBS成功后 |
|
||||
// 直接打开导入的项目 |
|
||||
this.onUploadSuccess(); |
|
||||
} catch (error) { |
|
||||
this.onUploadError(error); |
|
||||
} |
|
||||
}, |
|
||||
|
|
||||
// 导入成功 |
|
||||
onUploadSuccess() { |
|
||||
this.$refs.uTips.show({ |
|
||||
title: '导入成功,即将打开新项目', |
|
||||
type: 'success', |
|
||||
duration: '3000', |
|
||||
}); |
|
||||
}, |
|
||||
|
|
||||
// 导入失败 |
|
||||
onUploadError(error) { |
|
||||
this.$refs.uTips.show({ |
|
||||
title: error || '导入失败', |
|
||||
type: 'error', |
|
||||
duration: '6000', |
|
||||
}); |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
</script> |
|
||||