salesfunnel.vue 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. // 各模块文件存储占比
  2. <template>
  3. <div class="container normal-panel">
  4. <div class="inline-16" style="margin-top:0px;margin-bottom: 20px">
  5. <label class="search__label" >部门:</label>
  6. <el-cascader ref="selectdep" size="small" v-model="depment" :options="deplist" :props="{emitPath:true,expandTrigger:'hover',checkStrictly:true,label:'label',value:'departmentid',children:'children'}" @change="selectDep" clearable></el-cascader>
  7. </div>
  8. <div class="inline-16">
  9. <label class="search__label" >业务员:</label>
  10. <el-select v-model="person" filterable placeholder="请选择" size="small" clearable @change="selectPerson">
  11. <el-option
  12. v-for="item in personnelList"
  13. :key="item.index"
  14. :label="item.name"
  15. :value="item.userid">
  16. </el-option>
  17. </el-select>
  18. </div>
  19. <div class="inline-16">
  20. <p class="search__label">状态:</p>
  21. <el-select v-model="isleave" clearable style="margin-right:10px" size="small" placeholder="请选择状态" @change="leaveChange" :disabled="depment == ''">
  22. <el-option label="在职" value="1"></el-option>
  23. <el-option label="离职" value="2"></el-option>
  24. </el-select>
  25. </div>
  26. <div class="inline-16">
  27. <p class="search__label">领域:</p>
  28. <el-select v-model="tradefield" clearable style="margin-right:10px" size="small" placeholder="请选择领域" @change="dataParam.content.where.tradefield = tradefield;projectParam.content.where.tradefield = tradefield;getProportionOfFileModel()">
  29. <el-option v-for="item in tradefields" :label="item.value" :key="item.rowindex" :value="item.value">
  30. </el-option>
  31. </el-select>
  32. </div>
  33. <div class="inline-16">
  34. <el-checkbox v-model="unfinish" true-label="0" false-label="1" @change="dataParam.content.where.unfinish = unfinish;projectParam.content.where.unfinish = unfinish;getProportionOfFileModel()">包含失败、结案项目</el-checkbox>
  35. </div>
  36. <div class="inline-16" style="margin-top:0px;margin-bottom: 20px">
  37. <el-button-group>
  38. <el-button size="small" :type="dataParam.content.dateType==1?'primary':''" @click="dataChange(1)" >近一年</el-button>
  39. <el-button size="small" :type="dataParam.content.dateType==2?'primary':''" @click="dataChange(2)">近九个月</el-button>
  40. <el-button size="small" :type="dataParam.content.dateType==3?'primary':''" @click="dataChange(3)">近六个月</el-button>
  41. <el-button size="small" :type="dataParam.content.dateType==4?'primary':''" @click="dataChange(4)">近三个月</el-button>
  42. </el-button-group>
  43. </div>
  44. <div class="inline-16" style="margin-top:0px;margin-bottom: 20px">
  45. <el-date-picker
  46. size="small"
  47. v-model="dateSelect"
  48. @change="dateChange"
  49. type="daterange"
  50. :clearable="false"
  51. format="yyyy-MM-dd"
  52. value-format="yyyy-MM-dd"
  53. range-separator="至"
  54. start-placeholder="开始日期"
  55. end-placeholder="结束日期">
  56. </el-date-picker>
  57. </div>
  58. <div>
  59. <el-row>
  60. <el-col :xs="15" :sm="15" :md="15" :lg="15" :xl="14">
  61. <p class="title">销售漏斗图</p>
  62. <div class="re-panel">
  63. <div id="containerFunnel" style="height: calc(60vh)"></div>
  64. </div>
  65. </el-col>
  66. <el-col :offset="1" :xs="8" :sm="8" :md="8" :lg="8" :xl="9">
  67. <div>
  68. <p class="title">表格数据</p>
  69. <el-table
  70. :data="tableData"
  71. style="width: 100%"
  72. size="small"
  73. :header-cell-style="{height:'60px',fontWeight:'400',fontSize:'22px',color:'#333333',background:'#ddebf7'}"
  74. :cell-style="{height:'40px',fontWeight:'400',fontSize:'18px'}"
  75. border>
  76. <el-table-column
  77. prop="stagename"
  78. label="阶段"
  79. width="150">
  80. </el-table-column>
  81. <el-table-column
  82. prop="projectqty"
  83. label="项目数"
  84. width="100">
  85. </el-table-column>
  86. <el-table-column
  87. prop="signamount_due"
  88. label="预计签约金额(万元)">
  89. </el-table-column>
  90. <el-table-column
  91. prop="dealamount"
  92. label="项目成交金额(万元)">
  93. </el-table-column>
  94. </el-table>
  95. </div>
  96. </el-col>
  97. <!-- <el-col :span="24" style="margin-top: 20px">
  98. <p class="title">{{projectTile}}</p>
  99. <tableTemp :layout="tablecols" :data="projectList" :opwidth="200" :custom="true" :height="tableHieght">
  100. <template v-slot:customcol="scope">
  101. <p>{{scope.column.data[scope.column.columnname]?scope.column.data[scope.column.columnname]:'&#45;&#45;'}}</p>
  102. </template>
  103. </tableTemp>
  104. <div class="container normal-panel" style="text-align:right">
  105. <el-pagination
  106. background
  107. @size-change="handleSizeChange"
  108. @current-change="handleCurrentChange"
  109. :current-page="projectParam.content.pageNumber"
  110. :page-sizes="[10, 10, 50, 100]"
  111. :page-size="10"
  112. layout="total,sizes, prev, pager, next, jumper"
  113. :total="total">
  114. </el-pagination>
  115. </div>
  116. </el-col>-->
  117. </el-row>
  118. </div>
  119. <div>
  120. <p class="title">{{projectTile}}</p>
  121. <tableTemp :layout="tablecols" :data="projectList" :opwidth="200" :custom="true" :height="tableHieght">
  122. <template v-slot:customcol="scope">
  123. <div v-if="scope.column.columnname === 'status'">
  124. <span style="color:#52c41a" v-if="scope.column.data[[scope.column.columnname]] == '跟进中'">{{scope.column.data[[scope.column.columnname]]}}</span>
  125. <span style="color:#fa8c16" v-else-if="scope.column.data[[scope.column.columnname]] == '已成交'">{{scope.column.data[[scope.column.columnname]]}}</span>
  126. <span style="color:#999999" v-else-if="scope.column.data[[scope.column.columnname]] == '已失败'">{{scope.column.data[[scope.column.columnname]]}}</span>
  127. <span style="color:#999999" v-else-if="scope.column.data[[scope.column.columnname]] == '已结案'">{{scope.column.data[[scope.column.columnname]]}}</span>
  128. </div>
  129. <div v-else-if="scope.column.columnname === 'tag_sys'">
  130. <div v-for="item in scope.column.data.tag_sys" :key="item.index" style="float: left;margin-left: 5px;margin-bottom: 5px">
  131. <el-tag color="#3874F6" size="mini" type="primary" effect="dark">
  132. <span>{{item}}</span>
  133. </el-tag>
  134. </div>
  135. <div v-for="item in scope.column.data.tag" :key="item.index" style="float: left;margin-left: 5px;margin-bottom: 5px">
  136. <el-tag color="#FA8C16" size="mini" type="warning" effect="dark">
  137. <span>{{item}}</span>
  138. </el-tag>
  139. </div>
  140. </div>
  141. <div v-else-if="scope.column.columnname === 'leader'">
  142. {{scope.data.column.leader[0] && scope.data.column.data.leader[0].name}}
  143. </div>
  144. <div v-else-if="scope.column.columnname === 'projecttype'">
  145. {{scope.column.data.projecttype + '-' + scope.column.data.projecttype_remarks}}
  146. </div>
  147. <div v-else-if="scope.column.columnname == 'totalinvestment'">
  148. <span>{{scope.column.data[[scope.column.columnname]] ?tool.formatAmount(scope.column.data[[scope.column.columnname]],2):'--'}}</span>
  149. </div>
  150. <div v-else-if="scope.column.columnname == 'costofconstruction'">
  151. <span>{{scope.column.data[[scope.column.columnname]] ?tool.formatAmount(scope.column.data[[scope.column.columnname]],2):'--'}}</span>
  152. </div>
  153. <div v-else-if="scope.column.columnname == 'budgetary'">
  154. <span>{{scope.column.data[[scope.column.columnname]] ?tool.formatAmount(scope.column.data[[scope.column.columnname]],2):'--'}}</span>
  155. </div>
  156. <div v-else-if="scope.column.columnname == 'signamount_due'">
  157. <span>{{scope.column.data[[scope.column.columnname]] ?tool.formatAmount(scope.column.data[[scope.column.columnname]],2):'--'}}</span>
  158. </div>
  159. <div v-else-if="scope.column.columnname == 'dealamount'">
  160. <span>{{scope.column.data[[scope.column.columnname]] ?tool.formatAmount(scope.column.data[[scope.column.columnname]],2):'--'}}</span>
  161. </div>
  162. <div v-else-if="scope.column.columnname == 'begdate_due'">
  163. <span>{{scope.column.data[[scope.column.columnname]] ? scope.column.data[[scope.column.columnname]] !== 'NaN-NaN'?scope.column.data[[scope.column.columnname]]:'--' :'--'}}</span>
  164. </div>
  165. <div v-else-if="scope.column.columnname == 'enddate_due'">
  166. <span>{{scope.column.data[[scope.column.columnname]] ? scope.column.data[[scope.column.columnname]] !== 'NaN-NaN'?scope.column.data[[scope.column.columnname]]:'--' :'--'}}</span>
  167. </div>
  168. <div v-else-if="scope.column.columnname == 'scale'">
  169. <span>{{scope.column.data[[scope.column.columnname]]?scope.column.data[[scope.column.columnname]] + scope.column.data.unitname:'--'}}</span>
  170. </div>
  171. <div v-else>
  172. {{scope.column.data[[scope.column.columnname]]?scope.column.data[[scope.column.columnname]]:'--'}}
  173. </div>
  174. </template>
  175. </tableTemp>
  176. <div style="text-align:right;margin-top: 10px">
  177. <el-pagination
  178. background
  179. @size-change="handleSizeChange"
  180. @current-change="handleCurrentChange"
  181. :current-page="projectParam.content.pageNumber"
  182. :page-sizes="[20,50,100,150]"
  183. :page-size="20"
  184. layout="total,sizes, prev, pager, next, jumper"
  185. :total="total">
  186. </el-pagination>
  187. </div>
  188. </div>
  189. </div>
  190. </template>
  191. <script>
  192. import tableTemp from '@/components/table/index8'
  193. import { Funnel,G2 } from '@antv/g2plot';
  194. const G = G2.getEngine('canvas');
  195. export default {
  196. components:{tableTemp},
  197. data () {
  198. return {
  199. chartPie:null,
  200. flagIndex:'',
  201. /*tableHieght:'calc(100vh)',*/
  202. tableHieght:'857px',
  203. tableData:[],
  204. person:'',
  205. depment:'',
  206. dateType:"",
  207. projectTile:"",
  208. fullscreenLoading:false,
  209. total:0,
  210. sa_projstagemagid:'',
  211. data:[{ stagename: '简历筛选', sequence1: 253 },],
  212. activeName: '部门',
  213. dataid:'',
  214. range:'',
  215. pointValue:'',
  216. isDep:false,
  217. isPerson:false,
  218. visible:false,
  219. deplist:[],
  220. personnelList:[],
  221. projectList:[],
  222. tablecols:[],
  223. depmentParam:{
  224. "id": 20230620102004,
  225. "content": {
  226. "isleave":''
  227. }
  228. },
  229. dataParam:{
  230. "id": 20230630151504,
  231. "content": {
  232. "type":0, // 0 按人搜素 1 按部门搜索
  233. "dataid":0, // 人员id或部门id
  234. 'dateType':1,
  235. "where": {
  236. "begindate": "",
  237. "begdate":"",
  238. "enddate":"",
  239. "departmentid":"",
  240. "tradefield":"",
  241. "isleave":"0",
  242. "unfinish":'1'
  243. }
  244. }
  245. },
  246. projectParam:{
  247. "id": 20230719085004,
  248. "content": {
  249. "pageNumber": 1,
  250. "pageSize": 20,
  251. "type": '',
  252. "dataid": '',
  253. "dateType": 1,
  254. "sa_projstagemagid":'',
  255. "where": {
  256. "begdate":"",
  257. "enddate":"",
  258. "tradefield":"",
  259. "isleave":"0",
  260. "unfinish":'1'
  261. }
  262. }
  263. },
  264. dateSelect:[],
  265. tradefield:'',
  266. isleave:'',
  267. tradefields:[],
  268. unfinish:'1'
  269. }
  270. },
  271. methods:{
  272. async departmentrtment() {
  273. const res = await this.$api.requested(this.depmentParam)
  274. this.deplist = this.createMenu(res.data.dep)
  275. this.personnelList = res.data.hr
  276. this.person = JSON.parse(window.sessionStorage.getItem('active_account')).name
  277. this.getProportion()
  278. },
  279. async getProportion () {
  280. const res = await this.$api.requested(this.dataParam)
  281. this.tableData = res.data
  282. sessionStorage.setItem('flagIndex',res.data.length)
  283. this.renderPie()
  284. },
  285. async personData(){
  286. const res = await this.$api.requested(this.depmentParam)
  287. this.personnelList = res.data.hr
  288. },
  289. leaveChange(){
  290. if (this.isleave){
  291. this.dataParam.content.where.isleave = this.isleave
  292. this.projectParam.content.where.isleave = this.isleave
  293. this.depmentParam.content.isleave = this.isleave
  294. this.personData()
  295. this.getProportionOfFileModel()
  296. }else {
  297. this.dataParam.content.where.isleave = 0
  298. this.projectParam.content.where.isleave = 0
  299. this.depmentParam.content.isleave = 0
  300. this.personData()
  301. this.getProportionOfFileModel()
  302. }
  303. },
  304. createMenu (array) {
  305. var that = this
  306. let arr = []
  307. function convertToElementTree(node) {
  308. // 新节点
  309. if (node.subdep.length === 0){
  310. var elNode = {
  311. label: node["depname"],
  312. parentid:node['parentid'],
  313. parentname:node['parentname'],
  314. departmentid:node["departmentid"],
  315. value:node["departmentid"],
  316. remarks:node["remarks"],
  317. isused:node["isused"],
  318. changedate:node['changedate'],
  319. changeby:node['changeby'],
  320. createdate:node['createdate'],
  321. createby:node['createby'],
  322. depno:node['depno'],
  323. disabled:that.pageOnlyRead,
  324. }
  325. }else {
  326. var elNode = {
  327. label: node["depname"],
  328. parentid:node['parentid'],
  329. parentname:node['parentname'],
  330. departmentid:node["departmentid"],
  331. value:node["departmentid"],
  332. remarks:node["remarks"],
  333. isused:node["isused"],
  334. changedate:node['changedate'],
  335. changeby:node['changeby'],
  336. createdate:node['createdate'],
  337. createby:node['createby'],
  338. depno:node['depno'],
  339. disabled:that.pageOnlyRead,
  340. children: []
  341. }
  342. }
  343. if (node.subdep && node.subdep.length > 0) {
  344. // 如果存在子节点
  345. for (var index = 0; index < node.subdep.length; index++) {
  346. // 遍历子节点, 把每个子节点看做一颗独立的树, 传入递归构造子树, 并把结果放回到新node的children中
  347. elNode.children.push(convertToElementTree(node.subdep[index]));
  348. }
  349. }
  350. return elNode;
  351. }
  352. array.forEach((element) => {
  353. arr.push(convertToElementTree(element))
  354. });
  355. return arr
  356. },
  357. selectDep(val) {
  358. this.person = ''
  359. this.dataParam.content.type = 1
  360. this.dataParam.content.dataid = val[val.length -1]
  361. this.getProportionOfFileModel()
  362. },
  363. selectPerson(val){
  364. this.depment = ''
  365. this.isleave = ''
  366. this.dataParam.content.type = 0
  367. this.dataParam.content.dataid = val
  368. this.getProportionOfFileModel()
  369. },
  370. dataChange(val){
  371. this.dataParam.content.dateType = val
  372. this.projectParam.content.dateType = val
  373. if (val == '1'){
  374. let currentDate = new Date(); // 获取当前日期
  375. let startDate = new Date(currentDate.getFullYear() - 1, currentDate.getMonth(), currentDate.getDate() + 1); // 计算起始日期
  376. let endDate = currentDate; // 结束日期为当前日期
  377. this.dateSelect = [startDate.toISOString().split('T')[0],endDate.toISOString().split('T')[0]]
  378. }else if (val == '2'){
  379. let currentDate = new Date(); // 获取当前日期
  380. let startDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 9, currentDate.getDate() + 1); // 计算起始日期
  381. let endDate = currentDate; // 结束日期为当前日期
  382. this.dateSelect = [startDate.toISOString().split('T')[0],endDate.toISOString().split('T')[0]]
  383. }else if (val == '3'){
  384. let currentDate = new Date(); // 获取当前日期
  385. let startDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 6, currentDate.getDate() + 1); // 计算起始日期
  386. let endDate = currentDate; // 结束日期为当前日期
  387. this.dateSelect = [startDate.toISOString().split('T')[0],endDate.toISOString().split('T')[0]]
  388. }else if (val == '4'){
  389. let currentDate = new Date(); // 获取当前日期
  390. let startDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 3, currentDate.getDate() + 1); // 计算起始日期
  391. let endDate = currentDate; // 结束日期为当前日期
  392. this.dateSelect = [startDate.toISOString().split('T')[0],endDate.toISOString().split('T')[0]]
  393. }
  394. this.getProportionOfFileModel()
  395. },
  396. dateSet(val){
  397. if (val == '1'){
  398. let currentDate = new Date(); // 获取当前日期
  399. let startDate = new Date(currentDate.getFullYear() - 1, currentDate.getMonth(), currentDate.getDate() + 1); // 计算起始日期
  400. let endDate = currentDate; // 结束日期为当前日期
  401. this.dateSelect = [startDate.toISOString().split('T')[0],endDate.toISOString().split('T')[0]]
  402. }else if (val == '2'){
  403. let currentDate = new Date(); // 获取当前日期
  404. let startDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 9, currentDate.getDate() + 1); // 计算起始日期
  405. let endDate = currentDate; // 结束日期为当前日期
  406. this.dateSelect = [startDate.toISOString().split('T')[0],endDate.toISOString().split('T')[0]]
  407. }else if (val == '3'){
  408. let currentDate = new Date(); // 获取当前日期
  409. let startDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 6, currentDate.getDate() + 1); // 计算起始日期
  410. let endDate = currentDate; // 结束日期为当前日期
  411. this.dateSelect = [startDate.toISOString().split('T')[0],endDate.toISOString().split('T')[0]]
  412. }else if (val == '4'){
  413. let currentDate = new Date(); // 获取当前日期
  414. let startDate = new Date(currentDate.getFullYear(), currentDate.getMonth() - 3, currentDate.getDate() + 1); // 计算起始日期
  415. let endDate = currentDate; // 结束日期为当前日期
  416. this.dateSelect = [startDate.toISOString().split('T')[0],endDate.toISOString().split('T')[0]]
  417. }
  418. },
  419. dateChange(){
  420. this.dataParam.content.dateType = 0
  421. this.dataParam.content.where.begdate = this.dateSelect[0]
  422. this.dataParam.content.where.enddate = this.dateSelect[1]
  423. this.projectParam.content.dateType = 0
  424. this.projectParam.content.where.begdate = this.dateSelect[0]
  425. this.projectParam.content.where.enddate = this.dateSelect[1]
  426. this.getProportionOfFileModel()
  427. },
  428. renderPie() {
  429. if (JSON.parse(sessionStorage.getItem('flagIndex')) === 7){
  430. const colorArray = ['#6395fa','#63daab','#657798','#f7c122','#7666fa','#75cbed'];
  431. this.chartPie = new Funnel('containerFunnel', {
  432. data: this.tableData,
  433. maxSize:0.6,
  434. xField: 'stagename',
  435. yField: 'wide',
  436. shape: 'funnel',
  437. dynamicHeight: false,
  438. legend: false,
  439. interactions: [{ type: 'element-active'}],
  440. color:['#6395fa','#63daab','#657798','#f7c122','#7666fa','#75cbed','#fff'],
  441. label: {
  442. layout:"fixedOverlap",
  443. position:'right',
  444. offsetX:40,
  445. content:(datum)=>{
  446. const group = new G.Group({});
  447. const content = ()=>{
  448. if (this.tableData[0]) {
  449. const text = `${datum.stagename} 当前项目数: ${datum.projectqty} 项目数: ${datum.sequence1} 转化率: ${datum.zhl?Math.round((datum.zhl* 100)*100)/100 + '%':'--'} 预计签约金额: ${datum.signamount_due}万元 项目成交金额: ${datum.dealamount}万元`
  450. const lines = text.split(' ');
  451. return lines.join('\n');
  452. }
  453. };
  454. const color = ()=>{
  455. let clr = ''
  456. this.tableData.some((e,index) =>{
  457. if (e.stagename == datum.stagename) {
  458. clr = colorArray[index]
  459. }
  460. })
  461. if (clr == '' || clr == undefined) {
  462. clr= '#ffffff'
  463. }
  464. return clr
  465. };
  466. group.addShape({
  467. type: 'text',
  468. attrs: {
  469. x: 40,
  470. y: 0,
  471. text: content(),
  472. textAlign: 'left',
  473. fontSize: 14,
  474. textBaseline: 'top',
  475. fill: color()
  476. },
  477. });
  478. return group;
  479. },
  480. },
  481. tooltip:{
  482. customContent: (title, items) => {
  483. // 构建自定义内容
  484. const content = `<div>
  485. <ul style="padding:10px;">
  486. ${items.map((item) => `
  487. <li>
  488. <p style="margin-bottom:10px">${title}</p>
  489. <p>项目数:${item.data.projectqty}</p>
  490. </li>`).join('')}
  491. </ul>
  492. </div>`;
  493. return content;
  494. },
  495. },
  496. conversionTag: false,
  497. funnelStyle: {
  498. stroke: '#fff',
  499. lineWidth: 3,
  500. },
  501. });
  502. this.chartPie.render();
  503. document.addEventListener('click',(evt) => {
  504. const states = this.chartPie.getStates();
  505. let dataList = []
  506. dataList = states
  507. if (dataList.length > 0){
  508. this.projectTile = dataList[0].data.stagename
  509. this.sa_projstagemagid = dataList[0].data.sa_projstagemagid
  510. this.projectParam.content.pageNumber = 1
  511. this.projectParam.content.pageSize = 20
  512. this.getProjectList()
  513. }
  514. })
  515. this.getProportionOfFileModel()
  516. }else if(JSON.parse(sessionStorage.getItem('flagIndex')) === 8){
  517. const colorArray = ['#6395fa','#63daab','#657798','#f7c122','#7666fa','#75cbed','#6FD26C'];
  518. this.chartPie = new Funnel('containerFunnel', {
  519. data: this.tableData,
  520. maxSize:0.6,
  521. xField: 'stagename',
  522. yField: 'wide',
  523. shape: 'funnel',
  524. dynamicHeight: false,
  525. legend: false,
  526. interactions: [{ type: 'element-active'}],
  527. color:['#6395fa','#63daab','#657798','#f7c122','#7666fa','#75cbed','#6FD26C','#fff'],
  528. label: {
  529. layout:"fixedOverlap",
  530. position:'right',
  531. offsetX:40,
  532. content:(datum)=>{
  533. const group = new G.Group({});
  534. const content = ()=>{
  535. if (this.tableData[0]) {
  536. const text = `${datum.stagename} 当前项目数: ${datum.projectqty} 项目数: ${datum.sequence1} 转化率: ${datum.zhl?Math.round((datum.zhl* 100)*100)/100 + '%':'--'} 预计签约金额: ${datum.signamount_due}万元 项目成交金额: ${datum.dealamount}万元`
  537. const lines = text.split(' ');
  538. return lines.join('\n');
  539. }
  540. };
  541. const color = ()=>{
  542. let clr = ''
  543. this.tableData.some((e,index) =>{
  544. if (e.stagename == datum.stagename) {
  545. clr = colorArray[index]
  546. }
  547. })
  548. if (clr == '' || clr == undefined) {
  549. clr= '#ffffff'
  550. }
  551. return clr
  552. };
  553. group.addShape({
  554. type: 'text',
  555. attrs: {
  556. x: 40,
  557. y: 0,
  558. text: content(),
  559. textAlign: 'left',
  560. fontSize: 14,
  561. textBaseline: 'top',
  562. fill: color()
  563. },
  564. });
  565. return group;
  566. },
  567. },
  568. tooltip:{
  569. customContent: (title, items) => {
  570. // 构建自定义内容
  571. const content = `<div>
  572. <ul style="padding:10px;">
  573. ${items.map((item) => `
  574. <li>
  575. <p style="margin-bottom:10px">${title}</p>
  576. <p>项目数:${item.data.projectqty}</p>
  577. </li>`).join('')}
  578. </ul>
  579. </div>`;
  580. return content;
  581. },
  582. },
  583. conversionTag: false,
  584. funnelStyle: {
  585. stroke: '#fff',
  586. lineWidth: 3,
  587. },
  588. });
  589. this.chartPie.render();
  590. document.addEventListener('click',(evt) => {
  591. const states = this.chartPie.getStates();
  592. let dataList = []
  593. dataList = states
  594. if (dataList.length > 0){
  595. this.projectTile = dataList[0].data.stagename
  596. this.sa_projstagemagid = dataList[0].data.sa_projstagemagid
  597. this.projectParam.content.pageNumber = 1
  598. this.projectParam.content.pageSize = 20
  599. this.getProjectList()
  600. }
  601. })
  602. this.getProportionOfFileModel()
  603. }else if(JSON.parse(sessionStorage.getItem('flagIndex')) === 6){
  604. const colorArray = ['#6395fa','#63daab','#657798','#f7c122','#7666fa'];
  605. this.chartPie = new Funnel('containerFunnel', {
  606. data: this.tableData,
  607. maxSize:0.6,
  608. xField: 'stagename',
  609. yField: 'wide',
  610. shape: 'funnel',
  611. dynamicHeight: false,
  612. legend: false,
  613. interactions: [{ type: 'element-active'}],
  614. color:['#6395fa','#63daab','#657798','#f7c122','#7666fa','#fff'],
  615. label: {
  616. layout:"fixedOverlap",
  617. position:'right',
  618. offsetX:40,
  619. content:(datum)=>{
  620. const group = new G.Group({});
  621. const content = ()=>{
  622. if (this.tableData[0]) {
  623. const text = `${datum.stagename} 当前项目数: ${datum.projectqty} 项目数: ${datum.sequence1} 转化率: ${datum.zhl?Math.round((datum.zhl* 100)*100)/100 + '%':'--'} 预计签约金额: ${datum.signamount_due}万元 项目成交金额: ${datum.dealamount}万元`
  624. const lines = text.split(' ');
  625. return lines.join('\n');
  626. }
  627. };
  628. const color = ()=>{
  629. let clr = ''
  630. this.tableData.some((e,index) =>{
  631. if (e.stagename == datum.stagename) {
  632. clr = colorArray[index]
  633. }
  634. })
  635. if (clr == '' || clr == undefined) {
  636. clr= '#ffffff'
  637. }
  638. return clr
  639. };
  640. group.addShape({
  641. type: 'text',
  642. attrs: {
  643. x: 40,
  644. y: 0,
  645. text: content(),
  646. textAlign: 'left',
  647. fontSize: 14,
  648. textBaseline: 'top',
  649. fill: color()
  650. },
  651. });
  652. return group;
  653. },
  654. },
  655. tooltip:{
  656. customContent: (title, items) => {
  657. // 构建自定义内容
  658. const content = `<div>
  659. <ul style="padding:10px;">
  660. ${items.map((item) => `
  661. <li>
  662. <p style="margin-bottom:10px">${title}</p>
  663. <p>项目数:${item.data.projectqty}</p>
  664. </li>`).join('')}
  665. </ul>
  666. </div>`;
  667. return content;
  668. },
  669. },
  670. conversionTag: false,
  671. funnelStyle: {
  672. stroke: '#fff',
  673. lineWidth: 3,
  674. },
  675. });
  676. this.chartPie.render();
  677. document.addEventListener('click',(evt) => {
  678. const states = this.chartPie.getStates();
  679. let dataList = []
  680. dataList = states
  681. if (dataList.length > 0){
  682. this.projectTile = dataList[0].data.stagename
  683. this.sa_projstagemagid = dataList[0].data.sa_projstagemagid
  684. this.projectParam.content.pageNumber = 1
  685. this.projectParam.content.pageSize = 20
  686. this.getProjectList()
  687. }
  688. })
  689. this.getProportionOfFileModel()
  690. } else {
  691. /*const colorArray = ['#6395fa','#63daab','#657798','#f7c122','#7666fa','#75cbed','#6FD26C','#DFC064'];*/
  692. const colorArray = ['#6395fa','#63daab','#657798','#f7c122','#7666fa','#75cbed','#6FD26C','#DFC064'];
  693. this.chartPie = new Funnel('containerFunnel', {
  694. data: this.tableData,
  695. maxSize:0.6,
  696. xField: 'stagename',
  697. yField: 'wide',
  698. shape: 'funnel',
  699. dynamicHeight: false,
  700. legend: false,
  701. interactions: [{ type: 'element-active'}],
  702. color:['#6395fa','#63daab','#657798','#f7c122','#7666fa','#75cbed','#6FD26C','#DFC064','#fff'],
  703. label: {
  704. layout:"fixedOverlap",
  705. position:'right',
  706. offsetX:40,
  707. content:(datum)=>{
  708. const group = new G.Group({});
  709. const content = ()=>{
  710. if (this.tableData[0]) {
  711. const text = `${datum.stagename} 当前项目数: ${datum.projectqty} 项目数: ${datum.sequence1} 转化率: ${datum.zhl?Math.round((datum.zhl* 100)*100)/100 + '%':'--'} 预计签约金额: ${datum.signamount_due}万元 项目成交金额: ${datum.dealamount}万元`
  712. const lines = text.split(' ');
  713. return lines.join('\n');
  714. }
  715. };
  716. const color = ()=>{
  717. let clr = ''
  718. this.tableData.some((e,index) =>{
  719. if (e.stagename == datum.stagename) {
  720. clr = colorArray[index]
  721. }
  722. })
  723. if (clr == '' || clr == undefined) {
  724. clr= '#ffffff'
  725. }
  726. return clr
  727. };
  728. group.addShape({
  729. type: 'text',
  730. attrs: {
  731. x: 40,
  732. y: 0,
  733. text: content(),
  734. textAlign: 'left',
  735. fontSize: 14,
  736. textBaseline: 'top',
  737. fill: color()
  738. },
  739. });
  740. return group;
  741. },
  742. },
  743. tooltip:{
  744. customContent: (title, items) => {
  745. // 构建自定义内容
  746. const content = `<div>
  747. <ul style="padding:10px;">
  748. ${items.map((item) => `
  749. <li>
  750. <p style="margin-bottom:10px">${title}</p>
  751. <p>项目数:${item.data.projectqty}</p>
  752. </li>`).join('')}
  753. </ul>
  754. </div>`;
  755. return content;
  756. },
  757. },
  758. conversionTag: false,
  759. funnelStyle: {
  760. stroke: '#fff',
  761. lineWidth: 3,
  762. },
  763. });
  764. this.chartPie.render();
  765. document.addEventListener('click',(evt) => {
  766. const states = this.chartPie.getStates();
  767. let dataList = []
  768. dataList = states
  769. if (dataList.length > 0 && dataList[0].data.stagename !== ''){
  770. this.projectTile = dataList[0].data.stagename
  771. this.sa_projstagemagid = dataList[0].data.sa_projstagemagid
  772. this.projectParam.content.pageNumber = 1
  773. this.projectParam.content.pageSize = 20
  774. this.getProjectList()
  775. }
  776. })
  777. this.getProportionOfFileModel()
  778. }
  779. },
  780. async getProportionOfFileModel () {
  781. const res = await this.$api.requested(this.dataParam)
  782. this.tableData = res.data
  783. let dataList = []
  784. dataList = res.data
  785. this.sa_projstagemagid = dataList[0].sa_projstagemagid
  786. this.projectTile = dataList[0].stagename
  787. this.projectParam.content.pageNumber = 1
  788. this.projectParam.content.pageSize = 20
  789. this.getProjectList()
  790. sessionStorage.setItem('flagIndex',dataList.length)
  791. this.flagIndex = dataList.length
  792. this.chartPie.changeData(res.data)
  793. dataList.splice(dataList.length-1)
  794. },
  795. async getProjectList(){
  796. this.projectParam.content.type = this.dataParam.content.type
  797. this.projectParam.content.dataid = this.dataParam.content.dataid
  798. /*this.projectParam.content.dateType = this.dataParam.content.dateType*/
  799. this.projectParam.content.sa_projstagemagid = this.sa_projstagemagid
  800. const res = await this.$api.requested(this.projectParam)
  801. this.projectList = res.data
  802. this.total = res.total
  803. },
  804. handleSizeChange(val) {
  805. // console.log(`每页 ${val} 条`);
  806. this.projectParam.content.pageSize = val
  807. this.getProjectList()
  808. },
  809. handleCurrentChange(val) {
  810. // console.log(`当前页: ${val}`);
  811. this.projectParam.content.pageNumber = val
  812. this.getProjectList()
  813. },
  814. /*获取领域*/
  815. async queryTradeField(){
  816. const res = await this.$store.dispatch('optiontypeselect','tradefield')
  817. this.tradefields = res.data
  818. }
  819. },
  820. mounted () {
  821. /* this.renderPie()*/
  822. this.departmentrtment()
  823. this.dateSet(1)
  824. this.queryTradeField()
  825. },
  826. created() {
  827. this.tablecols = this.tool.tabelCol(this.$route.name).projectTable.tablecols
  828. }
  829. }
  830. </script>
  831. <style>
  832. </style>
  833. <style scoped>
  834. .title{
  835. height: 20px;
  836. line-height: 20px;
  837. font-size: 14px;
  838. text-indent: 7px;
  839. font-weight: bold;
  840. color: #333333;
  841. margin-bottom: 20px;
  842. border-left: .3rem solid #3874F6;
  843. }
  844. .container{
  845. /* height:calc(100vh)*/
  846. }
  847. </style>