index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. <script setup name="rateAnalysis">
  2. import excelCop from '@/components/excel.vue'
  3. import treeCop from '@/components/tree.vue'
  4. import barChartCop from './components/barChart.vue'
  5. import lineChartCop from './components/lineChart.vue'
  6. import CurrentScatterChartCop from './components/current-scatter-chart.vue'
  7. import SubmitBtn from '../../../components/SubmitBtn.vue'
  8. // import { ElMessage } from 'element-plus';
  9. import { onMounted, ref, onActivated, shallowRef, reactive, nextTick } from 'vue'
  10. import request from '@/api/axios.js'
  11. import tools from '@tools/htmlToPdf.js'
  12. // import flowerRes from '@/data/flower.json'
  13. // import lineChartRes from '@/data/lineNew.json'
  14. /**配置参数 */
  15. const treeHeight = ref(window.innerHeight - 150 + 'px') //tree高度
  16. const excelHeight = ref(window.innerHeight - 150 + 'px') //excel高度
  17. const tableHeight = ref(window.innerHeight - 150 + 'px')
  18. /**excel 开始 */
  19. const excelCheckIds = ref([])
  20. const excelList = ref([])
  21. /** 额定功率 */
  22. const powerproduction = ref("")
  23. //点击excel项时
  24. const funExcelChange = async (obj) => {
  25. excelCheckIds.value = [obj.id] //当为单选展示风机图表时
  26. chartExcelList.value = excelList.value.map(o=> {
  27. return {
  28. ...o,
  29. name: o.windturbine
  30. }
  31. }) // 选中excel当前项时, excel列表赋值给dialog 下拉框
  32. queryForm.checkIds = excelList.value.map(o => o.id)
  33. checkAll.value = true
  34. funSubmit()
  35. }
  36. const funExcelCheckChange = ({ checkArr, data }) => {
  37. excelCheckIds.value = checkArr
  38. }
  39. /**tree 开始 */
  40. const treeData = ref([])
  41. const actTreeNode = ref(null)
  42. const funRepeatMap = (arr) => {
  43. return arr.map(o => {
  44. if (o.children) {
  45. const findIndex = o.children.findIndex(p => !!p.type)
  46. if (findIndex !== -1) {
  47. o.childs = o.children
  48. o.children = []
  49. if(!actTreeNode.value){
  50. actTreeNode.value = o
  51. }
  52. }
  53. }
  54. return {
  55. ...o,
  56. children: o.children?.length ? funRepeatMap(o.children) : []
  57. }
  58. })
  59. }
  60. const funGetTree = async () => {
  61. const res = await request.get("/power/process/tree")
  62. actTreeNode.value = null
  63. excelList.value = []
  64. treeData.value = funRepeatMap(res.data)
  65. if(actTreeNode.value){
  66. funCurrentChange({current: actTreeNode.value, currentNode: null})
  67. funExcelChange({id: actTreeNode.value.childs[0].id})
  68. }
  69. }
  70. const funTreeCheckChange = ({ current, checkedNodes, checkedKeys, halfCheckedNodes, halfCheckedKeys }) => { //tree change -> excel change
  71. funCurrentChange({ current, currentNode: '' })
  72. const checkIds = []
  73. if (checkedNodes.length) {
  74. for (const node of checkedNodes) {
  75. if (node.childs && node.childs.length) {
  76. for (const child of node.childs) {
  77. checkIds.push(child.id)
  78. }
  79. }
  80. }
  81. }
  82. excelCheckIds.value = checkIds
  83. }
  84. const funCurrentChange = ({ current, currentNode }) => {
  85. if (current.childs) {
  86. excelList.value = current.childs.map(o => {
  87. return {
  88. id: o.id,
  89. interval: o.interval,
  90. path: o.path,
  91. prepareid: o.prepareid,
  92. station: o.station,
  93. time: o.time,
  94. type: o.type,
  95. windturbine: o.windturbine,
  96. name: o.path.substring(o.path.indexOf(o.station + '_') + (o.station + '_').length)
  97. }
  98. })
  99. } else {
  100. excelList.value = []
  101. }
  102. }
  103. /**chart */
  104. let chartId = 1
  105. const powerproductionNum = ref(0)
  106. /**submit */
  107. const funSubmit = async () => {
  108. const tempRes = await request.get('/temperature/rated/power', {
  109. params: {
  110. ids: excelCheckIds.value.join(','),
  111. }
  112. })
  113. // const lineRes = await request.get('/wind/deviation/ratio', {
  114. // params: {
  115. // ids: excelCheckIds.value.join(','),
  116. // mode: 0
  117. // }
  118. // })
  119. // const rosesRes = flowerRes
  120. // const lineRes = lineChartRes
  121. if (tempRes.code === 200) {
  122. if (tempRes.data?.length) {
  123. for (const chart of tempRes.data) {
  124. powerproduction.value = `(额定功率=${chart.power.powerproduction}kW)`
  125. powerproductionNum.value = chart.power.powerproduction
  126. barxAxis.data = Object.keys(chart.res1)
  127. barSeries[0].data = Object.values(chart.res1)
  128. barSeries[0].markLine.data = [{
  129. yAxis: 0,
  130. }]
  131. chartId++
  132. lineSeries.value = [
  133. {
  134. type: 'effectScatter',
  135. showEffectOn: "emphasis",
  136. rippleEffect: {
  137. scale: 1
  138. },
  139. legendHoverLink: false,
  140. name: '',
  141. symbolSize: 5,
  142. data: chart.res2,
  143. yAxisIndex: 0,
  144. markLine: {
  145. symbol: 'none',
  146. label: {
  147. show: false,
  148. },
  149. lineStyle: {
  150. color: '#F72C5B'
  151. },
  152. data: [{
  153. yAxis: powerproductionNum.value,
  154. }]
  155. }
  156. }
  157. ]
  158. chartId++
  159. }
  160. }
  161. }
  162. // if(lineRes.code === 200){
  163. // if(lineRes.data?.length){
  164. // lineDataSet.value[0].source = lineRes.data[0].scatter.map(o => {
  165. // return [o.x+'', o.y]
  166. // })
  167. // lineSeries.value = [{
  168. // name: "对风频次",
  169. // type: "line",
  170. // symbol: "line", //设定为实心点
  171. // symbolSize: 0, //设定实心点的大小
  172. // smooth: true, //这个是把线变成曲线
  173. // data: lineRes.data[0].count,
  174. // yAxisIndex: 1,
  175. // },
  176. // {
  177. // type: 'effectScatter',
  178. // showEffectOn: "emphasis",
  179. // rippleEffect: {
  180. // scale: 1
  181. // },
  182. // legendHoverLink: false,
  183. // name: '数据散点',
  184. // symbolSize: 5,
  185. // datasetIndex: 0,
  186. // encode: {
  187. // x: 'x',
  188. // y: 'y'
  189. // },
  190. // yAxisIndex: 0,
  191. // }]
  192. // }
  193. // }
  194. }
  195. /**lineChart */
  196. const linexAxis = reactive({
  197. type: 'value',
  198. name: '°C',
  199. splitLine: {
  200. show: false
  201. },
  202. axisTick: {
  203. show: true
  204. },
  205. axisLine: {
  206. onZero: false
  207. }
  208. })
  209. const lineyAxis = reactive([
  210. {
  211. type: 'value',
  212. name: 'kW',
  213. splitLine: {
  214. show: false
  215. },
  216. axisTick: {
  217. show: true
  218. },
  219. axisLine: {
  220. onZero: false
  221. }
  222. }
  223. ])
  224. const lineSeries = ref([])
  225. const lineDataSet = reactive([
  226. {
  227. source: []
  228. }
  229. ])
  230. // 圈选散点触发函数
  231. const funChartSelect = async (batch) => {
  232. const wDataArr = []
  233. const yDataArr = []
  234. let scatterls = []
  235. let dataSetObj = []
  236. wtData.value = []
  237. if (batch?.length && actCopList.value[0]?.dataset) {
  238. scatterls = batch[0].selected[1].dataIndex
  239. if (scatterls?.length) {
  240. dataSetObj = JSON.parse(actCopList.value[0].dataset)
  241. if (scatterls?.length) {
  242. for (const scatterIndex of scatterls) {
  243. wDataArr.push(dataSetObj[0].source[scatterIndex].k)
  244. }
  245. }
  246. const wtRes = await request.get('/power/fitting/filter', { params: { yk: yDataArr.join(','), wk: wDataArr.join(',') } })
  247. if (wtRes.code === 200) {
  248. let id = 1
  249. const tempArr = [] //用于以风机id 聚合dataArr
  250. if (wtRes.data?.length) {
  251. for (const data of wtRes.data) {
  252. if (tempArr.length) {
  253. const findIndex = tempArr.findIndex(o => o.wtId === data.wtId)
  254. if (findIndex !== -1) {
  255. if (!tempArr[findIndex].children) {
  256. tempArr[findIndex].children = []
  257. }
  258. tempArr[findIndex].children.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
  259. id++
  260. } else {
  261. tempArr.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
  262. id++
  263. }
  264. } else {
  265. tempArr.push({ ...data, id: id, filter: data.filter === 0 ? '是' : '否' })
  266. id++
  267. }
  268. }
  269. wtDialog.value = true
  270. nextTick(() => {
  271. wtTab.value = 'table'
  272. wtData.value = tempArr
  273. })
  274. }
  275. }
  276. }
  277. }
  278. }
  279. /**barChart */
  280. const barxAxis = reactive({
  281. type: 'category',
  282. name: '℃',
  283. data: [],
  284. splitLine: {
  285. show: false
  286. },
  287. axisTick: {
  288. show: true
  289. },
  290. axisLine: {
  291. onZero: false
  292. }
  293. })
  294. const baryAxis = reactive({
  295. type: 'value',
  296. name: 'kW',
  297. splitLine: {
  298. show: false
  299. },
  300. axisTick: {
  301. show: true
  302. },
  303. axisLine: {
  304. onZero: false
  305. }
  306. })
  307. const barSeries = reactive([{
  308. name: "",
  309. type: "bar",
  310. data: [],
  311. markLine: {
  312. symbol: 'none',
  313. label: {
  314. show: false,
  315. },
  316. lineStyle: {
  317. color: '#F72C5B'
  318. },
  319. data: []
  320. }
  321. }])
  322. /**dialog 数据 */
  323. const wtDialog = ref(false)
  324. const wtData = ref([])
  325. const wtTab = ref('table')
  326. /**dialog */
  327. const dialog = ref(false)
  328. const actChartName = ref('')
  329. const actDiaTitle = ref('')
  330. const diaPanelRef = ref()
  331. const exportLoading = ref(false)
  332. const actCopList = ref([
  333. // {
  334. // xAxis: [],
  335. // subtext: '',
  336. // title: '',
  337. // isRadar: false,
  338. // series: [],
  339. // yAxis: [],
  340. // dataset: []
  341. // }
  342. ])
  343. // 作为actCopList的备份 在actCopList赋值多个时 同时赋值, 在dialog弹出时清空. 作用: 在actCopList变化时, 重新赋值原始数据
  344. const actCopListBak = ref([])
  345. const checkAll = ref(true)
  346. const queryForm = reactive({
  347. checkIds: []
  348. })
  349. const funCheckAll = () => {
  350. checkAll.value = !checkAll.value
  351. if(checkAll.value){
  352. queryForm.checkIds = chartExcelList.value.map(o => o.id)
  353. }else{
  354. queryForm.checkIds = []
  355. }
  356. }
  357. const chartExcelList = ref([]) //dialog 下拉项
  358. const funActCop = (obj, type) => {
  359. switch(type){
  360. case 'barChartCop':
  361. actChartName.value = 'barChartCop'
  362. obj.actCop = shallowRef(barChartCop)
  363. actDiaTitle.value = '平均功率-额定功率'
  364. break
  365. case 'lineChartCop':
  366. actChartName.value = 'lineChartCop'
  367. obj.actCop = shallowRef(lineChartCop)
  368. actDiaTitle.value = '额定功率温度分析'
  369. break
  370. // case 'CurrentScatterChartCop':
  371. // actChartName.value = 'CurrentScatterChartCop'
  372. // obj.actCop = shallowRef(CurrentScatte console.log(res)rChartCop)
  373. // actDiaTitle.value = '静态偏航对风分析图'
  374. // break
  375. }
  376. obj.isBrush = false
  377. obj.id = chartId
  378. chartId ++
  379. dialog.value = true
  380. actCopListBak.value = []
  381. nextTick(() => {
  382. actCopList.value = [obj]
  383. })
  384. }
  385. const funDiaSubmit = async () => {
  386. let url = ''
  387. switch(actChartName.value){
  388. case 'barChartCop':
  389. url = '/temperature/rated/power'
  390. break
  391. case 'lineChartCop':
  392. url = '/temperature/rated/power'
  393. break
  394. // case 'CurrentScatterChartCop':
  395. // url = '' //暂无接口
  396. // break
  397. }
  398. if(url){
  399. const res = await request.get(url, {
  400. params: {
  401. ids: queryForm.checkIds.join(','),
  402. mode: 0
  403. }
  404. })
  405. if(res.code===200){
  406. actCopList.value = []
  407. actCopListBak.value = [] //清空备份
  408. if(res.data?.length){
  409. for(const chart of res.data){
  410. if(actChartName.value==='barChartCop'){
  411. actCopList.value.push({
  412. id: chartId,
  413. isBrush: false,
  414. actCop: shallowRef(barChartCop),
  415. title: chart.wt,
  416. subtext: `平均功率-额定功率(额定功率=${chart.power.powerproduction}kW)`,
  417. xAxis: {
  418. ...barxAxis,
  419. data: Object.keys(chart.res1)
  420. },
  421. yAxis: baryAxis,
  422. series: [{
  423. name: "",
  424. type: "bar",
  425. data: Object.values(chart.res1),
  426. markLine: {
  427. symbol: 'none',
  428. label: {
  429. show: false,
  430. },
  431. lineStyle: {
  432. color: '#F72C5B'
  433. },
  434. data: [{
  435. yAxis: 0,
  436. }]
  437. }
  438. }]
  439. })
  440. chartId++
  441. }
  442. if(actChartName.value === 'lineChartCop'){
  443. actCopList.value.push({
  444. id: chartId,
  445. isBrush: false,
  446. actCop: shallowRef(lineChartCop),
  447. title: chart.wt,
  448. subtext: `额定功率温度分析(额定功率=${chart.power.powerproduction}kW)`,
  449. xAxis: linexAxis,
  450. yAxis: lineyAxis,
  451. dataset: lineDataSet,
  452. series: [
  453. {
  454. type: 'effectScatter',
  455. showEffectOn: "emphasis",
  456. rippleEffect: {
  457. scale: 1
  458. },
  459. legendHoverLink: false,
  460. name: '',
  461. symbolSize: 5,
  462. data: chart.res2,
  463. yAxisIndex: 0,
  464. markLine: {
  465. symbol: 'none',
  466. label: {
  467. show: false,
  468. },
  469. lineStyle: {
  470. color: '#F72C5B'
  471. },
  472. data: [{
  473. yAxis: chart.power.powerproduction,
  474. }]
  475. }
  476. }
  477. ]
  478. })
  479. chartId++
  480. }
  481. }
  482. actCopListBak.value = actCopList.value
  483. }
  484. }
  485. }
  486. }
  487. const funDiaExport = () => {
  488. exportLoading.value = true
  489. tools.scrollToPDF(diaPanelRef.value, actDiaTitle.value, () => {
  490. exportLoading.value = false
  491. })
  492. }
  493. const funDbClick = (obj) => {
  494. if(actCopListBak.value.length > 1){ //判断大于1时, 才有双击放大功能
  495. if(actCopList.value.length === 1){
  496. actCopList.value = actCopListBak.value
  497. }else{
  498. actCopList.value = [obj]
  499. }
  500. }
  501. }
  502. /**created */
  503. // funGetTree()
  504. /**activated */
  505. onMounted(() => {
  506. //test
  507. // funSubmit()
  508. //
  509. tableHeight.value = window.innerHeight - 150 + 'px'
  510. excelHeight.value =(window.innerHeight - 150) + 'px'
  511. treeHeight.value = (window.innerHeight - 150) + 'px'
  512. window.addEventListener('resize', () => {
  513. tableHeight.value = window.innerHeight - 150 + 'px'
  514. excelHeight.value = (window.innerHeight - 150) + 'px'
  515. treeHeight.value = (window.innerHeight - 150) + 'px'
  516. })
  517. })
  518. onActivated(() => {
  519. funGetTree()
  520. })
  521. </script>
  522. <template>
  523. <div class="bg-white py-[10px] px-[10px] relative s-dialog-body">
  524. <!-- <el-dialog v-model="wtDialog" draggable title="风机功率点位">
  525. <el-tabs v-model="wtTab">
  526. <el-tab-pane label="数据" name="table">
  527. <el-table :data="wtData" row-key="id" :max-height="550">
  528. <el-table-column property="wtId" align="center" label="风机" />
  529. <el-table-column property="time" sortable :width="160" align="center" label="时间" />
  530. <el-table-column property="speed" sortable align="center" label="风速(m/s)" />
  531. <el-table-column property="power" sortable align="center" label="功率(kw)" />
  532. <el-table-column property="rr" sortable align="center" label="转速" />
  533. <el-table-column property="filter" sortable align="center" label="是否有用点" />
  534. </el-table>
  535. </el-tab-pane>
  536. <el-tab-pane label="故障" name="problem" disabled>
  537. </el-tab-pane>
  538. <el-tab-pane label="预警" name="warning" disabled>
  539. </el-tab-pane>
  540. </el-tabs>
  541. </el-dialog> -->
  542. <el-dialog draggable width="80%" v-model="dialog" :title="actDiaTitle">
  543. <el-form class="whitespace-nowrap" :inline="true" :model="queryForm">
  544. <el-form-item label="" class="!mb-0">
  545. <el-select v-model="queryForm.checkIds" clearable @clear="checkAll = false" collapse-tags multiple>
  546. <el-option label="全选" :class="{'selected': checkAll}" @click="funCheckAll"></el-option>
  547. <el-option v-for="item in chartExcelList" :key="item.id" :value="item.id" :label="item.name"></el-option>
  548. </el-select>
  549. </el-form-item>
  550. <el-form-item class="!mb-0">
  551. <submit-btn desc="查询" @click="funDiaSubmit"></submit-btn>
  552. <submit-btn desc="导出" @click="funDiaExport"></submit-btn>
  553. </el-form-item>
  554. </el-form>
  555. <div v-loading="exportLoading">
  556. <div ref="diaPanelRef" class="flex flex-wrap justify-center items-center h-[650px] overflow-y-auto overflow-x-hidden">
  557. <component :is="item.actCop" :width="actCopList.length > 1 ? '50%' : '100%'" height="100%" v-for="item in actCopList"
  558. :key="item.id" :xAxis="item.xAxis" :subtext="item.subtext" :title="item.title"
  559. :series="item.series" :isDiaAlone="(actCopList.length === 1)" @dblclick="funDbClick(item)" :yAxis="item.yAxis" :dataset="item.dataset" :brush="item.isBrush" @getSelected="funChartSelect"></component>
  560. </div>
  561. </div>
  562. </el-dialog>
  563. <div class="relative shadow rounded-[6px] shadow-blue-500 px-[10px] pt-[10px] pb-[10px]">
  564. <div class="text-[14px] absolute top-[-7px] text-[#838383] left-[20px]">数据展示</div>
  565. <el-row :gutter="10">
  566. <el-col :span="5">
  567. <tree-cop :data="treeData" @checkChange="funTreeCheckChange" :show-checkbox="false" :height="treeHeight"
  568. @currentChange="funCurrentChange" @refresh="funGetTree">
  569. </tree-cop>
  570. </el-col>
  571. <el-col :span="3">
  572. <excel-cop :checkIds="excelCheckIds" :showCheckbox="false" :data="excelList" :height="excelHeight"
  573. @excelChange="funExcelChange" @checkChange="funExcelCheckChange"></excel-cop>
  574. </el-col>
  575. <el-col :span="16">
  576. <div :style="{ height: tableHeight }"
  577. class="flex flex-wrap justify-center items-center overflow-x-hidden overflow-y-auto ">
  578. <div class="mb-[10px] w-[100%] h-[49%] flex flex-col items-end shadow rounded-[6px] shadow-blue-500">
  579. <el-icon class="mr-[10px] mt-[10px] cursor-pointer" size="18"
  580. @click="funActCop({xAxis:barxAxis, yAxis:baryAxis, series: barSeries}, 'barChartCop')">
  581. <ZoomIn />
  582. </el-icon>
  583. <bar-chart-cop width="100%" height="100%" :subtext="`平均功率-额定功率 ${powerproduction}`" :xAxis="barxAxis" :yAxis="baryAxis" :series="barSeries"></bar-chart-cop>
  584. </div>
  585. <div class="w-[100%] h-[49%] flex flex-col items-end shadow rounded-[6px] shadow-blue-500">
  586. <el-icon class="mr-[10px] mt-[10px] cursor-pointer" size="18"
  587. @click="funActCop({xAxis:linexAxis, yAxis:lineyAxis, series: lineSeries}, 'lineChartCop')">
  588. <ZoomIn />
  589. </el-icon>
  590. <line-chart-cop class="" height="100%" width="100%" :xAxis="linexAxis" :yAxis="lineyAxis"
  591. :series="lineSeries" :subtext="`额定功率温度分析 ${powerproduction}`" :dataset="lineDataSet"></line-chart-cop>
  592. </div>
  593. <!-- <div class="mr-[10px] w-[49%] h-[49%] flex flex-col items-end shadow rounded-[6px] shadow-blue-500" v-if="!!lineSeries.length"> -->
  594. <!-- <el-icon class="mr-[10px] mt-[10px] cursor-pointer" size="18"
  595. @click="funActCop({ xAxis: linexAxis, yAxis: lineyAxis, series: lineSeries, dataset: lineDataSet }, 'lineChartCop')">
  596. <ZoomIn />
  597. </el-icon> -->
  598. <!-- <current-scatter-chart-cop class="" height="100%" width="100%" :xAxis="linexAxis" :yAxis="lineyAxis"
  599. :series="lineSeries" subtext="风速功率-温度分析" :dataset="lineDataSet"></current-scatter-chart-cop> -->
  600. <!-- </div> -->
  601. <!-- <div class="w-[49%] h-[49%] flex flex-col items-end shadow rounded-[6px] shadow-blue-500" v-if="!!lineSeries.length"> -->
  602. <!-- <el-icon class="mr-[10px] mt-[10px] cursor-pointer" size="18"
  603. @click="funActCop({ xAxis: xAxisData, yAxis: { splitLine: { show: false } }, series: seriesData, dataSet: dataSet }, 'CurrentScatterChartCop')">
  604. <ZoomIn />
  605. </el-icon> -->
  606. <!-- <current-scatter-chart-cop class="" height="100%" width="100%" :xAxis="linexAxis" :yAxis="lineyAxis"
  607. :series="lineSeries" subtext="对风偏差分析图" :dataset="lineDataSet"></current-scatter-chart-cop> -->
  608. <!-- </div> -->
  609. </div>
  610. </el-col>
  611. </el-row>
  612. </div>
  613. </div>
  614. </template>
  615. <style scoped>
  616. .s-dialog-body /deep/ .el-dialog__body{
  617. padding: 0px 20px;
  618. }
  619. </style>