framework.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. <template>
  2. <div class="all-box">
  3. <!-- 头部提示 -->
  4. <div class="diy-tip" style="margin-bottom: 10px;">
  5. <div>
  6. 当前组织架构成员通过钉钉通讯录同步,员工开启积分管理后才能正式启用并进入“功道云积分制”,如果您的钉钉通讯录有变动,点击
  7. <span class="blue" style="margin-left: 10px;cursor: pointer;" @click="tb()" v-loading="tbLoading">
  8. <i class="el-icon-refresh"></i>
  9. 立即同步
  10. </span>
  11. </div>
  12. </div>
  13. <div class="all">
  14. <div class="flex-box">
  15. <div class="terr-left">
  16. <div class="rule_class_box" v-loading="ruleDeprt">
  17. <div class="company_name">
  18. <img src="@/assets/image/two.png" />
  19. <span>组织架构</span>
  20. </div>
  21. <el-tree
  22. :data="bmList"
  23. class="cate-tree"
  24. :highlight-current="true"
  25. :props="{ children: '_child', label: 'name' }"
  26. @node-click="handleNodeClick"
  27. :accordion="true"
  28. empty-text="您暂无部门数据,请同步钉钉通讯录"
  29. >
  30. <div
  31. content="tree"
  32. v-show="treedata.length != 0"
  33. class="flex-box flex-v-ce"
  34. slot-scope="{ node, data }"
  35. style="font-size: 14px;color: #606266; width:100%; text-align: left;"
  36. >
  37. <img src="@/assets/image/one.png" style="width: 20px;margin-right: 5px;" />
  38. <span class="name">{{ data.name }}</span>
  39. </div>
  40. </el-tree>
  41. </div>
  42. </div>
  43. <div class="terr-right border-right flex-1">
  44. <div class="margin-bottom">
  45. <el-button @click="participation()" :loading="enable_loading" size="medium" type="primary">批量启用</el-button>
  46. <el-button @click="forbidden()" :loading="enable_loading" size="medium" type="danger" style="margin-right: 10px;">批量禁用</el-button>
  47. <el-select v-model="status" size="medium" style="margin-right: 10px;width: 150px;">
  48. <el-option
  49. v-for="item in options"
  50. :key="item.value"
  51. :label="item.label"
  52. :value="item.value">
  53. </el-option>
  54. </el-select>
  55. <el-input placeholder="输入同事姓名" size="medium" style="width: 230px;" v-model="keywords" clearable></el-input>
  56. </div>
  57. <el-table :data="userList" @selection-change="handleSelectionChange" v-loading="tableToading">
  58. <el-table-column type="selection" width="50" :selectable="selectable"></el-table-column>
  59. <el-table-column label="姓名">
  60. <template slot-scope="scope">
  61. <div class="flex-box flex-v-ce">
  62. <userImage :user_name="scope.row.name" :img_url="scope.row.img_url" width="44px" height="44px"></userImage>
  63. <div style="margin-left: 10px;">{{ scope.row.name }}</div>
  64. <div style="margin-left: 10px;" v-if="scope.row.is_creator" class="green">(创始人)</div>
  65. <div style="margin-left: 10px;" v-if="scope.row.id == userInfo.id" class="green">(我)</div>
  66. </div>
  67. </template>
  68. </el-table-column>
  69. <el-table-column label="部门">
  70. <template slot-scope="scope">
  71. <div class="flex-box flex-v-ce bms">
  72. <div v-for="(item, index) in scope.row.employee_detail.dept_list" :key="index">{{ item.dept_name }}</div>
  73. </div>
  74. </template>
  75. </el-table-column>
  76. <el-table-column prop="accedence_time" label="入职时间"></el-table-column>
  77. <el-table-column prop="id" label="员工标识" width="80">
  78. <template slot-scope="scope">
  79. <el-button size="mini" type="primary" @click="copyId(scope.row.id)">复制</el-button>
  80. </template>
  81. </el-table-column>
  82. <el-table-column label="是否参与排名" align="center">
  83. <template slot-scope="scope">
  84. <template v-if="scope.row.is_creator != 1">
  85. <span
  86. class="participateRank"
  87. :style="scope.row.is_ranking == 1 ? 'color:#409eff' : 'color:#F56C6C'"
  88. @click="rankingtakePartIn(scope.row.id, scope.row.is_ranking)"
  89. >
  90. {{ scope.row.is_ranking == 1 ? '参与' : '不参与' }}
  91. </span>
  92. </template>
  93. <span v-else class="fontColorB">不参与</span>
  94. </template>
  95. </el-table-column>
  96. <el-table-column label="启用积分管理">
  97. <template slot="header" slot-scope="scope">
  98. <el-popover placement="top-start" width="300" trigger="manual" v-model="visible">
  99. <div class="el-popover2">
  100. <div class="title">
  101. 提示
  102. <i class="el-icon-info" style="margin-left: 5px;"></i>
  103. </div>
  104. <div style="margin-bottom: 10px;">在这里启用积分管理,即可进入系统</div>
  105. <div class="flex-box">
  106. <div class="flex-1"></div>
  107. <el-button size="small" @click="visible_close()">我知道了</el-button>
  108. </div>
  109. </div>
  110. <div slot="reference" class="popover" @click="visible = !visible">
  111. 启用积分管理
  112. <i class="el-icon-info" style="margin-left: 5px;"></i>
  113. </div>
  114. </el-popover>
  115. </template>
  116. <template slot-scope="scope">
  117. <div :class="[scope.row.is_official == 1 ? 'switch-box' : '']" @click="changeIs(scope.row.is_official, scope.row.id)">
  118. <div class="switch"></div>
  119. </div>
  120. </template>
  121. </el-table-column>
  122. <template slot="empty">
  123. <noData></noData>
  124. </template>
  125. </el-table>
  126. <div class="pagination">
  127. <el-pagination
  128. @size-change="handleSizeChange"
  129. @current-change="handleCurrentChange"
  130. :current-page="page"
  131. :page-sizes="[10, 20, 50, 100]"
  132. :page-size="perPage"
  133. layout="total,sizes, prev, pager, next"
  134. :total="total"
  135. ></el-pagination>
  136. </div>
  137. </div>
  138. </div>
  139. <!-- 隐藏文本,用于复制ID -->
  140. <input v-model="copyIds" id="biao" style="opacity:0"/>
  141. </div>
  142. <el-dialog title="设置是否参与排名" :visible.sync="dialogVisible" top="30vh" width="520px" :before-close="handleClose">
  143. <div style="margin-left:20px;">
  144. <el-radio v-for="(item, index) in radioLi" :key="index" v-model="radio" :label="item.id">
  145. <span style="font-size:17px;">{{ item.name }}</span>
  146. <p style="font-size:14px;margin:8px 0 0 24px;">{{ item.kam }}</p>
  147. </el-radio>
  148. </div>
  149. <span slot="footer" class="dialog-footer">
  150. <el-button @click="dialogVisible = false">取 消</el-button>
  151. <el-button type="primary" @click="setRanking" :disabled="rangLoad">确 定</el-button>
  152. </span>
  153. </el-dialog>
  154. </div>
  155. </template>
  156. <script>
  157. import noData from '@/components/noData';
  158. import {_debounce} from '@/api/auth';
  159. export default {
  160. data() {
  161. return {
  162. is: 1,
  163. no: 0,
  164. page: 1,
  165. perPage: 10,
  166. total: 0,
  167. info: {}, //公司信息
  168. tips_show: true,
  169. bmList: [],
  170. userList: [],
  171. class_type: '',
  172. treedata: [1],
  173. tableData: [],
  174. keywords: '',
  175. dept_id: 0,
  176. tableToading: false,
  177. tbLoading: false,
  178. selectIds: [],
  179. enable_loading: false,
  180. visible: false,
  181. ruleDeprt: false,
  182. dialogVisible: false,
  183. rankingtakePartInId: '',
  184. radio: '1',
  185. rangLoad: false,
  186. radioLi: [{ id: '1', name: '参与排名', kam: '在排名中展示此人' }, { id: '0', name: '不参与排名', kam: '排名不展示此人(自定义排名除外)' }],
  187. userInfo: this.$getUserData(),
  188. copyIds:'',
  189. options: [{
  190. value: '-1',
  191. label: '全部'
  192. }, {
  193. value: '1',
  194. label: '已开启'
  195. }, {
  196. value: '0',
  197. label: '已禁用'
  198. }],
  199. status: '-1'
  200. };
  201. },
  202. components: {
  203. noData
  204. },
  205. watch: {
  206. keywords: {
  207. deep: true,
  208. handler: _debounce(function(val) {
  209. this.page = 1;
  210. this.getEmployee();
  211. })
  212. },
  213. dept_id(val) {
  214. this.getEmployee();
  215. },
  216. status(){
  217. this.page = 1;
  218. this.getEmployee();
  219. }
  220. },
  221. created() {
  222. this.getInfo();
  223. this.getEmployee();
  224. },
  225. mounted() {
  226. this.$nextTick(function() {
  227. if (localStorage.getItem('rule')) {
  228. this.tips_show = false;
  229. } else {
  230. this.tips_show = true;
  231. }
  232. });
  233. },
  234. methods: {
  235. // 复制ID
  236. copyId(id) {
  237. this.$axios('get', '/api/employee/code', { employee_id: id })
  238. .then(res => {
  239. if (res.data.code == 1) {
  240. this.copyIds = res.data.data.encrypt_code;
  241. this.$nextTick(()=>{
  242. this.copyToClipboard();
  243. })
  244. }
  245. })
  246. },
  247. copyToClipboard() {
  248. var Url2=document.getElementById("biao");
  249. console.log(Url2)
  250. Url2.select(); // 选择对象
  251. document.execCommand("Copy"); // 执行浏览器复制命令
  252. this.$message.success('已复制');
  253. },
  254. forbidden() {
  255. if (this.selectIds.length == 0) {
  256. this.$message.error({ message: '请选择禁用的人员!' });
  257. return;
  258. }
  259. this.$confirm('确定禁用选择的人员?', '提示', {
  260. confirmButtonText: '确定',
  261. cancelButtonText: '取消',
  262. type: 'warning'
  263. }).then(() => {
  264. this.enable_loading = true;
  265. this.$axios('post', '/api/employee/disable', { employee_id: this.selectIds })
  266. .then(res => {
  267. if (res) {
  268. this.$message.success('已禁用');
  269. this.getEmployee();
  270. }
  271. })
  272. .finally(err => {
  273. this.enable_loading = false;
  274. });
  275. });
  276. },
  277. selectable(row) {
  278. if (row.is_creator) {
  279. return false;
  280. } else if (this.userInfo.id == row.id) {
  281. return false;
  282. } else {
  283. return true;
  284. }
  285. },
  286. setRanking() {
  287. this.rangLoad = true;
  288. let data = {
  289. employee_id: this.rankingtakePartInId,
  290. switch: Number(this.radio)
  291. };
  292. this.$axios('post', '/api/employee/ranking_switch', data)
  293. .then(res => {
  294. if (res.data.code == 1) {
  295. this.$message.success({ message: res.data.msg });
  296. this.getEmployee();
  297. }
  298. })
  299. .finally(() => {
  300. this.dialogVisible = false;
  301. setTimeout(() => {
  302. this.rangLoad = false;
  303. }, 200);
  304. });
  305. },
  306. rankingtakePartIn(id, is_ranking) {
  307. this.radio = is_ranking.toString();
  308. this.rankingtakePartInId = id;
  309. this.dialogVisible = true;
  310. },
  311. handleClose(done) {
  312. done();
  313. },
  314. //同步信息
  315. tb() {
  316. this.$confirm('下次同步时间需在10分钟之后,是否同步?', '提示', {
  317. confirmButtonText: '确定',
  318. cancelButtonText: '取消',
  319. type: 'warning'
  320. }).then(() => {
  321. this.tbLoading = true;
  322. this.$axios('post', '/api/ding/department_sync')
  323. .then(res => {
  324. this.$message.success({ message: '同步成功' });
  325. this.dept_id = 0;
  326. this.getInfo();
  327. this.getEmployee();
  328. })
  329. .finally(() => {
  330. this.tbLoading = false;
  331. });
  332. });
  333. },
  334. //搜索
  335. searchUser() {
  336. this.page = 1;
  337. this.getEmployee();
  338. },
  339. //是否开通
  340. changeIs(e, id) {
  341. var url = e == 1 ? '/api/employee/disable' : '/api/employee/enable';
  342. this.$axios('post', url, { employee_id: [id] }).then(res => {
  343. if (res) {
  344. if (e == 0) {
  345. this.$message.success({ message: '开启成功,可在"角色权限设置对应管理范围"' });
  346. } else {
  347. this.$message.success({ message: res.data.msg });
  348. }
  349. this.getEmployee();
  350. }
  351. });
  352. },
  353. //批量开通权限
  354. participation() {
  355. if (this.selectIds.length == 0) {
  356. this.$message.error({ message: '请选择参与的人员!' });
  357. return;
  358. }
  359. this.enable_loading = true;
  360. this.$axios('post', '/api/employee/enable', { employee_id: this.selectIds })
  361. .then(res => {
  362. if (res) {
  363. this.$message.success({ message: '开启成功,可在"角色权限设置对应管理范围"' });
  364. this.getEmployee();
  365. }
  366. })
  367. .finally(err => {
  368. this.enable_loading = false;
  369. });
  370. },
  371. //获取公司信息
  372. getInfo(is) {
  373. this.ruleDeprt = true;
  374. this.$axios('get', '/api/site/info').then(res => {
  375. this.info = res.data.data;
  376. this.getDepartment(is);
  377. });
  378. },
  379. //选择员工
  380. handleSelectionChange(e) {
  381. var arr = [];
  382. for (var item in e) {
  383. arr.push(e[item].id);
  384. }
  385. this.selectIds = arr;
  386. },
  387. //点击部门
  388. handleNodeClick(e) {
  389. this.page = 1;
  390. this.dept_id = e.id;
  391. },
  392. //获取部门
  393. getDepartment() {
  394. this.ruleDeprt = true;
  395. this.$axios('get', '/api/department/tree')
  396. .then(res => {
  397. var list = [
  398. {
  399. id: 0,
  400. name: this.info.name,
  401. _child: res.data.data.list
  402. }
  403. ];
  404. this.bmList = list;
  405. })
  406. .finally(() => {
  407. this.ruleDeprt = false;
  408. });
  409. },
  410. //获取员工
  411. getEmployee() {
  412. this.tableToading = true;
  413. let data={
  414. dept_id: this.dept_id,
  415. keywords: this.keywords,
  416. page: this.page,
  417. page_size:this.perPage,
  418. }
  419. let is_official=this.status=='-1'? '':this.status;
  420. if(is_official){
  421. data.is_official=is_official;
  422. }
  423. this.$axios('get', '/api/employee/index', data).then(res => {
  424. this.total = res.data.data.pageInfo.count;
  425. this.userList = res.data.data.list;
  426. var visible = localStorage.getItem('visible');
  427. if (!visible) {
  428. this.visible = true;
  429. }
  430. })
  431. .finally(err => {
  432. this.tableToading = false;
  433. });
  434. },
  435. visible_close() {
  436. localStorage.setItem('visible', 'true');
  437. this.visible = false;
  438. },
  439. //关闭提示
  440. tips_close() {
  441. localStorage.setItem('rule', 'true');
  442. this.tips_show = false;
  443. },
  444. handleSizeChange: function(val) {
  445. this.perPage = val;
  446. this.page = 1;
  447. this.getEmployee();
  448. },
  449. //页码变更
  450. handleCurrentChange: function(val) {
  451. this.page = val;
  452. this.getEmployee();
  453. }
  454. }
  455. };
  456. </script>
  457. <style lang="scss" scoped="scoped">
  458. .title {
  459. font-size: 16px;
  460. color: #909399;
  461. margin-bottom: 10px;
  462. }
  463. .popover {
  464. border: none;
  465. // color: #909399;
  466. font-weight: 600;
  467. cursor: pointer;
  468. }
  469. .popover:hover {
  470. background-color: #fff;
  471. border-color: #fff;
  472. }
  473. .switch {
  474. margin: 0;
  475. display: inline-block;
  476. position: relative;
  477. width: 40px;
  478. height: 20px;
  479. border: 1px solid #dcdfe6;
  480. outline: none;
  481. border-radius: 10px;
  482. box-sizing: border-box;
  483. background: #dcdfe6;
  484. cursor: pointer;
  485. transition: border-color 0.3s, background-color 0.3s;
  486. vertical-align: middle;
  487. }
  488. .switch:after {
  489. content: '';
  490. position: absolute;
  491. top: 1px;
  492. left: 1px;
  493. border-radius: 100%;
  494. transition: all 0.3s;
  495. width: 16px;
  496. height: 16px;
  497. background-color: #fff;
  498. }
  499. .switch-box .switch {
  500. border-color: #409eff;
  501. background-color: #409eff;
  502. }
  503. .switch-box .switch:after {
  504. left: 100%;
  505. margin-left: -17px;
  506. }
  507. .name {
  508. overflow: hidden;
  509. text-overflow: ellipsis;
  510. white-space: nowrap;
  511. width: 80%;
  512. }
  513. .bms div {
  514. margin-right: 10px;
  515. }
  516. .top-msg div:nth-child(1) {
  517. margin-bottom: 10px;
  518. }
  519. .company_name {
  520. position: relative;
  521. display: block;
  522. font-family: 'Microsoft YaHei';
  523. text-align: left;
  524. padding: 15px 25px;
  525. cursor: pointer;
  526. overflow: hidden;
  527. white-space: nowrap;
  528. text-overflow: ellipsis;
  529. border-bottom: 1px #f8f8f8 solid;
  530. }
  531. .company_name img {
  532. position: relative;
  533. display: inline-block;
  534. top: 2px;
  535. width: 18px;
  536. height: 18px;
  537. margin-right: 4px;
  538. }
  539. .terr-right {
  540. .custom-tree-node {
  541. margin-left: -4px;
  542. }
  543. .custom-tree-node * {
  544. vertical-align: middle;
  545. }
  546. .custom-tree-node:hover {
  547. .treeIcon {
  548. display: inline-block;
  549. width: 55%;
  550. }
  551. }
  552. }
  553. .el-popover2 {
  554. // background-color: #409eff !important;
  555. color: #409eff;
  556. }
  557. .rule_class_box {
  558. ::v-deep .el-tree-node {
  559. border-bottom: 1px #f8f8f8 solid;
  560. }
  561. ::v-deep .el-tree-node__content {
  562. padding: 10px 0;
  563. // border-bottom: 1px #f8f8f8 solid;
  564. }
  565. ::v-deep .el-tree-node__content:hover {
  566. background: #ecf5ff;
  567. border-radius: 4px;
  568. }
  569. ::v-deep .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content .name {
  570. color: #409eff !important;
  571. font-weight: normal;
  572. transition: 0.35s ease-in-out;
  573. }
  574. // ::v-deep .is-current .el-tree-node__content .el-icon-caret-right {
  575. // color: #409eff !important;
  576. // }
  577. // ::v-deep .is-current .el-tree-node__content .el-tree-node__label {
  578. // color: #409eff !important;
  579. // }
  580. // ::v-deep .is-current .el-tree-node__children .el-icon-caret-right {
  581. // color: #c0c4cc !important;
  582. // }
  583. // ::v-deep .is-current .el-tree-node__children .el-tree-node__label {
  584. // color: #606266 !important;
  585. // }
  586. // ::v-deep .is-current .name {
  587. // color: #409eff !important;
  588. // font-weight: normal;
  589. // transition: 0.35s ease-in-out;
  590. // }
  591. }
  592. .participateRank {
  593. cursor: pointer;
  594. text-decoration: underline;
  595. }
  596. </style>