framework.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  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. <div>
  58. <el-button size="small" type="success" @click="import_rules_show = true" plain>导入人员</el-button>
  59. <el-button size="small" type="primary" @click="derivedRule" plain>导出人员</el-button>
  60. </div>
  61. <el-table :data="userList" @selection-change="handleSelectionChange" v-loading="tableToading">
  62. <el-table-column type="selection" width="50" :selectable="selectable"></el-table-column>
  63. <el-table-column label="姓名">
  64. <template slot-scope="scope">
  65. <div class="flex-box flex-v-ce">
  66. <userImage :user_name="scope.row.name" :img_url="scope.row.img_url" width="44px" height="44px"></userImage>
  67. <div style="margin-left: 10px;">{{ scope.row.name }}</div>
  68. <div style="margin-left: 10px;" v-if="scope.row.is_creator" class="green">(创始人)</div>
  69. <div style="margin-left: 10px;" v-if="scope.row.id == userInfo.id" class="green">(我)</div>
  70. </div>
  71. </template>
  72. </el-table-column>
  73. <el-table-column label="部门">
  74. <template slot-scope="scope">
  75. <div class="flex-box flex-v-ce bms">
  76. <div v-for="(item, index) in scope.row.employee_detail.dept_list" :key="index">{{ item.dept_name }}</div>
  77. </div>
  78. </template>
  79. </el-table-column>
  80. <el-table-column prop="accedence_time" label="入职时间"></el-table-column>
  81. <el-table-column prop="id" label="员工标识" width="80">
  82. <template slot-scope="scope">
  83. <el-button size="mini" type="primary" @click="copyId(scope.row.id)">复制</el-button>
  84. </template>
  85. </el-table-column>
  86. <el-table-column label="是否参与排名" align="center">
  87. <template slot-scope="scope">
  88. <template v-if="scope.row.is_creator != 1">
  89. <span
  90. class="participateRank"
  91. :style="scope.row.is_ranking == 1 ? 'color:#409eff' : 'color:#F56C6C'"
  92. @click="rankingtakePartIn(scope.row.id, scope.row.is_ranking)"
  93. >
  94. {{ scope.row.is_ranking == 1 ? '参与' : '不参与' }}
  95. </span>
  96. </template>
  97. <span v-else class="fontColorB">不参与</span>
  98. </template>
  99. </el-table-column>
  100. <el-table-column label="启用积分管理">
  101. <template slot="header" slot-scope="scope">
  102. <el-popover placement="top-start" width="300" trigger="manual" v-model="visible">
  103. <div class="el-popover2">
  104. <div class="title">
  105. 提示
  106. <i class="el-icon-info" style="margin-left: 5px;"></i>
  107. </div>
  108. <div style="margin-bottom: 10px;">在这里启用积分管理,即可进入系统</div>
  109. <div class="flex-box">
  110. <div class="flex-1"></div>
  111. <el-button size="small" @click="visible_close()">我知道了</el-button>
  112. </div>
  113. </div>
  114. <div slot="reference" class="popover" @click="visible = !visible">
  115. 启用积分管理
  116. <i class="el-icon-info" style="margin-left: 5px;"></i>
  117. </div>
  118. </el-popover>
  119. </template>
  120. <template slot-scope="scope">
  121. <div :class="[scope.row.is_official == 1 ? 'switch-box' : '']" @click="changeIs(scope.row.is_official, scope.row.id)">
  122. <div class="switch"></div>
  123. </div>
  124. </template>
  125. </el-table-column>
  126. <template slot="empty">
  127. <noData></noData>
  128. </template>
  129. </el-table>
  130. <div class="pagination">
  131. <el-pagination
  132. @size-change="handleSizeChange"
  133. @current-change="handleCurrentChange"
  134. :current-page="page"
  135. :page-sizes="[10, 20, 50, 100]"
  136. :page-size="perPage"
  137. layout="total,sizes, prev, pager, next"
  138. :total="total"
  139. ></el-pagination>
  140. </div>
  141. </div>
  142. </div>
  143. <!-- 隐藏文本,用于复制ID -->
  144. <input v-model="copyIds" id="biao" style="opacity:0"/>
  145. </div>
  146. <el-dialog title="设置是否参与排名" :visible.sync="dialogVisible" top="30vh" width="520px" :before-close="handleClose">
  147. <div style="margin-left:20px;">
  148. <el-radio v-for="(item, index) in radioLi" :key="index" v-model="radio" :label="item.id">
  149. <span style="font-size:17px;">{{ item.name }}</span>
  150. <p style="font-size:14px;margin:8px 0 0 24px;">{{ item.kam }}</p>
  151. </el-radio>
  152. </div>
  153. <span slot="footer" class="dialog-footer">
  154. <el-button @click="dialogVisible = false">取 消</el-button>
  155. <el-button type="primary" @click="setRanking" :disabled="rangLoad">确 定</el-button>
  156. </span>
  157. </el-dialog>
  158. <!-- 导入规则 -->
  159. <el-dialog title="导入人员" :visible.sync="import_rules_show" width="500px" @before-close="close_import">
  160. <div class="text-center flex-box-v flex-center-center">
  161. <p><img src="@/assets/image/rules_mould1.png" alt="" /></p>
  162. <p>仅支持xls、xlsx格式文件</p>
  163. <el-upload
  164. class="upload-demo"
  165. :headers="ATOKEN"
  166. ref="upload"
  167. :limit="1"
  168. :action="action"
  169. :on-remove="handleRemove"
  170. :on-success="handleSuccess"
  171. :before-upload="beforeFilesUpload"
  172. :file-list="fileList"
  173. >
  174. <el-button slot="trigger" type="primary">选取文件</el-button>
  175. </el-upload>
  176. </div>
  177. </el-dialog>
  178. </div>
  179. </template>
  180. <script>
  181. import noData from '@/components/noData';
  182. import {_debounce} from '@/api/auth';
  183. export default {
  184. data() {
  185. return {
  186. is: 1,
  187. no: 0,
  188. page: 1,
  189. perPage: 10,
  190. total: 0,
  191. info: {}, //公司信息
  192. tips_show: true,
  193. bmList: [],
  194. userList: [],
  195. class_type: '',
  196. treedata: [1],
  197. tableData: [],
  198. keywords: '',
  199. dept_id: 0,
  200. tableToading: false,
  201. tbLoading: false,
  202. selectIds: [],
  203. enable_loading: false,
  204. visible: false,
  205. ruleDeprt: false,
  206. dialogVisible: false,
  207. rankingtakePartInId: '',
  208. radio: '1',
  209. rangLoad: false,
  210. radioLi: [{ id: '1', name: '参与排名', kam: '在排名中展示此人' }, { id: '0', name: '不参与排名', kam: '排名不展示此人(自定义排名除外)' }],
  211. userInfo: this.$getUserData(),
  212. copyIds:'',
  213. options: [{
  214. value: '-1',
  215. label: '全部'
  216. }, {
  217. value: '1',
  218. label: '已开启'
  219. }, {
  220. value: '0',
  221. label: '已禁用'
  222. }],
  223. status: '-1',
  224. //导入规则
  225. import_rules_show: false,
  226. save_loading: false,
  227. import_btn_show: false,
  228. fileList: [],
  229. file: null,
  230. action: process.env.VUE_APP_BASE_API + 'api/employee/enable_import',
  231. ATOKEN: { 'A-TOKEN': this.$getToken()},
  232. };
  233. },
  234. components: {
  235. noData
  236. },
  237. watch: {
  238. keywords: {
  239. deep: true,
  240. handler: _debounce(function(val) {
  241. this.page = 1;
  242. this.getEmployee();
  243. })
  244. },
  245. dept_id(val) {
  246. this.page = 1;
  247. this.getEmployee();
  248. },
  249. status(){
  250. this.page = 1;
  251. this.getEmployee();
  252. }
  253. },
  254. created() {
  255. this.getInfo();
  256. this.getEmployee();
  257. },
  258. mounted() {
  259. this.$nextTick(function() {
  260. if (localStorage.getItem('rule')) {
  261. this.tips_show = false;
  262. } else {
  263. this.tips_show = true;
  264. }
  265. });
  266. },
  267. methods: {
  268. handleSuccess(response) {
  269. if (response.code == 1) {
  270. if (response.data.length > 0) {
  271. var htmls = response.data;
  272. var str = "<div class='red'></div>";
  273. htmls.forEach(item => {
  274. str += `<div>${item.errors}</div>`;
  275. });
  276. this.close_import();
  277. this.$notify.error({
  278. title: '导入错误',
  279. dangerouslyUseHTMLString: true,
  280. message: str,
  281. duration: 0,
  282. offset: 50,
  283. customClass: 'notifyBox'
  284. });
  285. } else {
  286. this.file = response.data;
  287. this.$message.success({ message: response.msg });
  288. this.getEmployee();
  289. this.close_import();
  290. }
  291. }else{
  292. this.$message.error({ message: response.msg });
  293. }
  294. },
  295. handleRemove(file, fileList) {
  296. if (fileList !== null && fileList.length != 0) {
  297. this.import_btn_show = true;
  298. } else {
  299. this.import_btn_show = false;
  300. }
  301. },
  302. beforeFilesUpload(file) {
  303. const $ext_list = ['xlsx', 'xls'];
  304. let len = file.name.split('.').length - 1;
  305. const $ext_name = file.name.split('.')[len];
  306. if ($ext_list.indexOf($ext_name) != -1) {
  307. this.import_btn_show = true;
  308. } else {
  309. this.$message.warning('文件格式上传错误,仅支持上传xlsx,xls)');
  310. return false;
  311. }
  312. },
  313. //导出规则按钮
  314. derivedRule(){
  315. let status=this.status=='-1'? '':this.statu
  316. if(status){
  317. var str='&is_official='+status+'&dept_id='+this.dept_id+'&keywords='+this.keywords;
  318. }else{
  319. var str='&dept_id='+this.dept_id+'&keywords='+this.keywords;
  320. }
  321. let userData=this.$getUserData();
  322. window.open(process.env.VUE_APP_BASE_API+'/api/download/employee_status_export?employee_id='+userData.id+str)
  323. },
  324. // 导入相关
  325. close_import() {
  326. this.import_rules_show = false;
  327. this.import_btn_show = false;
  328. this.$refs.upload.clearFiles();
  329. },
  330. // 复制ID
  331. copyId(id) {
  332. this.$axios('get', '/api/employee/code', { employee_id: id })
  333. .then(res => {
  334. if (res.data.code == 1) {
  335. this.copyIds = res.data.data.encrypt_code;
  336. this.$nextTick(()=>{
  337. this.copyToClipboard();
  338. })
  339. }
  340. })
  341. },
  342. copyToClipboard() {
  343. var Url2=document.getElementById("biao");
  344. console.log(Url2)
  345. Url2.select(); // 选择对象
  346. document.execCommand("Copy"); // 执行浏览器复制命令
  347. this.$message.success('已复制');
  348. },
  349. forbidden() {
  350. if (this.selectIds.length == 0) {
  351. this.$message.error({ message: '请选择禁用的人员!' });
  352. return;
  353. }
  354. this.$confirm('确定禁用选择的人员?', '提示', {
  355. confirmButtonText: '确定',
  356. cancelButtonText: '取消',
  357. type: 'warning'
  358. }).then(() => {
  359. this.enable_loading = true;
  360. this.$axios('post', '/api/employee/disable', { employee_id: this.selectIds })
  361. .then(res => {
  362. if (res) {
  363. this.$message.success('已禁用');
  364. this.page=1;
  365. this.getEmployee();
  366. }
  367. })
  368. .finally(err => {
  369. this.enable_loading = false;
  370. });
  371. });
  372. },
  373. selectable(row) {
  374. if (row.is_creator) {
  375. return false;
  376. } else if (this.userInfo.id == row.id) {
  377. return false;
  378. } else {
  379. return true;
  380. }
  381. },
  382. setRanking() {
  383. this.rangLoad = true;
  384. let data = {
  385. employee_id: this.rankingtakePartInId,
  386. switch: Number(this.radio)
  387. };
  388. this.$axios('post', '/api/employee/ranking_switch', data)
  389. .then(res => {
  390. if (res.data.code == 1) {
  391. this.$message.success({ message: res.data.msg });
  392. this.getEmployee();
  393. }
  394. })
  395. .finally(() => {
  396. this.dialogVisible = false;
  397. setTimeout(() => {
  398. this.rangLoad = false;
  399. }, 200);
  400. });
  401. },
  402. rankingtakePartIn(id, is_ranking) {
  403. this.radio = is_ranking.toString();
  404. this.rankingtakePartInId = id;
  405. this.dialogVisible = true;
  406. },
  407. handleClose(done) {
  408. done();
  409. },
  410. //同步信息
  411. tb() {
  412. this.$confirm('下次同步时间需在10分钟之后,是否同步?', '提示', {
  413. confirmButtonText: '确定',
  414. cancelButtonText: '取消',
  415. type: 'warning'
  416. }).then(() => {
  417. this.tbLoading = true;
  418. this.$axios('post', '/api/ding/department_sync')
  419. .then(res => {
  420. this.$message.success({ message: '同步成功' });
  421. this.dept_id = 0;
  422. this.getInfo();
  423. this.page=1;
  424. this.getEmployee();
  425. })
  426. .finally(() => {
  427. this.tbLoading = false;
  428. });
  429. });
  430. },
  431. //搜索
  432. searchUser() {
  433. this.page = 1;
  434. this.getEmployee();
  435. },
  436. //是否开通
  437. changeIs(e, id) {
  438. var url = e == 1 ? '/api/employee/disable' : '/api/employee/enable';
  439. this.$axios('post', url, { employee_id: [id] }).then(res => {
  440. if (res) {
  441. if (e == 0) {
  442. this.$message.success({ message: '开启成功,可在"角色权限设置对应管理范围"' });
  443. } else {
  444. this.$message.success({ message: res.data.msg });
  445. }
  446. this.page=1;
  447. this.getEmployee();
  448. }
  449. });
  450. },
  451. //批量开通权限
  452. participation() {
  453. if (this.selectIds.length == 0) {
  454. this.$message.error({ message: '请选择参与的人员!' });
  455. return;
  456. }
  457. this.enable_loading = true;
  458. this.$axios('post', '/api/employee/enable', { employee_id: this.selectIds })
  459. .then(res => {
  460. if (res) {
  461. this.$message.success({ message: '开启成功,可在"角色权限设置对应管理范围"' });
  462. this.page=1;
  463. this.getEmployee();
  464. }
  465. })
  466. .finally(err => {
  467. this.enable_loading = false;
  468. });
  469. },
  470. //获取公司信息
  471. getInfo(is) {
  472. this.ruleDeprt = true;
  473. this.$axios('get', '/api/site/info').then(res => {
  474. this.info = res.data.data;
  475. this.getDepartment(is);
  476. });
  477. },
  478. //选择员工
  479. handleSelectionChange(e) {
  480. var arr = [];
  481. for (var item in e) {
  482. arr.push(e[item].id);
  483. }
  484. this.selectIds = arr;
  485. },
  486. //点击部门
  487. handleNodeClick(e) {
  488. this.page = 1;
  489. this.dept_id = e.id;
  490. },
  491. //获取部门
  492. getDepartment() {
  493. this.ruleDeprt = true;
  494. this.$axios('get', '/api/department/tree')
  495. .then(res => {
  496. var list = [
  497. {
  498. id: 0,
  499. name: this.info.name,
  500. _child: res.data.data.list
  501. }
  502. ];
  503. this.bmList = list;
  504. })
  505. .finally(() => {
  506. this.ruleDeprt = false;
  507. });
  508. },
  509. //获取员工
  510. getEmployee() {
  511. this.tableToading = true;
  512. let data={
  513. dept_id: this.dept_id,
  514. keywords: this.keywords,
  515. page: this.page,
  516. page_size:this.perPage,
  517. }
  518. let is_official=this.status=='-1'? '':this.status;
  519. if(is_official){
  520. data.is_official=is_official;
  521. }
  522. this.$axios('get', '/api/employee/index', data).then(res => {
  523. this.total = res.data.data.pageInfo.count;
  524. this.userList = res.data.data.list;
  525. var visible = localStorage.getItem('visible');
  526. if (!visible) {
  527. this.visible = true;
  528. }
  529. })
  530. .finally(err => {
  531. this.tableToading = false;
  532. });
  533. },
  534. visible_close() {
  535. localStorage.setItem('visible', 'true');
  536. this.visible = false;
  537. },
  538. //关闭提示
  539. tips_close() {
  540. localStorage.setItem('rule', 'true');
  541. this.tips_show = false;
  542. },
  543. handleSizeChange: function(val) {
  544. this.perPage = val;
  545. this.page = 1;
  546. this.getEmployee();
  547. },
  548. //页码变更
  549. handleCurrentChange: function(val) {
  550. this.page = val;
  551. this.getEmployee();
  552. }
  553. }
  554. };
  555. </script>
  556. <style lang="scss" scoped="scoped">
  557. .text-center {
  558. text-align: center;
  559. }
  560. .text-center p {
  561. padding: 10px 0;
  562. }
  563. .title {
  564. font-size: 16px;
  565. color: #909399;
  566. margin-bottom: 10px;
  567. }
  568. .popover {
  569. border: none;
  570. // color: #909399;
  571. font-weight: 600;
  572. cursor: pointer;
  573. }
  574. .popover:hover {
  575. background-color: #fff;
  576. border-color: #fff;
  577. }
  578. .switch {
  579. margin: 0;
  580. display: inline-block;
  581. position: relative;
  582. width: 40px;
  583. height: 20px;
  584. border: 1px solid #dcdfe6;
  585. outline: none;
  586. border-radius: 10px;
  587. box-sizing: border-box;
  588. background: #dcdfe6;
  589. cursor: pointer;
  590. transition: border-color 0.3s, background-color 0.3s;
  591. vertical-align: middle;
  592. }
  593. .switch:after {
  594. content: '';
  595. position: absolute;
  596. top: 1px;
  597. left: 1px;
  598. border-radius: 100%;
  599. transition: all 0.3s;
  600. width: 16px;
  601. height: 16px;
  602. background-color: #fff;
  603. }
  604. .switch-box .switch {
  605. border-color: #409eff;
  606. background-color: #409eff;
  607. }
  608. .switch-box .switch:after {
  609. left: 100%;
  610. margin-left: -17px;
  611. }
  612. .name {
  613. overflow: hidden;
  614. text-overflow: ellipsis;
  615. white-space: nowrap;
  616. width: 80%;
  617. }
  618. .bms div {
  619. margin-right: 10px;
  620. }
  621. .top-msg div:nth-child(1) {
  622. margin-bottom: 10px;
  623. }
  624. .company_name {
  625. position: relative;
  626. display: block;
  627. font-family: 'Microsoft YaHei';
  628. text-align: left;
  629. padding: 15px 25px;
  630. cursor: pointer;
  631. overflow: hidden;
  632. white-space: nowrap;
  633. text-overflow: ellipsis;
  634. border-bottom: 1px #f8f8f8 solid;
  635. }
  636. .company_name img {
  637. position: relative;
  638. display: inline-block;
  639. top: 2px;
  640. width: 18px;
  641. height: 18px;
  642. margin-right: 4px;
  643. }
  644. .terr-right {
  645. .custom-tree-node {
  646. margin-left: -4px;
  647. }
  648. .custom-tree-node * {
  649. vertical-align: middle;
  650. }
  651. .custom-tree-node:hover {
  652. .treeIcon {
  653. display: inline-block;
  654. width: 55%;
  655. }
  656. }
  657. }
  658. .el-popover2 {
  659. color: #409eff;
  660. }
  661. .rule_class_box {
  662. ::v-deep .el-tree-node {
  663. border-bottom: 1px #f8f8f8 solid;
  664. }
  665. ::v-deep .el-tree-node__content {
  666. padding: 10px 0;
  667. // border-bottom: 1px #f8f8f8 solid;
  668. }
  669. ::v-deep .el-tree-node__content:hover {
  670. background: #ecf5ff;
  671. border-radius: 4px;
  672. }
  673. ::v-deep .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content .name {
  674. color: #409eff !important;
  675. font-weight: normal;
  676. transition: 0.35s ease-in-out;
  677. }
  678. // ::v-deep .is-current .el-tree-node__content .el-icon-caret-right {
  679. // color: #409eff !important;
  680. // }
  681. // ::v-deep .is-current .el-tree-node__content .el-tree-node__label {
  682. // color: #409eff !important;
  683. // }
  684. // ::v-deep .is-current .el-tree-node__children .el-icon-caret-right {
  685. // color: #c0c4cc !important;
  686. // }
  687. // ::v-deep .is-current .el-tree-node__children .el-tree-node__label {
  688. // color: #606266 !important;
  689. // }
  690. // ::v-deep .is-current .name {
  691. // color: #409eff !important;
  692. // font-weight: normal;
  693. // transition: 0.35s ease-in-out;
  694. // }
  695. }
  696. .participateRank {
  697. cursor: pointer;
  698. text-decoration: underline;
  699. }
  700. </style>