index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. <template>
  2. <div class="app-container">
  3. <el-row :gutter="20">
  4. <!--部门数据-->
  5. <el-col :span="2" :xs="24" style="padding-left:0;padding-right:0;">
  6. <div class="head-container">
  7. <el-input
  8. v-model="deptName"
  9. placeholder="请输入部门名称"
  10. clearable
  11. size="small"
  12. prefix-icon="el-icon-search"
  13. style="margin-bottom: 20px"
  14. />
  15. </div>
  16. <div class="head-container">
  17. <el-tree
  18. :data="deptOptions"
  19. :props="defaultProps"
  20. :expand-on-click-node="false"
  21. :filter-node-method="filterNode"
  22. ref="tree"
  23. node-key="id"
  24. default-expand-all
  25. highlight-current
  26. @node-click="handleNodeClick"
  27. />
  28. </div>
  29. </el-col>
  30. <!--用户数据-->
  31. <el-col :span="22" :xs="24">
  32. <el-form
  33. :model="queryParams"
  34. ref="queryForm"
  35. size="small"
  36. :inline="true"
  37. v-show="showSearch"
  38. label-width="68px"
  39. >
  40. <el-form-item label="项目编号" prop="projectNumber">
  41. <el-input
  42. v-model="queryParams.projectNumber"
  43. placeholder="请输入项目编号"
  44. clearable
  45. style="width: 240px"
  46. @keyup.enter.native="handleQuery"
  47. />
  48. </el-form-item>
  49. <el-form-item label="项目名称" prop="projectName">
  50. <el-input
  51. v-model="queryParams.projectName"
  52. placeholder="请输入项目名称"
  53. clearable
  54. style="width: 240px"
  55. @keyup.enter.native="handleQuery"
  56. />
  57. </el-form-item>
  58. <el-form-item label="时间">
  59. <el-date-picker
  60. v-model="dateRange"
  61. style="width: 240px"
  62. value-format="yyyy-MM-dd"
  63. type="daterange"
  64. range-separator="-"
  65. start-placeholder="开始日期"
  66. end-placeholder="结束日期"
  67. ></el-date-picker>
  68. </el-form-item>
  69. <el-form-item label="兼职全职" prop="fullJob">
  70. <el-select
  71. v-model="queryParams.fullJob"
  72. placeholder="兼职/全职"
  73. clearable
  74. style="width: 240px"
  75. >
  76. <el-option
  77. v-for="dict in dict.type.sys_user_fulljob"
  78. :key="dict.value"
  79. :label="dict.label"
  80. :value="dict.value"
  81. />
  82. </el-select>
  83. </el-form-item>
  84. <el-form-item label="研发阶段" prop="projectStatus">
  85. <el-select
  86. v-model="queryParams.projectStatus"
  87. placeholder="研发阶段"
  88. clearable
  89. style="width: 240px"
  90. >
  91. <el-option
  92. v-for="dict in dict.type.syx_record_stage"
  93. :key="dict.value"
  94. :label="dict.label"
  95. :value="dict.value"
  96. />
  97. </el-select>
  98. </el-form-item>
  99. <el-form-item>
  100. <el-button
  101. type="primary"
  102. icon="el-icon-search"
  103. size="mini"
  104. @click="handleQuery"
  105. >搜索</el-button
  106. >
  107. <el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
  108. >重置</el-button
  109. >
  110. </el-form-item>
  111. </el-form>
  112. <el-row :gutter="10" class="mb8">
  113. <el-col :span="1.5">
  114. <el-button
  115. type="info"
  116. plain
  117. icon="el-icon-upload2"
  118. size="mini"
  119. @click="handleImport"
  120. v-hasPermi="['system:user:import']"
  121. >导入</el-button
  122. >
  123. </el-col>
  124. <el-col :span="1.5">
  125. <el-button
  126. type="warning"
  127. plain
  128. icon="el-icon-download"
  129. size="mini"
  130. @click="handleExport"
  131. v-hasPermi="['system:user:export']"
  132. >导出</el-button
  133. >
  134. </el-col>
  135. <el-col :span="1.5">
  136. <el-button
  137. type="primary"
  138. plain
  139. icon="el-icon-download"
  140. size="mini"
  141. :disabled="multiple"
  142. @click="handleDownload"
  143. v-hasPermi="['system:user:export']"
  144. >下载附件</el-button
  145. >
  146. </el-col>
  147. <right-toolbar
  148. :showSearch.sync="showSearch"
  149. @queryTable="getList"
  150. :columns="columns"
  151. ></right-toolbar>
  152. </el-row>
  153. <el-table
  154. v-loading="loading"
  155. :data="userList"
  156. @selection-change="handleSelectionChange"
  157. >
  158. <el-table-column type="selection" width="50" align="center" />
  159. <el-table-column
  160. label="员工工号"
  161. align="center"
  162. key="jobNumber"
  163. prop="jobNumber"
  164. v-if="columns[0].visible"
  165. />
  166. <el-table-column
  167. label="员工姓名"
  168. align="center"
  169. key="name"
  170. prop="name"
  171. v-if="columns[1].visible"
  172. :show-overflow-tooltip="true"
  173. />
  174. <el-table-column
  175. label="部门编号"
  176. align="center"
  177. key="deptId"
  178. prop="deptId"
  179. v-if="columns[2].visible"
  180. :show-overflow-tooltip="true"
  181. />
  182. <el-table-column
  183. label="部门"
  184. align="center"
  185. key="deptName"
  186. prop="deptName"
  187. v-if="columns[3].visible"
  188. />
  189. <el-table-column
  190. label="打卡时间"
  191. width="100"
  192. align="center"
  193. key="recordTime"
  194. prop="recordTime"
  195. v-if="columns[4].visible"
  196. />
  197. <el-table-column
  198. label="工时"
  199. align="center"
  200. width="50"
  201. key="duration"
  202. prop="duration"
  203. v-if="columns[5].visible"
  204. />
  205. <el-table-column
  206. label="打卡月份"
  207. align="center"
  208. key="createMonth"
  209. prop="createMonth"
  210. v-if="columns[6].visible"
  211. />
  212. <el-table-column
  213. label="项目编号"
  214. align="center"
  215. key="projectNumber"
  216. prop="projectNumber"
  217. v-if="columns[7].visible"
  218. />
  219. <el-table-column
  220. label="项目名称"
  221. align="center"
  222. key="projectName"
  223. prop="projectName"
  224. v-if="columns[8].visible"
  225. />
  226. <el-table-column
  227. label="研发阶段"
  228. align="center"
  229. key="projectStatus"
  230. prop="projectStatus"
  231. v-if="columns[9].visible"
  232. >
  233. <template slot-scope="scope">
  234. <dict-tag :options="dict.type.syx_record_stage" :value="scope.row.projectStatus"/>
  235. </template>
  236. </el-table-column>
  237. <el-table-column
  238. label="日报内容"
  239. align="center"
  240. key="content"
  241. prop="content"
  242. v-if="columns[10].visible"
  243. :show-overflow-tooltip="true"
  244. />
  245. <!-- :show-overflow-tooltip="true" -->
  246. <el-table-column
  247. label="审核人员"
  248. align="center"
  249. key="examineName"
  250. prop="examineName"
  251. v-if="columns[11].visible"
  252. />
  253. <el-table-column
  254. label="审核时间"
  255. width="100"
  256. align="center"
  257. key="examineTime"
  258. prop="examineTime"
  259. v-if="columns[12].visible"
  260. />
  261. <el-table-column
  262. label="附件"
  263. align="center"
  264. width="80"
  265. class-name="small-padding fixed-width"
  266. >
  267. <template slot-scope="scope" v-if="scope.row.userId !== 1">
  268. <el-button
  269. size="mini"
  270. type="text"
  271. icon="el-icon-edit"
  272. @click="handleSelect(scope.row)"
  273. >查看</el-button
  274. >
  275. </template>
  276. </el-table-column>
  277. </el-table>
  278. <pagination
  279. v-show="total > 0"
  280. :total="total"
  281. :page.sync="queryParams.pageNum"
  282. :limit.sync="queryParams.pageSize"
  283. @pagination="getList"
  284. />
  285. </el-col>
  286. </el-row>
  287. <!-- 项目导入对话框 -->
  288. <el-dialog
  289. :title="upload.title"
  290. :visible.sync="upload.open"
  291. width="400px"
  292. append-to-body
  293. >
  294. <el-upload
  295. ref="upload"
  296. :limit="1"
  297. accept=".xlsx, .xls"
  298. :headers="upload.headers"
  299. :action="upload.url + '?updateSupport=' + upload.updateSupport"
  300. :disabled="upload.isUploading"
  301. :on-progress="handleFileUploadProgress"
  302. :on-success="handleFileSuccess"
  303. :auto-upload="false"
  304. drag
  305. >
  306. <i class="el-icon-upload"></i>
  307. <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
  308. <div class="el-upload__tip text-center" slot="tip">
  309. <div class="el-upload__tip" slot="tip">
  310. <el-checkbox v-model="upload.updateSupport" /> 是否更新已经存在的用户数据
  311. </div>
  312. <span>仅允许导入xls、xlsx格式文件。</span>
  313. <el-link
  314. type="primary"
  315. :underline="false"
  316. style="font-size: 12px; vertical-align: baseline"
  317. @click="importTemplate"
  318. >下载模板</el-link
  319. >
  320. </div>
  321. </el-upload>
  322. <div slot="footer" class="dialog-footer">
  323. <el-button type="primary" @click="submitFileForm">确 定</el-button>
  324. <el-button @click="upload.open = false">取 消</el-button>
  325. </div>
  326. </el-dialog>
  327. <el-dialog :title="title" :visible.sync="open" width="400px" append-to-body>
  328. <template slot-scope="scope" v-if="!srcList">
  329. <span>暂无附件~</span>
  330. </template>
  331. <template slot-scope="scope" v-if="!!srcList">
  332. <ImagePreview :src="srcList" :width="100" :height="100" />
  333. </template>
  334. </el-dialog>
  335. </div>
  336. </template>
  337. <script>
  338. import { listRecord } from "@/api/system/record";
  339. import { deptTreeSelect } from "@/api/system/user";
  340. import { getToken } from "@/utils/auth";
  341. import Treeselect from "@riophae/vue-treeselect";
  342. import "@riophae/vue-treeselect/dist/vue-treeselect.css";
  343. export default {
  344. name: "Record",
  345. dicts: ["sys_user_fulljob", "syx_record_stage"],
  346. components: { Treeselect },
  347. data() {
  348. return {
  349. // 遮罩层
  350. loading: true,
  351. // 选中数组
  352. ids: [],
  353. // 非单个禁用
  354. single: true,
  355. // 非多个禁用
  356. multiple: true,
  357. // 显示搜索条件
  358. showSearch: true,
  359. // 总条数
  360. total: 0,
  361. // 用户表格数据
  362. userList: null,
  363. // 弹出层标题
  364. title: "",
  365. // 部门树选项
  366. deptOptions: undefined,
  367. // 是否显示弹出层
  368. open: false,
  369. // 部门名称
  370. deptName: undefined,
  371. // 默认密码
  372. initPassword: undefined,
  373. // 日期范围
  374. dateRange: [],
  375. // 岗位选项
  376. postOptions: [],
  377. // 角色选项
  378. roleOptions: [],
  379. // 表单参数
  380. form: {},
  381. // 附件
  382. srcList: "",
  383. year: [
  384. { label: "非跨年", value: 0 },
  385. { label: "跨年", value: 1 },
  386. ],
  387. defaultProps: {
  388. children: "children",
  389. label: "label",
  390. },
  391. // 用户导入参数
  392. upload: {
  393. // 是否显示弹出层(用户导入)
  394. open: false,
  395. // 弹出层标题(用户导入)
  396. title: "",
  397. // 是否禁用上传
  398. isUploading: false,
  399. // 是否更新已经存在的用户数据
  400. updateSupport: 0,
  401. // 设置上传的请求头部
  402. headers: { Authorization: "Bearer " + getToken() },
  403. // 上传的地址
  404. url: process.env.VUE_APP_BASE_API + "/api/project/listRecord/importData",
  405. },
  406. // 查询参数
  407. queryParams: {
  408. pageNum: 1,
  409. pageSize: 10,
  410. projectNumber: undefined,
  411. name: undefined,
  412. staffId: undefined,
  413. projectYear: undefined,
  414. crossYear: undefined,
  415. deptId: undefined,
  416. },
  417. // 列信息
  418. columns: [
  419. { key: 0, label: `员工工号`, visible: true },
  420. { key: 1, label: `员工姓名`, visible: true },
  421. { key: 2, label: `部门编号`, visible: true },
  422. { key: 3, label: `部门`, visible: true },
  423. { key: 4, label: `打卡时间`, visible: true },
  424. { key: 5, label: `工时`, visible: true },
  425. { key: 6, label: `打卡月份`, visible: true },
  426. { key: 7, label: `项目编号`, visible: true },
  427. { key: 8, label: `项目名称`, visible: true },
  428. { key: 9, label: `创建任务`, visible: true },
  429. { key: 10, label: `日报内容`, visible: true },
  430. { key: 11, label: `研发人员`, visible: true },
  431. { key: 12, label: `研发时间`, visible: true },
  432. ],
  433. // 表单校验
  434. rules: {
  435. // projectNumber: [
  436. // { required: true, message: "用户名称不能为空", trigger: "blur" },
  437. // { min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
  438. // ],
  439. // name: [
  440. // { required: true, message: "用户昵称不能为空", trigger: "blur" }
  441. // ],
  442. // password: [
  443. // { required: true, message: "用户密码不能为空", trigger: "blur" },
  444. // { min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' }
  445. // ],
  446. // email: [
  447. // {
  448. // type: "email",
  449. // message: "请输入正确的邮箱地址",
  450. // trigger: ["blur", "change"]
  451. // }
  452. // ],
  453. // phonenumber: [
  454. // {
  455. // pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
  456. // message: "请输入正确的手机号码",
  457. // trigger: "blur"
  458. // }
  459. // ]
  460. },
  461. };
  462. },
  463. watch: {
  464. // 根据名称筛选部门树
  465. deptName(val) {
  466. this.$refs.tree.filter(val);
  467. },
  468. },
  469. created() {
  470. this.getList();
  471. this.getDeptTree();
  472. this.getConfigKey("sys.user.initPassword").then((response) => {
  473. this.initPassword = response.msg;
  474. });
  475. },
  476. methods: {
  477. /** 查询用户列表 */
  478. getList() {
  479. this.loading = true;
  480. if (this.dateRange.length > 0) {
  481. this.queryParams.startTime = this.dateRange[0];
  482. this.queryParams.endTime = this.dateRange[1];
  483. }
  484. this.queryParams.roleType = 3;
  485. listRecord(this.queryParams).then((response) => {
  486. this.userList = response.rows;
  487. this.total = response.total;
  488. this.loading = false;
  489. });
  490. },
  491. /** 查询部门下拉树结构 */
  492. getDeptTree() {
  493. deptTreeSelect().then((response) => {
  494. this.deptOptions = response.data;
  495. });
  496. },
  497. // 筛选节点
  498. filterNode(value, data) {
  499. if (!value) return true;
  500. return data.label.indexOf(value) !== -1;
  501. },
  502. // 节点单击事件
  503. handleNodeClick(data) {
  504. this.queryParams.deptId = data.id;
  505. this.handleQuery();
  506. },
  507. /** 搜索按钮操作 */
  508. handleQuery() {
  509. this.queryParams.pageNum = 1;
  510. this.getList();
  511. },
  512. /** 重置按钮操作 */
  513. resetQuery() {
  514. this.dateRange = [];
  515. this.resetForm("queryForm");
  516. this.queryParams.startTime = undefined;
  517. this.queryParams.endTime = undefined;
  518. this.queryParams.deptId = undefined;
  519. this.$refs.tree.setCurrentKey(null);
  520. this.handleQuery();
  521. },
  522. // 多选框选中数据
  523. handleSelectionChange(selection) {
  524. this.ids = selection.map((item) => item.id);
  525. this.single = selection.length != 1;
  526. this.multiple = !selection.length;
  527. },
  528. /** 查看按钮 */
  529. handleSelect(row) {
  530. this.title = "查看附件";
  531. this.srcList = row.annexUrl;
  532. this.open = true;
  533. },
  534. /** 下载附件 */
  535. handleDownload(row) {
  536. const ids = this.ids.toString();
  537. const url = "/api/project/download?ids=" + ids;
  538. const _this = this;
  539. var date = new Date();
  540. var year = date.getFullYear();
  541. var month =
  542. date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
  543. var day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
  544. var hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
  545. var minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
  546. var seconds = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
  547. var time = year + "" + month + "" + day + "" + hours + "" + minutes + "" + seconds;
  548. this.$modal
  549. .confirm("确认下载已经勾选的项目附件吗?")
  550. .then(function () {
  551. _this.$download.zip(url, `项目打卡数据_${time}`);
  552. _this.$modal.msgSuccess("下载成功");
  553. })
  554. .then(() => {})
  555. .catch(() => {});
  556. },
  557. /** 导出按钮操作 */
  558. handleExport() {
  559. this.download(
  560. "api/project/listRecord/export",
  561. {
  562. ...this.queryParams,
  563. },
  564. `project_record_${new Date().getTime()}.xlsx`
  565. );
  566. },
  567. /** 导入按钮操作 */
  568. handleImport() {
  569. this.upload.title = "项目导入";
  570. this.upload.open = true;
  571. },
  572. /** 下载模板操作 */
  573. importTemplate() {
  574. this.download(
  575. "api/project/listRecord/importTemplate",
  576. {},
  577. `project_record_template_${new Date().getTime()}.xlsx`
  578. );
  579. },
  580. // 文件上传中处理
  581. handleFileUploadProgress(event, file, fileList) {
  582. this.upload.isUploading = true;
  583. },
  584. // 文件上传成功处理
  585. handleFileSuccess(response, file, fileList) {
  586. this.upload.open = false;
  587. this.upload.isUploading = false;
  588. this.$refs.upload.clearFiles();
  589. this.$alert(
  590. "<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" +
  591. response.msg +
  592. "</div>",
  593. "导入结果",
  594. { dangerouslyUseHTMLString: true }
  595. );
  596. this.getList();
  597. },
  598. // 提交上传文件
  599. submitFileForm() {
  600. this.$refs.upload.submit();
  601. },
  602. },
  603. };
  604. </script>
  605. <style lang="scss" scoped>
  606. .head-container {
  607. word-wrap: break-word;
  608. overflow: hidden;
  609. word-break: break-all;
  610. }
  611. </style>