detail.vue 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. <template>
  2. <div class="project-task-detail-window" :class="{'task-detail-show': visible}">
  3. <div class="task-detail-main">
  4. <div class="detail-left">
  5. <div class="detail-title-box detail-icon">
  6. <input v-model="detail.title" :disabled="!!loadData.title" type="text" maxlength="60" @keydown.enter="(e)=>{e.target.blur()}" @blur="handleTask('title')">
  7. <div class="time">
  8. <span class="z-nick">{{detail.createuser}}</span>
  9. {{$L('创建于:')}}
  10. <span>{{$A.formatDate("Y-m-d H:i:s", detail.indate)}}</span>
  11. </div>
  12. </div>
  13. <div class="detail-desc-box detail-icon">
  14. <div class="detail-h2"><strong class="active">{{$L('描述')}}</strong></div>
  15. <textarea v-model="detail.desc" :placeholder="$L('添加详细描述...')" @keydown="descKeydown" @blur="handleTask('desc')"></textarea>
  16. </div>
  17. <ul class="detail-text-box">
  18. <li v-if="detail.startdate > 0 && detail.enddate > 0" class="text-time detail-icon">
  19. <span>{{$L('计划时间:')}}</span>
  20. <em>{{$A.formatDate("Y-m-d H:i", detail.startdate)}} {{$L('至')}} {{$A.formatDate("Y-m-d H:i", detail.enddate)}}</em>
  21. <em v-if="detail.overdue" class="overdue">[{{$L('已超期')}}]</em>
  22. </li>
  23. <li class="text-username detail-icon">
  24. <span>{{$L('负责人:')}}</span>
  25. <em>{{detail.username}}</em>
  26. </li>
  27. <li v-if="followerLength(detail.follower) > 0" class="text-follower detail-icon">
  28. <span>{{$L('关注者:')}}</span>
  29. <em>
  30. <Tag v-for="(fname, findex) in detail.follower" :key="findex" closable @on-close="handleTask('unattention', {username:fname,uisynch:true})">{{fname}}</Tag>
  31. </em>
  32. </li>
  33. <li class="text-level detail-icon">
  34. <span>{{$L('优先级:')}}</span>
  35. <em :class="`p${detail.level}`">{{levelFormt(detail.level)}}</em>
  36. </li>
  37. <li class="text-status detail-icon">
  38. <span>{{$L('任务状态:')}}</span>
  39. <em v-if="detail.complete" class="complete">{{$L('已完成')}}</em>
  40. <em v-else class="unfinished">{{$L('未完成')}}</em>
  41. </li>
  42. </ul>
  43. <div :style="`${detail.filenum>0?'':'display:none'}`">
  44. <div class="detail-h2 detail-file-box detail-icon"><strong class="active">{{$L('附件')}}</strong></div>
  45. <project-task-files ref="upload" :taskid="taskid" :simple="true" @change="handleTask('filechange', $event)"></project-task-files>
  46. </div>
  47. <div class="detail-h2 detail-comment-box detail-icon"><strong class="link" :class="{active:logType=='评论'}" @click="logType='评论'">{{$L('评论')}}</strong><em></em><strong class="link" :class="{active:logType=='日志'}" @click="logType='日志'">{{$L('操作记录')}}</strong></div>
  48. <div class="detail-log-box">
  49. <project-task-logs ref="log" :logtype="logType" :projectid="detail.projectid" :taskid="taskid" :pagesize="5"></project-task-logs>
  50. </div>
  51. <div class="detail-footer-box">
  52. <Input class="comment-input" v-model="commentText" type="textarea" :rows="1" :autosize="{ minRows: 1, maxRows: 3 }" :maxlength="255" @on-keydown="commentKeydown" :placeholder="$L('输入评论,Enter发表评论,Shift+Enter换行')" />
  53. <Button :loading="!!loadData.comment" :disabled="!commentText" type="primary" @click="handleTask('comment')">评 论</Button>
  54. </div>
  55. </div>
  56. <div class="detail-right">
  57. <div class="cancel"><em @click="visible=false"></em></div>
  58. <Dropdown trigger="click" class="block" @on-click="handleTask">
  59. <Button :loading="!!loadData.unfinished || !!loadData.complete" icon="md-checkmark-circle-outline" class="btn">{{$L('标记')}}{{$L(detail.complete?'未完成':'已完成')}}</Button>
  60. <DropdownMenu slot="list">
  61. <DropdownItem name="unfinished">{{$L('标记未完成')}}<Icon v-if="!detail.complete" type="md-checkmark" class="checkmark"/></DropdownItem>
  62. <DropdownItem name="complete">{{$L('标记已完成')}}<Icon v-if="detail.complete" type="md-checkmark" class="checkmark"/></DropdownItem>
  63. <DropdownItem name="archived2">{{$L('完成并归档')}}<Icon v-if="detail.complete && detail.archived" type="md-checkmark" class="checkmark"/></DropdownItem>
  64. </DropdownMenu>
  65. </Dropdown>
  66. <Dropdown trigger="click" class="block" @on-click="handleTask">
  67. <Button :loading="!!loadData.level" icon="md-funnel" class="btn">{{$L('优先级')}}</Button>
  68. <DropdownMenu slot="list">
  69. <DropdownItem v-for="level in [1,2,3,4]" :key="level" :name="`level-${level}`" :class="`p${level}`">{{levelFormt(level)}}<Icon v-if="detail.level==level" type="md-checkmark" class="checkmark"/></DropdownItem>
  70. </DropdownMenu>
  71. </Dropdown>
  72. <Poptip placement="bottom" class="block">
  73. <Button :loading="!!loadData.username" icon="md-person" class="btn">{{$L('负责人')}}</Button>
  74. <div slot="content">
  75. <div style="width:280px">
  76. {{$L('选择负责人')}}
  77. <UseridInput :projectid="detail.projectid" :nousername="detail.username" :transfer="false" @change="handleTask('usernameb', $event)" :placeholder="$L('输入关键词搜索')" style="margin:5px 0 3px"></UseridInput>
  78. </div>
  79. </div>
  80. </Poptip>
  81. <Poptip ref="timeRef" placement="bottom" class="block" @on-popper-show="handleTask('inittime')">
  82. <Button :loading="!!loadData.plannedtime || !!loadData.unplannedtime" icon="md-calendar" class="btn">{{$L('计划时间')}}</Button>
  83. <div slot="content">
  84. <div style="width:280px">
  85. {{$L('选择日期范围')}}
  86. <Date-picker
  87. v-model="timeValue"
  88. :options="timeOptions"
  89. :placeholder="$L('日期范围')"
  90. format="yyyy-MM-dd HH:mm"
  91. type="datetimerange"
  92. placement="bottom"
  93. @on-ok="handleTask('plannedtimeb')"
  94. @on-clear="handleTask('unplannedtimeb')"
  95. style="display:block;margin:5px 0 3px"></Date-picker>
  96. </div>
  97. </div>
  98. </Poptip>
  99. <Button icon="md-attach" class="btn" @click="handleTask('fileupload')">{{$L('添加附件')}}</Button>
  100. <Poptip ref="attentionRef" v-if="detail.username == myUsername" placement="bottom" class="block" @on-popper-show="() => {$set(detail, 'attentionLists', followerToStr(detail.follower))}">
  101. <Button :loading="!!loadData.attention" icon="md-at" class="btn">{{$L('关注人')}}</Button>
  102. <div slot="content">
  103. <div style="width:280px">
  104. {{$L('选择关注人')}}
  105. <UseridInput :multiple="true" :transfer="false" v-model="detail.attentionLists" :placeholder="$L('输入关键词搜索')" style="margin:5px 0 3px"></UseridInput>
  106. <Button :loading="!!loadData.attention" :disabled="!detail.attentionLists" class="btn" type="primary" style="text-align:center;width:72px;height:28px;font-size:13px" @click="handleTask('attention')">确 定</Button>
  107. </div>
  108. </div>
  109. </Poptip>
  110. <Button v-else-if="haveAttention(detail.follower)" :loading="!!loadData.unattention" icon="md-at" class="btn" @click="handleTask('unattention', {username:myUsername})">{{$L('取消关注')}}</Button>
  111. <Button v-else :loading="!!loadData.attention" icon="md-at" class="btn" @click="handleTask('attentiona')">{{$L('关注任务')}}</Button>
  112. <Button v-if="!detail.archived" :loading="!!loadData.archived" icon="md-filing" class="btn" @click="handleTask('archived')">{{$L('归档')}}</Button>
  113. <Button v-else :loading="!!loadData.unarchived" icon="md-filing" class="btn" @click="handleTask('unarchived')">{{$L('取消归档')}}</Button>
  114. <Button :loading="!!loadData.delete" icon="md-trash" class="btn" type="error" ghost @click="handleTask('deleteb')">{{$L('删除')}}</Button>
  115. </div>
  116. </div>
  117. </div>
  118. </template>
  119. <script>
  120. import ProjectTaskLogs from "../logs";
  121. import ProjectTaskFiles from "../files";
  122. export default {
  123. components: {ProjectTaskFiles, ProjectTaskLogs},
  124. data() {
  125. return {
  126. taskid: 0,
  127. detail: {},
  128. visible: false,
  129. bakData: {},
  130. loadData: {},
  131. commentText: '',
  132. logType: '评论',
  133. timeValue: [],
  134. timeOptions: {},
  135. myUsername: '',
  136. }
  137. },
  138. beforeCreate() {
  139. let doms = document.querySelectorAll('.project-task-detail-window');
  140. for (let i = 0; i < doms.length; ++i) {
  141. if (doms[i].parentNode != null) doms[i].parentNode.removeChild(doms[i]);
  142. }
  143. },
  144. created() {
  145. this.timeOptions = {
  146. shortcuts: [{
  147. text: this.$L('今天'),
  148. value() {
  149. return [new Date(), new Date()];
  150. }
  151. }, {
  152. text: this.$L('明天'),
  153. value() {
  154. let e = new Date();
  155. e.setDate(e.getDate() + 1);
  156. return [new Date(), e];
  157. }
  158. }, {
  159. text: this.$L('本周'),
  160. value() {
  161. return [$A.getData('今天', true), $A.getData('本周结束', true)];
  162. }
  163. }, {
  164. text: this.$L('本月'),
  165. value() {
  166. return [$A.getData('今天', true), $A.getData('本月结束', true)];
  167. }
  168. }, {
  169. text: this.$L('3天'),
  170. value() {
  171. let e = new Date();
  172. e.setDate(e.getDate() + 3);
  173. return [new Date(), e];
  174. }
  175. }, {
  176. text: this.$L('5天'),
  177. value() {
  178. let e = new Date();
  179. e.setDate(e.getDate() + 5);
  180. return [new Date(), e];
  181. }
  182. }, {
  183. text: this.$L('7天'),
  184. value() {
  185. let e = new Date();
  186. e.setDate(e.getDate() + 7);
  187. return [new Date(), e];
  188. }
  189. }]
  190. };
  191. },
  192. mounted() {
  193. this.$nextTick(() => {
  194. let dom = this.$el;
  195. if (parseInt(this.taskid) === 0) {
  196. if (dom.parentNode != null) dom.parentNode.removeChild(dom);
  197. return;
  198. }
  199. //
  200. dom.addEventListener('transitionend', () => {
  201. if (dom !== null && dom.parentNode !== null && !this.visible) {
  202. dom.parentNode.removeChild(dom);
  203. }
  204. }, false);
  205. //
  206. setTimeout(() => {
  207. this.visible = true;
  208. }, 0)
  209. });
  210. this.bakData = $A.cloneData(this.detail);
  211. this.myUsername = $A.getUserName();
  212. this.getTaskDetail();
  213. //
  214. $A.setOnUserInfoListener("components/project/task/detail", () => {
  215. this.myUsername = $A.getUserName();
  216. });
  217. $A.setOnTaskInfoListener('components/project/task/detail',(act, detail) => {
  218. if (detail.id != this.taskid) {
  219. return;
  220. }
  221. if (detail.__modifyUsername == this.myUsername) {
  222. return;
  223. }
  224. this.getTaskDetail();
  225. }, true);
  226. },
  227. watch: {
  228. taskid() {
  229. this.bakData = $A.cloneData(this.detail);
  230. this.getTaskDetail();
  231. }
  232. },
  233. methods: {
  234. levelFormt(p) {
  235. switch (parseInt(p)) {
  236. case 1:
  237. return this.$L("重要且紧急 (P1)");
  238. case 2:
  239. return this.$L("重要不紧急 (P2)");
  240. case 3:
  241. return this.$L("紧急不重要 (P3)");
  242. case 4:
  243. return this.$L("不重要不紧急 (P4)");
  244. }
  245. },
  246. descKeydown(e) {
  247. e = e || event;
  248. if (e.keyCode == 13) {
  249. if (e.shiftKey) {
  250. return;
  251. }
  252. e.preventDefault();
  253. e.target.blur();
  254. }
  255. },
  256. commentKeydown(e) {
  257. e = e || event;
  258. if (e.keyCode == 13) {
  259. if (e.shiftKey) {
  260. return;
  261. }
  262. e.preventDefault();
  263. this.handleTask('comment');
  264. }
  265. },
  266. followerLength(follower) {
  267. if (follower instanceof Array) {
  268. return follower.length;
  269. } else {
  270. return 0;
  271. }
  272. },
  273. followerToStr(follower) {
  274. if (follower instanceof Array) {
  275. return follower.join(",");
  276. } else {
  277. return '';
  278. }
  279. },
  280. haveAttention(follower) {
  281. if (follower instanceof Array) {
  282. return follower.filter((uname) => { return uname == this.myUsername }).length > 0
  283. } else {
  284. return 0;
  285. }
  286. },
  287. getTaskDetail() {
  288. $A.aAjax({
  289. url: 'project/task/lists',
  290. data: {
  291. taskid: this.taskid,
  292. archived: '全部'
  293. },
  294. error: () => {
  295. alert(this.$L('网络繁忙,请稍后再试!'));
  296. this.visible = false;
  297. },
  298. success: (res) => {
  299. if (res.ret === 1) {
  300. this.detail = res.data;
  301. this.bakData = $A.cloneData(this.detail);
  302. } else {
  303. this.$Modal.error({
  304. title: this.$L('温馨提示'),
  305. content: res.msg,
  306. onOk: () => {
  307. this.visible = false;
  308. }
  309. });
  310. }
  311. }
  312. });
  313. },
  314. handleTask(act, eve) {
  315. if (!!this.loadData[act]) {
  316. this.$Message.info(this.$L('请稍候...'));
  317. return;
  318. }
  319. //
  320. let ajaxData = {
  321. act: act,
  322. taskid: this.taskid,
  323. };
  324. let ajaxCallback = () => {};
  325. //
  326. switch (act) {
  327. case 'title':
  328. case 'desc':
  329. if (this.detail[act] == this.bakData[act]) {
  330. return;
  331. }
  332. if (!this.detail[act]) {
  333. this.$set(this.detail, act, this.bakData[act]);
  334. return;
  335. }
  336. ajaxData.content = this.detail[act];
  337. ajaxCallback = (res) => {
  338. if (res !== 1) {
  339. this.$set(this.detail, act, this.bakData[act]);
  340. }
  341. };
  342. break;
  343. case 'fileupload':
  344. this.$refs.upload.uploadHandleClick();
  345. return;
  346. case 'filechange':
  347. let filenum = $A.runNum(this.detail.filenum);
  348. switch (eve) {
  349. case 'up':
  350. this.$set(this.detail, 'filenum', filenum + 1);
  351. break;
  352. case 'error':
  353. case 'delete':
  354. this.$set(this.detail, 'filenum', filenum - 1);
  355. break;
  356. }
  357. if (eve == 'add' || eve == 'delete') {
  358. this.logType == '日志' && this.$refs.log.getLists(true, true);
  359. }
  360. return;
  361. case 'complete':
  362. case 'unfinished':
  363. case 'archived':
  364. case 'unarchived':
  365. break;
  366. case 'archived2':
  367. ajaxData.act = 'complete';
  368. ajaxCallback = (res) => {
  369. if (res === 1 && !this.detail.archived) {
  370. this.handleTask('archived');
  371. return false;
  372. }
  373. };
  374. break;
  375. case 'level-1':
  376. case 'level-2':
  377. case 'level-3':
  378. case 'level-4':
  379. ajaxData.act = 'level';
  380. ajaxData.content = act.substring(6);
  381. break;
  382. case 'usernameb':
  383. if (!eve.username) {
  384. return;
  385. }
  386. this.$Modal.confirm({
  387. title: this.$L('修改负责人'),
  388. content: this.$L('你确定修改负责人设置为“%”吗?', (eve.nickname || eve.username)),
  389. onOk: () => {
  390. this.handleTask('username', eve);
  391. }
  392. });
  393. return;
  394. case 'username':
  395. if (!eve.username) {
  396. return;
  397. }
  398. ajaxData.content = eve.username;
  399. ajaxCallback = (res) => {
  400. if (res === 1) {
  401. this.$Modal.info({
  402. title: this.$L('温馨提示'),
  403. content: this.$L('任务负责人已改变,点击确定关闭窗口。'),
  404. onOk: () => {
  405. this.visible = false;
  406. }
  407. });
  408. }
  409. };
  410. break;
  411. case 'inittime':
  412. if (this.detail.startdate > 0 && this.detail.enddate > 0) {
  413. this.timeValue = [$A.formatDate("Y-m-d H:i", this.detail.startdate), $A.formatDate("Y-m-d H:i", this.detail.enddate)]
  414. } else {
  415. this.timeValue = [];
  416. }
  417. return;
  418. case 'plannedtimeb':
  419. let temp = $A.date2string(this.timeValue, "Y-m-d H:i");
  420. this.$Modal.confirm({
  421. title: this.$L('修改计划时间'),
  422. content: this.$L('你确定将任务计划时间设置为“%”吗?', temp[0] + "~" + temp[1]),
  423. onOk: () => {
  424. this.handleTask('plannedtime');
  425. }
  426. });
  427. return;
  428. case 'plannedtime':
  429. this.timeValue = $A.date2string(this.timeValue);
  430. ajaxData.content = this.timeValue[0] + "," + this.timeValue[1];
  431. this.$refs.timeRef.handleClose();
  432. break;
  433. case 'unplannedtimeb':
  434. this.$Modal.confirm({
  435. title: this.$L('取消计划时间'),
  436. content: this.$L('你确定将任务计划时间取消吗?'),
  437. onOk: () => {
  438. this.handleTask('unplannedtime');
  439. }
  440. });
  441. return;
  442. case 'unplannedtime':
  443. this.$refs.timeRef.handleClose();
  444. break;
  445. case 'attentiona':
  446. ajaxData.act = "attention";
  447. ajaxData.content = this.myUsername;
  448. break;
  449. case 'attention':
  450. if (!this.detail.attentionLists) {
  451. return;
  452. }
  453. ajaxData.content = this.detail.attentionLists;
  454. this.$refs.attentionRef.handleClose();
  455. break;
  456. case 'unattention':
  457. ajaxData.content = eve.username;
  458. if (eve.uisynch === true) {
  459. let bakFollower = $A.cloneData(this.detail.follower);
  460. this.$set(this.detail, 'follower', this.detail.follower.filter((uname) => { return uname != eve }));
  461. ajaxCallback = (res) => {
  462. if (res !== 1) {
  463. this.$set(this.detail, 'follower', bakFollower);
  464. }
  465. };
  466. }
  467. break;
  468. case 'deleteb':
  469. this.$Modal.confirm({
  470. title: this.$L('删除提示'),
  471. content: this.$L('您确定要删除此任务吗?'),
  472. onOk: () => {
  473. this.handleTask('delete');
  474. },
  475. });
  476. return;
  477. case 'delete':
  478. ajaxCallback = (res) => {
  479. if (res === 1) {
  480. this.$Modal.info({
  481. title: this.$L('温馨提示'),
  482. content: this.$L('任务已删除,点击确定关闭窗口。'),
  483. onOk: () => {
  484. this.visible = false;
  485. }
  486. });
  487. }
  488. };
  489. break;
  490. case 'comment':
  491. if (!this.commentText) {
  492. return;
  493. }
  494. ajaxData.content = this.commentText;
  495. ajaxCallback = (res) => {
  496. if (res === 1) {
  497. this.commentText = "";
  498. this.logType == '评论' && this.$refs.log.getLists(true, true);
  499. }
  500. };
  501. break;
  502. default: {
  503. return;
  504. }
  505. }
  506. //
  507. this.$set(this.loadData, ajaxData.act, true);
  508. $A.aAjax({
  509. url: 'project/task/edit',
  510. data: ajaxData,
  511. complete: () => {
  512. this.$set(this.loadData, ajaxData.act, false);
  513. },
  514. error: () => {
  515. ajaxCallback(-1);
  516. alert(this.$L('网络繁忙,请稍后再试!'));
  517. },
  518. success: (res) => {
  519. if (res.ret === 1) {
  520. this.detail = res.data;
  521. this.bakData = $A.cloneData(this.detail);
  522. if (ajaxCallback(1) !== false) {
  523. this.logType == '日志' && this.$refs.log.getLists(true, true);
  524. this.$Message.success(res.msg);
  525. }
  526. $A.triggerTaskInfoListener(ajaxData.act, res.data);
  527. } else {
  528. ajaxCallback(0);
  529. this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
  530. }
  531. }
  532. });
  533. }
  534. }
  535. }
  536. </script>
  537. <style lang="scss" scoped>
  538. .project-task-detail-window {
  539. position: fixed;
  540. z-index: 1001;
  541. top: 0;
  542. left: 0;
  543. height: 100%;
  544. width: 100%;
  545. background-color: rgba(0, 0, 0, 0.5);
  546. transition: all .3s;
  547. opacity: 0;
  548. pointer-events: unset;
  549. display: flex;
  550. flex-direction: column;
  551. align-items: center;
  552. justify-content: center;
  553. &.task-detail-show {
  554. opacity: 1;
  555. }
  556. .task-detail-main {
  557. display: flex;
  558. flex-direction: row;
  559. width: 92%;
  560. max-width: 800px;
  561. max-height: 92%;
  562. background: #ffffff;
  563. overflow: visible;
  564. border-radius: 4px;
  565. padding: 10px 20px 2px;
  566. transform: translateZ(0);
  567. .detail-left {
  568. flex: 1;
  569. padding-left: 8px;
  570. padding-right: 20px;
  571. overflow: auto;
  572. .detail-h2 {
  573. color: #172b4d;
  574. font-size: 16px;
  575. display: flex;
  576. align-items: center;
  577. line-height: 26px;
  578. strong {
  579. font-size: 14px;
  580. font-weight: normal;
  581. &.link {
  582. cursor: pointer;
  583. }
  584. &.active {
  585. font-size: 16px;
  586. font-weight: bold;
  587. }
  588. }
  589. em {
  590. margin: 0 9px;
  591. width: 1px;
  592. height: 10px;
  593. background: #cccccc;
  594. }
  595. }
  596. .detail-icon {
  597. position: relative;
  598. padding-left: 26px;
  599. &:before {
  600. font-family: zenicon;
  601. font-size: 20px;
  602. color: #42526e;
  603. font-weight: 600;
  604. position: absolute;
  605. top: 0;
  606. left: 0;
  607. width: 26px;
  608. height: 26px;
  609. line-height: 26px;
  610. }
  611. }
  612. .detail-title-box {
  613. margin-top: 12px;
  614. margin-bottom: 12px;
  615. &:before {
  616. content: "\E740";
  617. }
  618. .time {
  619. font-size: 12px;
  620. color: #606266;
  621. }
  622. input {
  623. margin: -10px 0 0 -8px;
  624. font-size: 20px;
  625. font-weight: 600;
  626. border: 2px solid #ffffff;
  627. padding: 5px 8px;
  628. cursor: pointer;
  629. color: #172b4d;
  630. background: #ffffff;
  631. width: 100%;
  632. border-radius: 3px;
  633. }
  634. input:focus {
  635. outline: 0;
  636. background: #fff;
  637. border-color: #0396f2;
  638. }
  639. }
  640. .detail-desc-box {
  641. &:before {
  642. content: "\E75E";
  643. }
  644. textarea {
  645. border: 2px solid #F4F5F7;
  646. padding: 5px 8px;
  647. cursor: pointer;
  648. color: #172b4d;
  649. background: rgba(9, 30, 66, 0.04);
  650. width: 100%;
  651. border-radius: 3px;
  652. resize: none;
  653. margin-top: 10px;
  654. &:focus {
  655. outline: 0;
  656. background: #fff;
  657. border-color: #0396f2;
  658. }
  659. }
  660. }
  661. .detail-text-box {
  662. margin-bottom: 12px;
  663. li {
  664. color: #606266;
  665. font-size: 14px;
  666. line-height: 32px;
  667. word-break: break-all;
  668. display: flex;
  669. &:before {
  670. font-weight: normal;
  671. color: #606266;
  672. font-size: 14px;
  673. padding-left: 4px;
  674. line-height: 32px;
  675. }
  676. &.text-time {
  677. &:before {
  678. content: "\E706";
  679. }
  680. }
  681. &.text-username {
  682. &:before {
  683. content: "\E903";
  684. }
  685. }
  686. &.text-follower {
  687. &:before {
  688. content: "\E90D";
  689. }
  690. }
  691. &.text-level {
  692. &:before {
  693. content: "\E725";
  694. }
  695. }
  696. &.text-status {
  697. &:before {
  698. content: "\E6AF";
  699. }
  700. }
  701. > span {
  702. white-space: nowrap;
  703. }
  704. > em {
  705. margin-left: 4px;
  706. padding-top: 5px;
  707. line-height: 22px;
  708. &.p1 {
  709. color: #ed3f14;
  710. }
  711. &.p2 {
  712. color: #ff9900;
  713. }
  714. &.p3 {
  715. color: #19be6b;
  716. }
  717. &.p4 {
  718. color: #666666;
  719. }
  720. &.complete {
  721. color: #666666;
  722. }
  723. &.overdue {
  724. color: #ff0000;
  725. }
  726. &.unfinished {
  727. color: #19be6b;
  728. }
  729. }
  730. }
  731. }
  732. .detail-file-box {
  733. &:before {
  734. content: "\E8B9";
  735. font-size: 16px;
  736. padding-left: 2px;
  737. }
  738. }
  739. .detail-comment-box {
  740. &:before {
  741. content: "\E753";
  742. }
  743. }
  744. .detail-footer-box {
  745. border-top: 1px solid #e5e5e5;
  746. display: flex;
  747. flex-direction: row;
  748. padding-top: 20px;
  749. padding-bottom: 16px;
  750. .comment-input {
  751. margin-right: 12px;
  752. }
  753. }
  754. }
  755. .detail-right {
  756. .cancel {
  757. text-align: right;
  758. width: auto;
  759. height: 38px;
  760. em {
  761. display: inline-block;
  762. width: 38px;
  763. height: 38px;
  764. cursor: pointer;
  765. border-radius: 50%;
  766. transform: scale(0.92);
  767. &:after,
  768. &:before {
  769. position: absolute;
  770. content: "";
  771. top: 50%;
  772. left: 50%;
  773. width: 2px;
  774. height: 20px;
  775. background-color: #EE2321;
  776. transform: translate(-50%, -50%) rotate(45deg) scale(0.6, 1);
  777. transition: all .2s;
  778. }
  779. &:before {
  780. position: absolute;
  781. transform: translate(-50%, -50%) rotate(-45deg) scale(0.6, 1);
  782. }
  783. &:hover {
  784. &:after,
  785. &:before {
  786. background-color: #ff0000;
  787. transform: translate(-50%, -50%) rotate(135deg) scale(0.6, 1);
  788. }
  789. &:before {
  790. background-color: #ff0000;
  791. transform: translate(-50%, -50%) rotate(45deg) scale(0.6, 1);
  792. }
  793. }
  794. }
  795. }
  796. .block {
  797. display: block;
  798. .p1 {
  799. color: #ed3f14;
  800. }
  801. .p2 {
  802. color: #ff9900;
  803. }
  804. .p3 {
  805. color: #19be6b;
  806. }
  807. .p4 {
  808. color: #666666;
  809. }
  810. .checkmark {
  811. margin-left: 8px;
  812. margin-right: -8px;
  813. }
  814. }
  815. .btn {
  816. display: block;
  817. width: 118px;
  818. text-align: left;
  819. margin-top: 8px;
  820. padding-left: 10px;
  821. padding-right: 10px;
  822. }
  823. }
  824. }
  825. }
  826. </style>