details.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. <template>
  2. <u-navbar :titleStyle="{ color: '#000' }" :autoBack="false" title="日报详情" :placeholder="true" :safeAreaInsetTop="true" bgColor="#fff">
  3. <template #left>
  4. <view class="u-navbar__content__left__item">
  5. <u-icon name="arrow-left" size="20" color="#000" @click="returnTo('business/common/projectMange/record/index')"></u-icon>
  6. </view>
  7. </template>
  8. </u-navbar>
  9. <oa-scroll
  10. customClass="record-container scroll-height"
  11. :pageSize="pageSize"
  12. :total="total"
  13. :isSticky="true"
  14. :customStyle="{
  15. //#ifdef APP-PLUS || MP-WEIXIN
  16. height: `calc(100vh - 44px)`,
  17. //#endif
  18. //#ifdef H5
  19. height: `calc(100vh - 44px)`,
  20. //#endif
  21. }"
  22. :refresherLoad="true"
  23. :refresherEnabled="true"
  24. :refresherDefaultStyle="'none'"
  25. :refresherThreshold="44"
  26. :lowerThreshold="44"
  27. :refresherBackground="'#f5f6f7'"
  28. @load="load"
  29. @refresh="refresh"
  30. :data-theme="'theme-' + proxy.$settingStore.themeColor.name"
  31. >
  32. <template #default>
  33. <view class="content-area radius bg-white" v-for="(item, index) in dataList" :key="index" style="margin-top: 6px">
  34. <view class="content-area-top menu-item" style="float: right; padding: 10px 0px">
  35. <view class="content-area-top-time"> </view>
  36. <u-icon class="content-area-top-icon" name="more-dot-fill" size="20" color="#000" @click="moreClick(item)"></u-icon>
  37. </view>
  38. <view class="content-area-header flex mb10">
  39. <img :src="item?.avatar" class="content-area-header-avatarImg mr10" v-if="item?.avatar" />
  40. <u-avatar
  41. v-if="!item?.avatar"
  42. class="content-area-header-avatar mr10"
  43. :text="item.createBy.length > 2 ? item.createBy.slice(1, 3) : item.createBy"
  44. shape="square"
  45. size="40"
  46. fontSize="12"
  47. color="#ffffff"
  48. :bgColor="proxy.$settingStore.themeColor.color"
  49. ></u-avatar>
  50. <view>
  51. <view class="content-area-header-title font16 mb5">{{ item.createBy ? item.createBy : " " }} {{ item.submitDate.slice(0, 10) != item.reportDate ? "( " + item.reportDate + " )" : "" }}</view>
  52. <view class="content-area-header-time font14">{{ item.submitDate ? item.submitDate.replace("T", " ") : " " }}</view>
  53. </view>
  54. </view>
  55. <view class="content-area-center mb10" v-for="child in item.workContents" :key="child">
  56. <view class="content-area-center-top flex">
  57. <view class="content-area-center-top-title mr10" style="color: #559aff" @click="toProjectMange(child.projectId)">{{ child.projectName ? child.projectName : " " }}</view>
  58. <view class="content-area-center-top-time" :style="{ color: proxy.$settingStore.themeColor.color }">{{ child.workTime }}h</view>
  59. </view>
  60. <u-text :text="child.workContent" color="#000000" size="14"></u-text>
  61. </view>
  62. <view class="content-area-center mb10">
  63. <view class="content-area-center-top"> 明日计划 </view>
  64. <u-text :text="item.tomorrowPlan ? item.tomorrowPlan : '无'" color="#000000" size="14"></u-text>
  65. </view>
  66. <view class="content-area-center mb10">
  67. <view class="content-area-center-top"> 工作协调 </view>
  68. <u-text :text="item.coordinateWork ? item.coordinateWork : '无'" color="#000000" size="14"></u-text>
  69. </view>
  70. <view class="content-area-center mb10">
  71. <view class="content-area-center-top">图片</view>
  72. <view class="imageBox" v-if="JSON.parse(item.reportImage) && JSON.parse(item.reportImage).length > 0">
  73. <image class="image m5" style="width: 50px" mode="widthFix" v-for="(a, index2) in JSON.parse(item.reportImage)" :key="index2" :src="a.url" @click="previewImage(index,index)" />
  74. </view>
  75. <view class="imageBox" v-else>无</view>
  76. </view>
  77. <view class="content-area-center mb10">
  78. <view class="content-area-center-top">附件 </view>
  79. <view v-if="JSON.parse(item.reportFile) && JSON.parse(item.reportFile).length > 0">
  80. <uni-link v-for="(file, index2) in JSON.parse(item.reportFile)" :key="index2" :href="file.url" text="file.url" style="color: rgba(0, 0, 0, 0.7)">{{ file.name }}</uni-link>
  81. </view>
  82. <view v-else>无</view>
  83. </view>
  84. <view class="content-area-center mb10" style="display: flex; flex-wrap: wrap" v-if="item.pmReportReaders.read > 0 || item.pmReportReaders.unRead > 0">
  85. <u-tabs
  86. :list="item.tabsList"
  87. :current="item.tab"
  88. @click="tabsClick(index, $event.value)"
  89. lineColor="#333"
  90. :activeStyle="{ color: '#333', fontSize: '14px' }"
  91. :inactiveStyle="{ color: '#909399', fontSize: '14px' }"
  92. :scrollable="false"
  93. style="width: 100%"
  94. ></u-tabs>
  95. <view class="content-area-header mt20 mb10 text-center" style="display: inline-block" v-for="(item2, index2) in item.tabsList[item.tab].treeSelectNodes" :key="index2">
  96. <img v-if="item2?.avatar" class="content-area-header-avatarImg mlr5" :src="item2.avatar" style="display: block; width: 40px; height: 40px" />
  97. <u-avatar
  98. v-if="!item2.avatar"
  99. class="content-area-header-avatar mlr5"
  100. :text="item2.nickName.length > 2 ? item2.nickName.slice(1, 3) : item2.nickName"
  101. shape="square"
  102. size="40"
  103. fontSize="12"
  104. color="#ffffff"
  105. :bgColor="proxy.$settingStore.themeColor.color"
  106. ></u-avatar>
  107. <u-text :text="item2.nickName" color="#000000" size="14" align="center"></u-text>
  108. </view>
  109. </view>
  110. </view>
  111. </template>
  112. </oa-scroll>
  113. <u-popup :show="popup.show" mode="bottom" bgColor="#fff" :round="10" @close="popup.show = false">
  114. <view
  115. :style="{
  116. borderTopLeftRadius: '10px',
  117. borderTopRightRadius: '10px',
  118. overflow: 'hidden',
  119. }"
  120. >
  121. <u-button
  122. class="custom-style"
  123. type="info"
  124. size="normal"
  125. :text="`查看${eventList.createBy}的所有日报`"
  126. :customStyle="{
  127. height: '50px',
  128. color: '#3c9cff',
  129. borderWidth: 0,
  130. borderRadius: 0,
  131. borderBottomWidth: '1px',
  132. }"
  133. @click="handleSubmit(eventList)"
  134. ></u-button>
  135. <u-button
  136. class="custom-style"
  137. type="info"
  138. size="normal"
  139. text="取消"
  140. :customStyle="{
  141. height: '50px',
  142. color: '#3c9cff',
  143. border: 'none',
  144. borderRadius: 0,
  145. }"
  146. @click="popup.show = false"
  147. ></u-button>
  148. </view>
  149. </u-popup>
  150. </template>
  151. <script setup>
  152. /*----------------------------------依赖引入-----------------------------------*/
  153. import { onLoad, onShow, onReady, onHide, onLaunch, onBackPress, onUnload, onNavigationBarButtonTap, onPageScroll } from "@dcloudio/uni-app";
  154. import { ref, reactive, computed, getCurrentInstance, toRefs, inject } from "vue";
  155. /*----------------------------------接口引入-----------------------------------*/
  156. import { projectApi } from "@/api/business/project.js";
  157. import { dUserList } from "@/api/system/user.js";
  158. import { deptUserTreeSelect } from "@/api/system/user.js";
  159. /*----------------------------------组件引入-----------------------------------*/
  160. /*----------------------------------store引入-----------------------------------*/
  161. /*----------------------------------公共方法引入-----------------------------------*/
  162. /*----------------------------------公共变量-----------------------------------*/
  163. const { proxy } = getCurrentInstance();
  164. /*----------------------------------变量声明-----------------------------------*/
  165. const tree = ref({
  166. value: "tree_root",
  167. label: "Root",
  168. children: [],
  169. });
  170. const reportDetailData = ref([]);
  171. const pmReportReaders = ref([]); //已读未读集合
  172. const state = reactive({
  173. loading: true,
  174. dataList: [], //日报列表
  175. options: {
  176. //日报详情参数
  177. reportId: "",
  178. },
  179. userData: [], //用户列表
  180. pageSize:1,
  181. total:10,
  182. submitDate:undefined,
  183. popup: {
  184. show: false, //弹窗显示
  185. content: "", //提示信息
  186. },
  187. eventList: {}, //数据存储
  188. });
  189. const { dataList, userData, tabsList, tabsCurrent, pageSize, total, popup, eventList } = toRefs(state);
  190. /**
  191. * 返回上级页面
  192. * @param defaultPage 默认页面
  193. */
  194. function returnTo(defaultPage) {
  195. if(getCurrentPages().length > 1){
  196. uni.navigateBack()
  197. }else{
  198. uni.redirectTo({
  199. url: `/pages/${defaultPage}`
  200. })
  201. }
  202. }
  203. /**
  204. * @tabs点击事件
  205. */
  206. function tabsClick(index,e) {
  207. dataList.value[index].tab = e
  208. }
  209. function previewImage(index1,index2) {
  210. uni.previewImage({
  211. current: index2, // 当前显示图片索引
  212. urls: dataList.value[index1].images[index2], // 需要预览的图片http链接列表
  213. });
  214. }
  215. /**
  216. * @初始化
  217. */
  218. function init() {
  219. dataList.value = [];
  220. state.loading = true;
  221. /** 查询树结构用户列表 回显抄送人*/
  222. deptUserTreeSelect({ pageNum: "1", pageSize: "1000" }).then((res) => {
  223. tree.value = res.data;
  224. projectApi()
  225. .ReportRecord({
  226. reportId: state.options.reportId,
  227. pageNum: 1,
  228. pageSize: 1,
  229. })
  230. .then((requset) => {
  231. dataRebuild(requset.data.records);
  232. state.loading = false;
  233. }).catch((err) => {
  234. state.loading = false;
  235. });
  236. });
  237. }
  238. /**
  239. *
  240. * @param item 数据重组
  241. */
  242. function dataRebuild(item,type){
  243. for(let i=0;i<item.length;i++){
  244. item[i].tabsList = [
  245. { name: "已读(" + item[i].pmReportReaders.read + ")", value: 0,
  246. treeSelectNodes:proxy.$common.findTreeNodes(tree.value, item[i].pmReportReaders.readAlready),num:item[i].pmReportReaders.read},
  247. { name: "未读(" + item[i].pmReportReaders.unRead + ")", value: 1,
  248. treeSelectNodes:proxy.$common.findTreeNodes(tree.value,item[i].pmReportReaders.readNotAlready),num:item[i].pmReportReaders.read},
  249. ];
  250. item[i].tab = 0
  251. var imgs = JSON.parse(item[i].reportImage);
  252. var files = JSON.parse(item[i].reportFile);
  253. imgs.forEach(function (val) {
  254. item[i].images.push(val.url);
  255. });
  256. files.forEach(function (val) {
  257. item[i].files.push(val.url);
  258. });
  259. //数据插入
  260. if(type == "refresh"){
  261. dataList.value.unshift(item[i])
  262. }else{
  263. dataList.value.push(item[i])
  264. }
  265. // 未读状态变更
  266. if(item[i].readFlag == "0"){
  267. projectApi()
  268. .ReportRecordReadFlag({ reportId: item[i].id })
  269. .then((res) => {
  270. if (res.status != "SUCCESS") {
  271. proxy.$modal.msgError("读取异常");
  272. }
  273. });
  274. }
  275. }
  276. }
  277. /**
  278. * 跳转项目概览
  279. * @param id 项目id
  280. */
  281. function toProjectMange(id) {
  282. proxy.$tab.navigateTo(`/pages/business/common/projectMange/overview/index?id=${id}`);
  283. }
  284. /**
  285. * @scrollView加载数据
  286. */
  287. function load() {
  288. projectApi().ReportRecord(
  289. {
  290. upOrDown:0,
  291. slideSum:1,
  292. submitDate:dataList.value[dataList.value.length-1].submitDate,
  293. projectAscription:2
  294. }
  295. ).then((requset) => {
  296. if(requset?.data?.records.length>0){
  297. dataRebuild(requset.data.records,"load");
  298. }
  299. })
  300. }
  301. /**
  302. * @scrollView刷新数据
  303. */
  304. function refresh() {
  305. projectApi().ReportRecord(
  306. {
  307. upOrDown:1,
  308. slideSum:1,
  309. submitDate:dataList.value[0].submitDate,
  310. projectAscription:2
  311. }
  312. ).then((requset) => {
  313. if(requset?.data?.records.length>0){
  314. dataRebuild(requset.data.records,"refresh");
  315. }
  316. })
  317. }
  318. /** 更多按钮点击事件 */
  319. function moreClick(event) {
  320. state.popup.show = true;
  321. state.eventList = event;
  322. }
  323. /** 编辑、删除日报*/
  324. function handleSubmit(e) {
  325. state.popup.show = false;
  326. proxy.$tab.navigateTo(`/pages/business/common/projectMange/record/detailsAll?reportId=${e.id}`);
  327. }
  328. onReady(() => {});
  329. onShow(() => {
  330. //调用系统主题颜色
  331. proxy.$settingStore.systemThemeColor([1]);
  332. });
  333. onLoad((options) => {
  334. state.options.reportId = options?.reportId;
  335. init();
  336. });
  337. onUnload(() => {
  338. projectApi()
  339. .ReportRecordReadFlag({ reportId: state.options.reportId })
  340. .then((requset) => {
  341. uni.$emit("projectMange_record", true); //监听器
  342. })
  343. .catch((err) => {
  344. uni.$emit("projectMange_record", true); //监听器
  345. });
  346. });
  347. </script>
  348. <style lang="scss" scoped>
  349. .content-area {
  350. margin: 0;
  351. padding: 15px 20px;
  352. overflow: hidden;
  353. &-header {
  354. &-avatar {
  355. margin: auto 0;
  356. }
  357. &-avatarImg {
  358. width: 35px;
  359. height: 35px;
  360. border-radius: 4px;
  361. }
  362. &-title {
  363. margin: 0 0 15px 0;
  364. font-weight: 600;
  365. color: #000000;
  366. }
  367. }
  368. &-center {
  369. line-height: 25px;
  370. &-top {
  371. color: #000000;
  372. font-weight: 600;
  373. }
  374. }
  375. }
  376. </style>