persona.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. <template>
  2. <div>
  3. <div class="title">程序员用户画像</div>
  4. <div>
  5. <div>
  6. <span class="sub-title">活跃度:</span>
  7. <span class="i-content">
  8. <span v-if="active">活跃用户</span>
  9. <span v-if="lost">流失用户</span>
  10. <span v-if="nonActive">不活跃用户</span>
  11. <span v-if="back">回流用户</span>
  12. <span v-if="loyal">忠实用户</span>
  13. </span>
  14. </div>
  15. <div>
  16. <span class="sub-title">活跃时间段(最近7天):</span>
  17. <span class="i-content">
  18. <span v-if="active">{{activePeriod}}</span>
  19. </span>
  20. </div>
  21. <div>
  22. <span class="sub-title">常用设备(最近7天):</span>
  23. <span class="i-content">
  24. <span>手机({{equipment.computer}}次),电脑({{equipment.mobile}}次)</span>
  25. </span>
  26. </div>
  27. <div>
  28. <span class="sub-title">收入情况:</span>
  29. <span class="i-content income">
  30. <span>整包{{incomeCount.package/100}}元</span>
  31. <span>云端{{incomeCount.cloud/100}}元</span>
  32. <span>雇佣{{incomeCount.hire/100}}元</span>
  33. <span class="clickable" @click="goUserBill()">查看详细记录>></span>
  34. </span>
  35. </div>
  36. </div>
  37. <div class="title">基本信息及身份特征</div>
  38. <div class="content">
  39. <div class="dev-main clear">
  40. <div class="dev-left">
  41. <div class="grid-content">
  42. <img
  43. class="dev-head point"
  44. @click="clickUserID(userInfo.uid)"
  45. :src="userInfo.icon_url"
  46. alt
  47. />
  48. <p class="blackc">{{userInfo.uid}}</p>
  49. <p class="lblack font13">¥{{userInfo.work_price}}</p>
  50. <p v-if="userInfo.realname_re=='2'">
  51. <span class="state-of">已签约</span>
  52. </p>
  53. </div>
  54. </div>
  55. <div class="dev-center">
  56. <div class="grid-content">
  57. <div class="clear">
  58. <div class="floatl">
  59. <span class="lblue point blod" @click="clickUserID(userInfo.uid)">{{userInfo.nickname}}</span>
  60. <span v-if="userInfo.realname" class="lblack font13">({{userInfo.realname}})</span>
  61. <span class="blod">{{userInfo.occupation_name}}</span>
  62. <span v-if="userInfo.direction_name">/{{userInfo.direction_name}}</span>
  63. </div>
  64. <div class="floatr dev-mark clear">
  65. <span v-if="userInfo.in_black_list==1" class="dev-dark">{{'黑名单'}}</span>
  66. <span v-if="userInfo.city_op_name">{{userInfo.city_op_name}}</span>
  67. <span v-if="userInfo.industry_name">{{userInfo.industry_name}}</span>
  68. <span v-if="userInfo.work_year_name">{{userInfo.work_year_name}}</span>
  69. <span>{{userInfo.on_project==0&&userInfo.on_job==0&&userInfo.on_hire==0 ?'空闲':'工作中'}}</span>
  70. </div>
  71. </div>
  72. <div class="dev-infor">
  73. <p>
  74. <span class="blod black">技能:</span>
  75. <span>{{userInfo.skill_description}}</span>
  76. </p>
  77. <p>
  78. <span class="blod black">项目:</span>
  79. <span v-for="(itms,ind) in userInfo.works" :key="itms.uid">
  80. {{itms.name}}
  81. <span v-if="ind!=userInfo.works.length-1">,</span>
  82. </span>
  83. </p>
  84. <p>
  85. <span class="blod black">公司:</span>
  86. <span>{{userInfo.company}}</span>
  87. <span>{{userInfo.title}}</span>
  88. </p>
  89. <p style="padding-top:22px;">
  90. <span class="blod black">认证:</span>
  91. <span v-for="(itms,ind) in userInfo.certTags" :key="itms.uid">
  92. {{itms.tag_name}}
  93. <span v-if="ind!=userInfo.certTags.length-1">,</span>
  94. </span>
  95. </p>
  96. </div>
  97. </div>
  98. </div>
  99. <div class="dev-right">
  100. <div class="grid-content">
  101. <div class="dev-detail">
  102. <p>
  103. <span class="blod black">意愿:</span>
  104. <span>{{userInfo.willing}}</span>
  105. </p>
  106. <p>
  107. <span class="blod black">接单:</span>
  108. <span v-if="userInfo.work_status==1">
  109. <span v-if="userInfo.work_option==0 ">接受所有派单及预约机会</span>
  110. <span v-if="userInfo.work_option==3">只接受平台派单和认证企业预约</span>
  111. <span v-if="userInfo.work_option==1">只接受平台派单</span>
  112. </span>
  113. <span v-else>
  114. <span>不接单</span>
  115. </span>
  116. </p>
  117. <p>
  118. <span class="blod black">数量:</span>
  119. <span v-if="userInfo.doing_project_num">项目:{{userInfo.doing_project_num}},</span>
  120. <span v-if="userInfo.doing_job_num">云端:{{userInfo.doing_job_num}},</span>
  121. <span v-if="userInfo.doing_hire_num">雇佣:{{userInfo.doing_hire_num}},</span>
  122. </p>
  123. <p>
  124. <span class="blod black">权重:</span>
  125. <span>{{userInfo.appoint_weight}}</span>
  126. </p>
  127. <p style="padding-top:22px;">
  128. <span class="blod black">评价:</span>
  129. <el-rate
  130. disabled
  131. class="inlineb"
  132. style=" vertical-align: top;"
  133. v-model="userInfo.rating"
  134. :colors="['#99A9BF', '#F7BA2A', '#FF9900']"
  135. ></el-rate>
  136. <span v-if="userInfo.rating_count" class="lblack">({{userInfo.rating_count}})</span>
  137. </p>
  138. </div>
  139. </div>
  140. </div>
  141. </div>
  142. </div>
  143. <div class="title">企业用户行为特征</div>
  144. <el-tabs v-model="activeName" @tab-click="handleClick">
  145. <el-tab-pane label="登录(7天内)" name="login">
  146. <el-table border style="width: 100%" :data="loginData">
  147. <el-table-column prop="loginTypeName" label="登录方式"></el-table-column>
  148. <el-table-column prop="client_type" label="登录名称">
  149. <template slot-scope="scope">
  150. <span v-if="scope.row.client_type == 'android' || scope.row.client_type == 'ios'">手机</span>
  151. <span v-else>电脑</span>
  152. </template>
  153. </el-table-column>
  154. <el-table-column prop="loginTimeFormat" label="登录时间"></el-table-column>
  155. <el-table-column prop="client_type" label="登录环境">
  156. <template slot-scope="scope">{{scope.row.client_type}} {{scope.row.version}}</template>
  157. </el-table-column>
  158. </el-table>
  159. </el-tab-pane>
  160. <el-tab-pane label="搜索记录" name="search">
  161. <el-table border style="width: 100%" :data="searchData">
  162. <el-table-column prop="keyword" label="关键词"></el-table-column>
  163. <el-table-column prop="created_at" label="操作时间">
  164. <template slot-scope="scope">
  165. <span>{{formatDate(scope.row.created_at,'Y-m-d H:i')}}</span>
  166. </template>
  167. </el-table-column>
  168. <el-table-column prop="app_type" label="操作设备"></el-table-column>
  169. </el-table>
  170. </el-tab-pane>
  171. <el-tab-pane label="聊天(7天内)" name="liaotian">
  172. <el-table border style="width: 100%" :data="liaotianData">
  173. <el-table-column prop="demander_uid" label="发起者">
  174. <template slot-scope="scope">
  175. <span class="lblue point blod" @click="clickUserID(scope.row.demander_uid)">{{scope.row.demander_uid}}</span>
  176. </template>
  177. </el-table-column>
  178. <el-table-column prop="developer_uid" label="被发起者">
  179. <template slot-scope="scope">
  180. <span class="lblue point blod" @click="clickUserID(scope.row.developer_uid)">{{scope.row.developer_uid}}</span>
  181. </template>
  182. </el-table-column>
  183. <el-table-column prop="create_time" label="发起时间">
  184. <template slot-scope="scope">
  185. <span>{{formatDate(scope.row.create_time,'Y-m-d H:i')}}</span>
  186. </template>
  187. </el-table-column>
  188. <el-table-column prop="chat_total_time" label="聊天时长"></el-table-column>
  189. </el-table>
  190. </el-tab-pane>
  191. <el-tab-pane label="认证记录" name="renzheng">
  192. <el-table border style="width: 100%" :data="renzhengData">
  193. <el-table-column prop="name" label="项目名称"></el-table-column>
  194. <el-table-column prop="cert_status_name" label="认证状态"></el-table-column>
  195. <!-- <el-table-column prop="check_failed_times" label="当前认证失败次数"></el-table-column>-->
  196. <el-table-column prop="certified_times" label="认证通过次数"></el-table-column>
  197. <el-table-column prop="uid" label="操作">
  198. <template slot-scope="scope">
  199. <el-button type="text" @click="clickCheckCert(scope.row)">查看详情>></el-button>
  200. </template>
  201. </el-table-column>
  202. </el-table>
  203. </el-tab-pane>
  204. <el-tab-pane label="ping单记录" name="ping">
  205. <el-table border style="width: 100%" :data="pingData">
  206. <el-table-column prop="create_time" label="操作时间">
  207. <template slot-scope="scope">
  208. <span>{{formatDate(scope.row.create_time)}}</span>
  209. </template>
  210. </el-table-column>
  211. <el-table-column prop="client_type" label="操作设备">
  212. <template slot-scope="scope">{{scope.row.client_type}} {{scope.row.version}}</template>
  213. </el-table-column>
  214. </el-table>
  215. </el-tab-pane>
  216. <el-tab-pane label="其它行为操作记录" name="other">
  217. <el-table border style="width: 100%" :data="otherData">
  218. <el-table-column prop="name" label="行为名称"></el-table-column>
  219. <el-table-column prop="create_time" label="发生时间">
  220. <template slot-scope="scope">
  221. <span>{{formatDate(scope.row.create_time,'Y-m-d H:i')}}</span>
  222. </template>
  223. </el-table-column>
  224. <el-table-column prop="client_type" label="操作设备">
  225. <template slot-scope="scope">{{scope.row.client_type}} {{scope.row.version}}</template>
  226. </el-table-column>
  227. </el-table>
  228. </el-tab-pane>
  229. </el-tabs>
  230. <div style="margin-top: 20px">
  231. <el-pagination
  232. background
  233. @current-change="changePagination"
  234. :current-page.sync="page"
  235. :page-size="pageSize"
  236. layout="total, prev, pager, next, jumper"
  237. :total="total"
  238. ></el-pagination>
  239. </div>
  240. </div>
  241. </template>
  242. <script>
  243. export default {
  244. data() {
  245. return {
  246. userInfo: {},
  247. active: false,
  248. back: false,
  249. nonActive: false,
  250. loyal: false,
  251. lost: false,
  252. activePeriod: '',
  253. equipment: {
  254. computer: 0,
  255. mobile: 0
  256. },
  257. incomeCount: {
  258. package: 0, //整包
  259. cloud: 0, //云端
  260. hire: 0, //雇佣
  261. },
  262. income: null,
  263. certs: [],
  264. total: 0,
  265. pageSize: 20,
  266. page: 1,
  267. uid: this.$route.query.uid,
  268. realNameAuditTimes: 0,
  269. signAuditTimes: 0,
  270. activeName: 'login',
  271. loginData: [], //登录数据
  272. searchData: [], //搜索记录数据
  273. liaotianData: [], //聊天数据
  274. renzhengData: [], //认证数据
  275. pingData: [], //ping数据
  276. otherData: [], //其他操作数据
  277. };
  278. },
  279. created() {
  280. this.loadPersona();
  281. this.loadCerts();
  282. this.loadLoginLog();
  283. },
  284. methods: {
  285. formatDate(time,format = '') {
  286. if (time === "0") {
  287. return "--";
  288. }
  289. let now = new Date(time * 1000);
  290. let year = now.getFullYear();
  291. let month = now.getMonth() + 1;
  292. let date = now.getDate();
  293. let hour = now.getHours();
  294. let minute = now.getMinutes();
  295. let second = now.getSeconds();
  296. if (hour < 10) {
  297. hour = "0" + hour;
  298. }
  299. if (minute < 10) {
  300. minute = "0" + minute;
  301. }
  302. if (second < 10) {
  303. second = "0" + second;
  304. }
  305. return (format == ''?
  306. year +
  307. "-" +
  308. month +
  309. "-" +
  310. date +
  311. " " +
  312. hour +
  313. ":" +
  314. minute +
  315. ":" +
  316. second
  317. :
  318. year +
  319. "-" +
  320. month +
  321. "-" +
  322. date +
  323. " " +
  324. hour +
  325. ":" +
  326. minute
  327. );
  328. },
  329. async loadPersona() {
  330. let res = await this.$post("/api/admin/user/persona", {uid: this.uid});
  331. this.userInfo = res.data.userInfo;
  332. this.active = res.data.active;
  333. (this.nonActive = res.data.nonActive), (this.loyal = res.data.loyal);
  334. this.back = res.data.return;
  335. this.lost = res.data.lost;
  336. this.incomeCount = res.data.incomeCount;
  337. this.income = res.data.income;
  338. this.realNameAuditTimes = res.data.realNameAuditTimes;
  339. this.signAuditTimes = res.data.signAuditTimes;
  340. this.activePeriod = res.data.activePeriod;
  341. this.equipment = res.data.equipment;
  342. },
  343. async loadCerts() {
  344. let res = await this.$post("/api/admin/cert/getUserList", {
  345. uid: this.uid,
  346. page: 1,
  347. page_size: 100
  348. });
  349. this.certs = res.data.list;
  350. },
  351. async loadLoginLog() {
  352. let res;
  353. switch (this.activeName) {
  354. case "login":
  355. res = await this.$post("/api/admin/user/lastSevenDaysLoginLog", {
  356. uid: this.uid,
  357. page: this.page
  358. });
  359. this.loginData = res.data.list;
  360. this.pageData(res);
  361. break;
  362. case 'search':
  363. res = await this.$post("/api/admin/user/searchLog", {
  364. uid: this.uid,
  365. page: this.page
  366. });
  367. this.searchData = res.data.list;
  368. this.pageData(res);
  369. break;
  370. case 'liaotian':
  371. res = await this.$post("/api/admin/user/chatLog", {
  372. uid: this.uid,
  373. page: this.page
  374. });
  375. this.liaotianData = res.data.list;
  376. this.pageData(res);
  377. break;
  378. case 'renzheng':
  379. let res = await this.$post("/api/admin/cert/getUserList", {
  380. uid: this.uid,
  381. page: this.page,
  382. // page_size: 100
  383. });
  384. this.renzhengData = res.data.list;
  385. this.pageData(res);
  386. break;
  387. case 'ping':
  388. res = await this.$post("/api/admin/user/pingLog", {
  389. uid: this.uid,
  390. page: this.page
  391. });
  392. this.pingData = res.data.list;
  393. this.pageData(res);
  394. break;
  395. case 'other':
  396. res = await this.$post("/api/admin/user/behaviorLog", {
  397. uid: this.uid,
  398. page: this.page
  399. });
  400. this.otherData = res.data.list;
  401. this.pageData(res);
  402. break;
  403. }
  404. },
  405. pageData(res){
  406. this.pageSize = res.data.pageSize * 1;
  407. this.total = res.data.total * 1;
  408. },
  409. goUserBill() {
  410. window.location.href = "/main/user_bills?user=" + this.uid;
  411. },
  412. clickCheckCert(item) {
  413. window.open(
  414. this.$store.state.domainConfig.rooterUrl +
  415. `/main/dev_check_detail?uid=${item.uid}&cert_id=${item.cert_id}`
  416. );
  417. },
  418. goSignVerify(item) {
  419. window.open(
  420. this.$store.state.domainConfig.siteUrl +
  421. `/rooter/outsourcecoderitem?uid=${this.uid}`
  422. );
  423. },
  424. goRealNameVerify(item) {
  425. window.open(
  426. this.$store.state.domainConfig.siteUrl +
  427. `/rooter/realnameVerifyAuditItem?uid=${this.uid}`
  428. );
  429. },
  430. clickUserID(uid) {
  431. console.log(uid);
  432. window.open(
  433. this.$store.state.domainConfig.siteUrl + `/rooter/user/${uid}`
  434. );
  435. },
  436. // 页码变动
  437. changePagination(page) {
  438. this.page = page;
  439. this.loadLoginLog();
  440. },
  441. handleClick(tab, event) {
  442. this.clearData();
  443. this.loadLoginLog();
  444. },
  445. clearData() {
  446. this.page = 1;
  447. this.total = 0;
  448. }
  449. }
  450. };
  451. </script>
  452. <style lang="scss">
  453. .title {
  454. font-size: 18px;
  455. font-weight: 700;
  456. line-height: 64px;
  457. }
  458. .sub-title {
  459. font-size: 14px;
  460. font-weight: 700;
  461. line-height: 48px;
  462. padding-left: 32px;
  463. }
  464. .content {
  465. padding-left: 32px;
  466. font-size: 12px;
  467. }
  468. .i-head-content div{
  469. height: 22px;
  470. }
  471. .i-content{
  472. font-size: 12px;
  473. }
  474. .dev-main {
  475. margin: 0 auto;
  476. padding: 37px 9px 20px 23px;
  477. background: white;
  478. width: 1000px;
  479. margin-bottom: 10px;
  480. box-sizing: border-box;
  481. }
  482. .dev-main > div {
  483. float: left;
  484. }
  485. .dev-left {
  486. width: 112px;
  487. text-align: center;
  488. }
  489. .state-of {
  490. display: inline-block;
  491. background: rgba(243, 243, 243, 1);
  492. font-size: 14px;
  493. color: #888888;
  494. padding: 3px 11px;
  495. }
  496. .dev-left p {
  497. padding: 3px 0;
  498. }
  499. .dev-center {
  500. width: 594px;
  501. }
  502. .dev-right {
  503. width: 260px;
  504. }
  505. .dev-detail {
  506. border-left: 1px solid #e0e0e0;
  507. padding: 3px 0 3px 19px;
  508. }
  509. .dev-detail > p {
  510. padding-top: 3px;
  511. padding-right: 10px;
  512. font-size: 13px;
  513. color: #505050;
  514. box-sizing: border-box;
  515. overflow: hidden;
  516. text-overflow: ellipsis;
  517. white-space: nowrap;
  518. }
  519. .dev-head {
  520. width: 74px;
  521. border-radius: 50%;
  522. overflow: hidden;
  523. }
  524. .dev-mark {
  525. margin-right: 22px;
  526. }
  527. .dev-mark > span {
  528. float: left;
  529. padding: 2px 9px;
  530. color: #888888;
  531. font-size: 14px;
  532. border: 1px solid #c0c0c0;
  533. border-radius: 2px;
  534. margin-right: 7px;
  535. height: 23px;
  536. line-height: 18px;
  537. }
  538. .dev-mark .dev-dark {
  539. float: left;
  540. padding: 2px 9px;
  541. color: white;
  542. font-size: 14px;
  543. background: #999999;
  544. border: 1px solid #999999;
  545. border-radius: 2px;
  546. margin-right: 7px;
  547. }
  548. .dev-infor {
  549. padding-top: 2px;
  550. }
  551. .dev-infor > p {
  552. padding-top: 3px;
  553. padding-right: 10px;
  554. font-size: 13px;
  555. color: #505050;
  556. box-sizing: border-box;
  557. overflow: hidden;
  558. text-overflow: ellipsis;
  559. white-space: nowrap;
  560. }
  561. .clear::after {
  562. display: block;
  563. clear: both;
  564. content: "";
  565. }
  566. .inlineb {
  567. display: inline-block;
  568. }
  569. .floatl {
  570. float: left;
  571. }
  572. .floatr {
  573. float: right;
  574. }
  575. .income span {
  576. margin-left: 20px;
  577. }
  578. </style>