Merge branch 'dev_New' of http://114.132.189.42:9002/r/product-inventory-management into dev_New
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // åè´§å®¡æ¹ |
| | | import request from "@/utils/request"; |
| | | |
| | | // è·åå货审æ¹å表 |
| | | export function getShipmentApprovalList(query) { |
| | | return request({ |
| | | url: '/shipmentApproval/listPage', |
| | | method: 'get', |
| | | params: query, |
| | | }) |
| | | } |
| | | |
| | | // åè´§ç³è¯·æ¹å |
| | | // /shipmentApproval/update |
| | | export function approveShipment(query) { |
| | | return request({ |
| | | url: '/shipmentApproval/update', |
| | | method: 'post', |
| | | data: query, |
| | | }) |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // æ¥è¯¢å¨èåå·¥å°è´¦ |
| | | export function staffOnJobListPage(query) { |
| | | return request({ |
| | | url: '/staff/staffOnJob/listPage', |
| | | method: 'get', |
| | | params: query, |
| | | }) |
| | | } |
| | | // æ¥è¯¢åå·¥å
¥èä¿¡æ¯ |
| | | export function staffOnJobInfo(query) { |
| | | return request({ |
| | | url: '/staff/staffOnJob/staffNo', |
| | | method: 'get', |
| | | params: query, |
| | | }) |
| | | } |
| | | |
| | | // 导åºåå坿¬ |
| | | export function staffOnJobExportCopy(data) { |
| | | return request({ |
| | | url: '/staff/staffOnJob/exportCopy', |
| | | method: 'post', |
| | | data: data, |
| | | }) |
| | | } |
| | |
| | | } |
| | | |
| | | // å 餿æ å表 |
| | | export function qualityInspectDetailByProductId(productId) { |
| | | export function qualityInspectDetailByProductId(params) { |
| | | return request({ |
| | | url: "/qualityTestStandard/product/" + productId, |
| | | url: "/qualityTestStandard/getQualityTestStandardByProductId", |
| | | method: "get", |
| | | params: params, |
| | | }); |
| | | } |
| | | |
| | |
| | | data: ids, |
| | | }); |
| | | } |
| | | |
| | | // æ ¹æ®æ åIDè·åæ ååæ° |
| | | export function getQualityTestStandardParamByTestStandardId(testStandardId) { |
| | | return request({ |
| | | url: "/qualityTestStandard/getQualityTestStandardParamByTestStandardId", |
| | | method: "get", |
| | | params: { testStandardId }, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="40" height="40" viewBox="0 0 40 40"><defs><mask id="master_svg0_88_35670" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="40" height="40"><ellipse cx="20" cy="20" rx="20" ry="20" fill="#FFFFFF" fill-opacity="1"/></mask><clipPath id="master_svg1_88_35666"><rect x="7" y="7" width="27" height="27" rx="0"/></clipPath><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg2_88_26531"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"/><stop offset="98.57142567634583%" stop-color="#F0FBFF" stop-opacity="1"/></linearGradient><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg3_88_26531"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"/><stop offset="98.57142567634583%" stop-color="#F0FBFF" stop-opacity="1"/></linearGradient></defs><g mask="url(#master_svg0_88_35670)"><ellipse cx="20" cy="20" rx="20" ry="20" fill="#0092FF" fill-opacity="1"/><g clip-path="url(#master_svg1_88_35666)"><path d="M21.175671875,27.58515925L14.263672875000001,27.58515925C13.750673275,27.58515925,13.426672974999999,27.24765625,13.426672974999999,26.74815725C13.426672974999999,26.23515525,13.764173075,25.911160250000002,14.263672875000001,25.911160250000002L21.351173875,25.911160250000002C21.688676875,24.89865825,22.188173875,23.88615425,22.863174875,23.211156250000002L14.263672875000001,23.211156250000002C13.750673275,23.211156250000002,13.426672974999999,22.87365525,13.426672974999999,22.37415225C13.426672974999999,21.87465325,13.764173075,21.537155249999998,14.263672875000001,21.537155249999998L25.738675875,21.537155249999998C26.251674875,21.37515325,26.751174875,21.37515325,27.088676875,21.37515325C28.438678875,21.37515325,29.626676875,21.88815525,30.625678875,22.549656249999998L30.625678875,13.072656349999999C30.625678875,11.38515625,29.275674875,10.03515625,27.588174875,10.03515625L27.075177875,10.03515625L27.075177875,13.24815675C27.075177875,14.935656550000001,25.725173875,16.285657450000002,24.037676875000002,16.285657450000002L16.113174475,16.285657450000002C14.425674475000001,16.272157149999998,13.075673375000001,14.922158249999999,13.075673375000001,13.23465635L13.075673375000001,10.03515625L12.238672475,10.03515625C10.551171974999999,10.03515625,9.201171875,11.38515625,9.201171875,13.072656349999999L9.201171875,29.94765825C9.201171875,31.63515625,10.551171974999999,32.985161250000004,12.238672475,32.985161250000004L25.576673875,32.985161250000004C23.200674875,32.485662250000004,21.337675875000002,30.28515825,21.175671875,27.58515925Z" fill="url(#master_svg2_88_26531)" fill-opacity="1" style="mix-blend-mode:passthrough"/><path d="M16.1124145625,14.764538762499999L24.0504169625,14.764538762499999C24.8874170625,14.764538762499999,25.5624140625,14.0895385625,25.5624140625,13.252537762500001L25.5624140625,10.0395388625L22.5249171625,10.0395388625C22.3629159625,8.8650390625,21.3369150625,7.8525390625,19.986915562500002,7.8525390625C18.7989153625,7.8525390625,17.7864150625,8.8650390625,17.6244149625,10.0395388625L14.5869140625,10.0395388625L14.5869140625,13.252537762500001C14.5869140625,14.0895385625,15.2619143725,14.764538762499999,16.1124145625,14.764538762499999ZM30.7869150625,24.3900370625C29.9499160625,23.3775360625,28.5999220625,22.7025380625,27.2499170625,22.7025380625L26.412916062500003,22.7025380625C25.8999180625,22.7025380625,25.5759160625,22.8780390625,25.0629190625,23.2155400625C24.0504169625,23.7285370625,23.1999158625,24.7275330625,22.700415562499998,25.9155390625C22.5384173625,26.4285390625,22.5384173625,26.9280380625,22.5384173625,27.4275380625L22.5384173625,27.5895390625C22.700415562499998,30.1275410625,24.7254170625,31.9770390625,27.1014200625,31.9770390625C28.4514180625,31.9770390625,29.8014230625,31.3020400625,30.6384180625,30.2895320625C31.3134210625,29.4525340625,31.6509170625,28.4265380625,31.6509170625,27.2520330625C31.8129160625,26.2395310625,31.2999250625,25.2270370625,30.7869150625,24.3900370625ZM29.7879200625,26.5770380625L27.0879160625,29.2770390625C26.7504160625,29.6145400625,26.412916062500003,29.6145400625,26.0754160625,29.2770390625L24.387915562499998,27.5895390625C24.0504169625,27.2520370625,24.0504169625,26.9145390625,24.387915562499998,26.5770380625C24.725415062499998,26.2395380625,25.0629150625,26.2395400625,25.4004160625,26.5770380625L26.2374170625,27.4140400625L26.5749150625,27.7515370625L28.7619150625,25.5645350625C29.0994140625,25.2270370625,29.4369190625,25.2270370625,29.774416062500002,25.5645350625C30.1119160625,25.9020370625,30.1119160625,26.2395380625,29.7879200625,26.5770380625Z" fill="url(#master_svg3_88_26531)" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="40" height="40" viewBox="0 0 40 40"><defs><mask id="master_svg0_88_35670" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="40" height="40"><ellipse cx="20" cy="20" rx="20" ry="20" fill="#FFFFFF" fill-opacity="1"/></mask><clipPath id="master_svg1_88_35666"><rect x="7" y="7" width="27" height="27" rx="0"/></clipPath><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg2_88_26531"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"/><stop offset="98.57142567634583%" stop-color="#F0FBFF" stop-opacity="1"/></linearGradient><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg3_88_26531"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"/><stop offset="98.57142567634583%" stop-color="#F0FBFF" stop-opacity="1"/></linearGradient></defs><g mask="url(#master_svg0_88_35670)"><ellipse cx="20" cy="20" rx="20" ry="20" fill="#5EB334" fill-opacity="1"/><g clip-path="url(#master_svg1_88_35666)"><path d="M21.175671875,27.58515925L14.263672875000001,27.58515925C13.750673275,27.58515925,13.426672974999999,27.24765625,13.426672974999999,26.74815725C13.426672974999999,26.23515525,13.764173075,25.911160250000002,14.263672875000001,25.911160250000002L21.351173875,25.911160250000002C21.688676875,24.89865825,22.188173875,23.88615425,22.863174875,23.211156250000002L14.263672875000001,23.211156250000002C13.750673275,23.211156250000002,13.426672974999999,22.87365525,13.426672974999999,22.37415225C13.426672974999999,21.87465325,13.764173075,21.537155249999998,14.263672875000001,21.537155249999998L25.738675875,21.537155249999998C26.251674875,21.37515325,26.751174875,21.37515325,27.088676875,21.37515325C28.438678875,21.37515325,29.626676875,21.88815525,30.625678875,22.549656249999998L30.625678875,13.072656349999999C30.625678875,11.38515625,29.275674875,10.03515625,27.588174875,10.03515625L27.075177875,10.03515625L27.075177875,13.24815675C27.075177875,14.935656550000001,25.725173875,16.285657450000002,24.037676875000002,16.285657450000002L16.113174475,16.285657450000002C14.425674475000001,16.272157149999998,13.075673375000001,14.922158249999999,13.075673375000001,13.23465635L13.075673375000001,10.03515625L12.238672475,10.03515625C10.551171974999999,10.03515625,9.201171875,11.38515625,9.201171875,13.072656349999999L9.201171875,29.94765825C9.201171875,31.63515625,10.551171974999999,32.985161250000004,12.238672475,32.985161250000004L25.576673875,32.985161250000004C23.200674875,32.485662250000004,21.337675875000002,30.28515825,21.175671875,27.58515925Z" fill="url(#master_svg2_88_26531)" fill-opacity="1" style="mix-blend-mode:passthrough"/><path d="M16.1124145625,14.764538762499999L24.0504169625,14.764538762499999C24.8874170625,14.764538762499999,25.5624140625,14.0895385625,25.5624140625,13.252537762500001L25.5624140625,10.0395388625L22.5249171625,10.0395388625C22.3629159625,8.8650390625,21.3369150625,7.8525390625,19.986915562500002,7.8525390625C18.7989153625,7.8525390625,17.7864150625,8.8650390625,17.6244149625,10.0395388625L14.5869140625,10.0395388625L14.5869140625,13.252537762500001C14.5869140625,14.0895385625,15.2619143725,14.764538762499999,16.1124145625,14.764538762499999ZM30.7869150625,24.3900370625C29.9499160625,23.3775360625,28.5999220625,22.7025380625,27.2499170625,22.7025380625L26.412916062500003,22.7025380625C25.8999180625,22.7025380625,25.5759160625,22.8780390625,25.0629190625,23.2155400625C24.0504169625,23.7285370625,23.1999158625,24.7275330625,22.700415562499998,25.9155390625C22.5384173625,26.4285390625,22.5384173625,26.9280380625,22.5384173625,27.4275380625L22.5384173625,27.5895390625C22.700415562499998,30.1275410625,24.7254170625,31.9770390625,27.1014200625,31.9770390625C28.4514180625,31.9770390625,29.8014230625,31.3020400625,30.6384180625,30.2895320625C31.3134210625,29.4525340625,31.6509170625,28.4265380625,31.6509170625,27.2520330625C31.8129160625,26.2395310625,31.2999250625,25.2270370625,30.7869150625,24.3900370625ZM29.7879200625,26.5770380625L27.0879160625,29.2770390625C26.7504160625,29.6145400625,26.412916062500003,29.6145400625,26.0754160625,29.2770390625L24.387915562499998,27.5895390625C24.0504169625,27.2520370625,24.0504169625,26.9145390625,24.387915562499998,26.5770380625C24.725415062499998,26.2395380625,25.0629150625,26.2395400625,25.4004160625,26.5770380625L26.2374170625,27.4140400625L26.5749150625,27.7515370625L28.7619150625,25.5645350625C29.0994140625,25.2270370625,29.4369190625,25.2270370625,29.774416062500002,25.5645350625C30.1119160625,25.9020370625,30.1119160625,26.2395380625,29.7879200625,26.5770380625Z" fill="url(#master_svg3_88_26531)" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="40" height="40" viewBox="0 0 40 40"><defs><mask id="master_svg0_88_35670" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="40" height="40"><ellipse cx="20" cy="20" rx="20" ry="20" fill="#FFFFFF" fill-opacity="1"/></mask><clipPath id="master_svg1_88_35666"><rect x="7" y="7" width="27" height="27" rx="0"/></clipPath><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg2_88_26531"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"/><stop offset="98.57142567634583%" stop-color="#F0FBFF" stop-opacity="1"/></linearGradient><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg3_88_26531"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"/><stop offset="98.57142567634583%" stop-color="#F0FBFF" stop-opacity="1"/></linearGradient></defs><g mask="url(#master_svg0_88_35670)"><ellipse cx="20" cy="20" rx="20" ry="20" fill="#8000FF" fill-opacity="1"/><g clip-path="url(#master_svg1_88_35666)"><path d="M21.175671875,27.58515925L14.263672875000001,27.58515925C13.750673275,27.58515925,13.426672974999999,27.24765625,13.426672974999999,26.74815725C13.426672974999999,26.23515525,13.764173075,25.911160250000002,14.263672875000001,25.911160250000002L21.351173875,25.911160250000002C21.688676875,24.89865825,22.188173875,23.88615425,22.863174875,23.211156250000002L14.263672875000001,23.211156250000002C13.750673275,23.211156250000002,13.426672974999999,22.87365525,13.426672974999999,22.37415225C13.426672974999999,21.87465325,13.764173075,21.537155249999998,14.263672875000001,21.537155249999998L25.738675875,21.537155249999998C26.251674875,21.37515325,26.751174875,21.37515325,27.088676875,21.37515325C28.438678875,21.37515325,29.626676875,21.88815525,30.625678875,22.549656249999998L30.625678875,13.072656349999999C30.625678875,11.38515625,29.275674875,10.03515625,27.588174875,10.03515625L27.075177875,10.03515625L27.075177875,13.24815675C27.075177875,14.935656550000001,25.725173875,16.285657450000002,24.037676875000002,16.285657450000002L16.113174475,16.285657450000002C14.425674475000001,16.272157149999998,13.075673375000001,14.922158249999999,13.075673375000001,13.23465635L13.075673375000001,10.03515625L12.238672475,10.03515625C10.551171974999999,10.03515625,9.201171875,11.38515625,9.201171875,13.072656349999999L9.201171875,29.94765825C9.201171875,31.63515625,10.551171974999999,32.985161250000004,12.238672475,32.985161250000004L25.576673875,32.985161250000004C23.200674875,32.485662250000004,21.337675875000002,30.28515825,21.175671875,27.58515925Z" fill="url(#master_svg2_88_26531)" fill-opacity="1" style="mix-blend-mode:passthrough"/><path d="M16.1124145625,14.764538762499999L24.0504169625,14.764538762499999C24.8874170625,14.764538762499999,25.5624140625,14.0895385625,25.5624140625,13.252537762500001L25.5624140625,10.0395388625L22.5249171625,10.0395388625C22.3629159625,8.8650390625,21.3369150625,7.8525390625,19.986915562500002,7.8525390625C18.7989153625,7.8525390625,17.7864150625,8.8650390625,17.6244149625,10.0395388625L14.5869140625,10.0395388625L14.5869140625,13.252537762500001C14.5869140625,14.0895385625,15.2619143725,14.764538762499999,16.1124145625,14.764538762499999ZM30.7869150625,24.3900370625C29.9499160625,23.3775360625,28.5999220625,22.7025380625,27.2499170625,22.7025380625L26.412916062500003,22.7025380625C25.8999180625,22.7025380625,25.5759160625,22.8780390625,25.0629190625,23.2155400625C24.0504169625,23.7285370625,23.1999158625,24.7275330625,22.700415562499998,25.9155390625C22.5384173625,26.4285390625,22.5384173625,26.9280380625,22.5384173625,27.4275380625L22.5384173625,27.5895390625C22.700415562499998,30.1275410625,24.7254170625,31.9770390625,27.1014200625,31.9770390625C28.4514180625,31.9770390625,29.8014230625,31.3020400625,30.6384180625,30.2895320625C31.3134210625,29.4525340625,31.6509170625,28.4265380625,31.6509170625,27.2520330625C31.8129160625,26.2395310625,31.2999250625,25.2270370625,30.7869150625,24.3900370625ZM29.7879200625,26.5770380625L27.0879160625,29.2770390625C26.7504160625,29.6145400625,26.412916062500003,29.6145400625,26.0754160625,29.2770390625L24.387915562499998,27.5895390625C24.0504169625,27.2520370625,24.0504169625,26.9145390625,24.387915562499998,26.5770380625C24.725415062499998,26.2395380625,25.0629150625,26.2395400625,25.4004160625,26.5770380625L26.2374170625,27.4140400625L26.5749150625,27.7515370625L28.7619150625,25.5645350625C29.0994140625,25.2270370625,29.4369190625,25.2270370625,29.774416062500002,25.5645350625C30.1119160625,25.9020370625,30.1119160625,26.2395380625,29.7879200625,26.5770380625Z" fill="url(#master_svg3_88_26531)" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg> |
| | |
| | | </div> |
| | | |
| | | <!-- æé® --> |
| | | <div v-else-if="item.dataType == 'action'"> |
| | | <div v-else-if="item.dataType == 'action'" @click.stop> |
| | | <template v-for="(o, key) in item.operation" :key="key"> |
| | | <el-button |
| | | v-show="o.type != 'upload'" |
| | |
| | | : o.color, |
| | | }" |
| | | link |
| | | @click="o.clickFun(scope.row)" |
| | | @click.stop="o.clickFun(scope.row)" |
| | | :key="key" |
| | | > |
| | | {{ o.name }} |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="dialogVisible" title="éä»¶" width="40%" :before-close="handleClose"> |
| | | <el-table :data="tableData" border height="40vh"> |
| | | <el-table-column label="éä»¶åç§°" prop="name" min-width="400" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">ä¸è½½</el-button> |
| | | <el-button link type="primary" size="small" @click="lookFile(scope.row)">é¢è§</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-dialog> |
| | | <filePreview ref="filePreviewRef" /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | import filePreview from '@/components/filePreview/index.vue' |
| | | |
| | | const dialogVisible = ref(false) |
| | | const tableData = ref([]) |
| | | const { proxy } = getCurrentInstance(); |
| | | const filePreviewRef = ref() |
| | | const handleClose = () => { |
| | | dialogVisible.value = false |
| | | } |
| | | const open = (list) => { |
| | | dialogVisible.value = true |
| | | tableData.value = list |
| | | } |
| | | const downLoadFile = (row) => { |
| | | proxy.$download.name(row.url); |
| | | |
| | | } |
| | | const lookFile = (row) => { |
| | | filePreviewRef.value.open(row.url) |
| | | } |
| | | defineExpose({ |
| | | open |
| | | }) |
| | | </script> |
| | | |
| | | <style></style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">éå®ååå·ï¼</span> |
| | | <el-input |
| | | v-model="searchForm.salesContractNo" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥éå®ååå·æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | /> |
| | | <span class="search_title ml10">审æ¹ç¶æï¼</span> |
| | | <el-select v-model="searchForm.approveStatus" clearable @change="handleQuery" style="width: 240px"> |
| | | <el-option label="å¾
å®¡æ ¸" :value="2" /> |
| | | <el-option label="å®¡æ ¸æå" :value="3" /> |
| | | <el-option label="å®¡æ ¸å¤±è´¥" :value="4" /> |
| | | </el-select> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px" |
| | | >æç´¢</el-button |
| | | > |
| | | </div> |
| | | <div> |
| | | <!-- <el-button type="primary" @click="openForm('add')">æ°å¢</el-button>--> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <!-- <el-button type="danger" plain @click="handleDelete">å é¤</el-button>--> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :total="page.total" |
| | | ></PIMTable> |
| | | </div> |
| | | <info-form-dia ref="infoFormDia" @close="handleQuery" :approveType="approveType"></info-form-dia> |
| | | <approval-dia ref="approvalDia" @close="handleQuery"></approval-dia> |
| | | <FileList ref="fileListRef" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import FileList from "./fileList.vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import {onMounted, ref} from "vue"; |
| | | import {ElMessageBox} from "element-plus"; |
| | | import InfoFormDia from "@/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue"; |
| | | import ApprovalDia from "@/views/collaborativeApproval/approvalProcess/components/approvalDia.vue"; |
| | | import {getShipmentApprovalList, approveShipment} from "@/api/collaborativeApproval/shipmentReview.js"; |
| | | // import {approveProcessDelete, approveProcessListPage} from "@/api/collaborativeApproval/approvalProcess.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | |
| | | // å®ä¹ç»ä»¶æ¥æ¶çprops |
| | | const props = defineProps({ |
| | | approveType: { |
| | | type: [Number, String], |
| | | default: 6 |
| | | } |
| | | }); |
| | | |
| | | const userList = ref([]); |
| | | |
| | | const userStore = useUserStore(); |
| | | |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | approveId: "", |
| | | approveStatus: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "审æ¹ç¶æ", |
| | | prop: "approveStatus", |
| | | dataType: "tag", |
| | | width: 100, |
| | | formatData: (params) => { |
| | | if (params === 2) { |
| | | return "å¾
å®¡æ ¸"; |
| | | } else if (params === 3) { |
| | | return "å®¡æ ¸å®æ"; |
| | | } else if (params === 4) { |
| | | return "å®¡æ ¸é©³å"; |
| | | } else { |
| | | return 'æªç¥ç¶æ'; |
| | | } |
| | | }, |
| | | formatType: (params) => { |
| | | if (params === 0) { |
| | | return "warning"; |
| | | } else if (params === 2) { |
| | | return "info"; |
| | | } else if (params === 3) { |
| | | return "success"; |
| | | } else if (params === 4) { |
| | | return "danger"; |
| | | } else { |
| | | return 'danger'; |
| | | } |
| | | }, |
| | | }, |
| | | { |
| | | label: "éå®ååå·", |
| | | prop: "salesContractNo", |
| | | width: 170 |
| | | }, |
| | | { |
| | | label: "客æ·åç§°", |
| | | prop: "customerName", |
| | | width: 200 |
| | | }, |
| | | { |
| | | label: "产å大类", |
| | | prop: "productCategory", |
| | | width: 200 |
| | | }, |
| | | { |
| | | label: "è§æ ¼åå·", |
| | | prop: "specificationModel", |
| | | width: 220 |
| | | }, |
| | | { |
| | | label: "ç³è¯·äºº", |
| | | prop: "approveUserId", |
| | | width: 120, |
| | | align: "center", |
| | | formatData:(params)=>{ |
| | | const user = userList.value.find(item => item.userId === params) |
| | | return user ? user.nickName : '--' |
| | | } |
| | | }, |
| | | { |
| | | label: "车çå·", |
| | | prop: "shippingCarNumber", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "ç³è¯·äºº", |
| | | prop: "approveUserId", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "ç³è¯·æ¥æ", |
| | | prop: "executionDate", |
| | | width: 200 |
| | | }, |
| | | { |
| | | label: "å½å审æ¹äºº", |
| | | prop: "salesman", |
| | | width: 120 |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 120, |
| | | operation: [ |
| | | { |
| | | name: "éè¿", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | handleApproval("éè¿", row); |
| | | }, |
| | | disabled: (row) => row.approveStatus !== 2 |
| | | }, |
| | | { |
| | | name: "驳å", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | handleApproval("驳å", row); |
| | | }, |
| | | disabled: (row) => row.approveStatus !== 2 |
| | | }, |
| | | // { |
| | | // name: "ç¼è¾", |
| | | // type: "text", |
| | | // clickFun: (row) => { |
| | | // openForm("edit", row); |
| | | // }, |
| | | // disabled: (row) => row.approveStatus == 2 || row.approveStatus == 1 || row.approveStatus == 4 |
| | | // }, |
| | | // { |
| | | // name: "å®¡æ ¸", |
| | | // type: "text", |
| | | // clickFun: (row) => { |
| | | // openApprovalDia("approval", row); |
| | | // }, |
| | | // disabled: (row) => row.approveUserCurrentId == null || row.approveStatus == 2 || row.approveStatus == 3 || row.approveStatus == 4 || row.approveUserCurrentId !== userStore.id |
| | | // }, |
| | | // { |
| | | // name: "详æ
", |
| | | // type: "text", |
| | | // clickFun: (row) => { |
| | | // openApprovalDia('view', row); |
| | | // }, |
| | | // }, |
| | | // { |
| | | // name: "éä»¶", |
| | | // type: "text", |
| | | // clickFun: (row) => { |
| | | // downLoadFile(row); |
| | | // }, |
| | | // }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0 |
| | | }); |
| | | const infoFormDia = ref() |
| | | const approvalDia = ref() |
| | | const { proxy } = getCurrentInstance() |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const fileListRef = ref(null) |
| | | const downLoadFile = (row) => { |
| | | fileListRef.value.open(row.commonFileList) |
| | | |
| | | } |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList =async () => { |
| | | let userLists = await userListNoPage(); |
| | | userList.value = userLists.data; |
| | | tableLoading.value = true; |
| | | getShipmentApprovalList({...page, ...searchForm.value,approveType:props.approveType}).then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records |
| | | page.total = res.data.total; |
| | | }).catch(err => { |
| | | tableLoading.value = false; |
| | | }) |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | const type = Number(props.approveType || 6) |
| | | const urlMap = { |
| | | 0: "/shipmentApproval/export", |
| | | } |
| | | const url = urlMap[type] || urlMap[0] |
| | | const nameMap = { |
| | | 0: "åè´§å®¡æ ¸è¡¨", |
| | | } |
| | | const fileName = nameMap[type] || nameMap[0] |
| | | proxy.download(url, {}, `${fileName}.xlsx`) |
| | | } |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | // æå¼æ°å¢ãç¼è¾å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | nextTick(() => { |
| | | infoFormDia.value?.openDialog(type, row) |
| | | }) |
| | | }; |
| | | // æå¼æ°å¢æ£éªå¼¹æ¡ |
| | | const openApprovalDia = (type, row) => { |
| | | nextTick(() => { |
| | | approvalDia.value?.openDialog(type, row) |
| | | }) |
| | | }; |
| | | |
| | | // å®¡æ ¸éè¿/驳å |
| | | const handleApproval = (name = "å®¡æ ¸",row) => { |
| | | ElMessageBox.confirm(`éä¸çå
容å°è¢«${name}ï¼æ¯å¦ç¡®è®¤${name}ï¼`, "æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(async()=>{ |
| | | let res = await approveShipment({ |
| | | id: row.id, |
| | | approveStatus: name === "éè¿" ? 3 : 4 |
| | | }); |
| | | if(res.code === 200){ |
| | | proxy.$modal.msgSuccess(`${name}æå`); |
| | | }else{ |
| | | proxy.$modal.msgError(`${name}失败`); |
| | | } |
| | | await getList() |
| | | }).catch(err=>{ |
| | | proxy.$modal.msgError(`æªç¥é误,请è系管çå`); |
| | | }) |
| | | }; |
| | | |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map((item) => item.approveId); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | approveProcessDelete(ids).then((res) => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped></style> |
| | |
| | | <el-input v-model="form.model" placeholder="请è¾å
¥" clearable/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ææ éæ©ï¼" prop="testStandardId"> |
| | | <el-select |
| | | v-model="form.testStandardId" |
| | | placeholder="è¯·éæ©ææ " |
| | | clearable |
| | | @change="handleTestStandardChange" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in testStandardOptions" |
| | | :key="item.id" |
| | | :label="item.standardName || item.standardNo" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref} from "vue"; |
| | | import {ref, reactive, toRefs, getCurrentInstance, nextTick} from "vue"; |
| | | import {getOptions} from "@/api/procurementManagement/procurementLedger.js"; |
| | | import {productTreeList} from "@/api/basicData/product.js"; |
| | | import {qualityInspectAdd, qualityInspectUpdate} from "@/api/qualityManagement/rawMaterialInspection.js"; |
| | | import {userListNoPage} from "@/api/system/user.js"; |
| | | import {qualityInspectDetailByProductId} from "@/api/qualityManagement/metricMaintenance.js"; |
| | | import {qualityInspectDetailByProductId, getQualityTestStandardParamByTestStandardId} from "@/api/qualityManagement/metricMaintenance.js"; |
| | | import {qualityInspectParamInfo} from "@/api/qualityManagement/qualityInspectParam.js"; |
| | | const { proxy } = getCurrentInstance() |
| | | const emit = defineEmits(['close']) |
| | |
| | | productName: "", |
| | | productId: "", |
| | | model: "", |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | checkCompany: "", |
| | |
| | | checkName: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | productId: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | model: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | testStandardId: [{required: true, message: "è¯·éæ©ææ ", trigger: "change"}], |
| | | unit: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkCompany: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | |
| | | const tableLoading = ref(false); |
| | | const userList = ref([]); |
| | | const currentProductId = ref(0); |
| | | const testStandardOptions = ref([]); // ææ éæ©ä¸ææ¡æ°æ® |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = async (type, row) => { |
| | |
| | | let userLists = await userListNoPage(); |
| | | userList.value = userLists.data; |
| | | form.value = {} |
| | | testStandardOptions.value = []; |
| | | tableData.value = []; |
| | | getProductOptions(); |
| | | if (operationType.value === 'edit') { |
| | | form.value = {...row} |
| | | // å
ä¿å testStandardIdï¼é¿å
被æ¸
空 |
| | | const savedTestStandardId = row.testStandardId; |
| | | // å
è®¾ç½®è¡¨åæ°æ®ï¼ä½ææ¶æ¸
空 testStandardIdï¼çé项å è½½å®æåå设置 |
| | | form.value = {...row, testStandardId: ''} |
| | | currentProductId.value = row.productId || 0 |
| | | getQualityInspectParamList(row.id) |
| | | // ç¼è¾æ¨¡å¼ä¸ï¼å
å è½½ææ é项ï¼ç¶åå è½½åæ°å表 |
| | | if (currentProductId.value) { |
| | | // å
å è½½ææ é项 |
| | | let params = { |
| | | productId: currentProductId.value, |
| | | inspectType: 2 |
| | | } |
| | | qualityInspectDetailByProductId(params).then(res => { |
| | | testStandardOptions.value = res.data || []; |
| | | // ä½¿ç¨ nextTick å setTimeout ç¡®ä¿éé¡¹å·²ç»æ¸²æå° DOM |
| | | nextTick(() => { |
| | | setTimeout(() => { |
| | | // 妿ç¼è¾æ°æ®ä¸æ testStandardIdï¼å设置并å 载对åºçåæ° |
| | | if (savedTestStandardId) { |
| | | // ç¡®ä¿ç±»åå¹é
ï¼item.id å¯è½æ¯æ°åæåç¬¦ä¸²ï¼ |
| | | const matchedOption = testStandardOptions.value.find(item => |
| | | item.id == savedTestStandardId || String(item.id) === String(savedTestStandardId) |
| | | ); |
| | | if (matchedOption) { |
| | | // ç¡®ä¿ä½¿ç¨å¹é
项ç idï¼ä¿æç±»åä¸è´ï¼ |
| | | form.value.testStandardId = matchedOption.id; |
| | | console.log(22222,form.value.testStandardId); |
| | | handleTestStandardChange(matchedOption.id); |
| | | } else { |
| | | // 妿æ¾ä¸å°å¹é
项ï¼å°è¯ç´æ¥ä½¿ç¨åå¼ |
| | | console.warn('æªæ¾å°å¹é
çææ é项ï¼testStandardId:', savedTestStandardId, 'å¯ç¨é项:', testStandardOptions.value); |
| | | form.value.testStandardId = savedTestStandardId; |
| | | handleTestStandardChange(savedTestStandardId); |
| | | } |
| | | } else { |
| | | // å¦åä½¿ç¨æ§çé»è¾ |
| | | getQualityInspectParamList(row.id); |
| | | } |
| | | }, 100); |
| | | }); |
| | | }); |
| | | } else { |
| | | getQualityInspectParamList(row.id); |
| | | } |
| | | } |
| | | } |
| | | const getProductOptions = () => { |
| | |
| | | const getModels = (value) => { |
| | | currentProductId.value = value |
| | | form.value.productName = findNodeById(productOptions.value, value); |
| | | if (currentProductId) { |
| | | if (currentProductId.value) { |
| | | getList(); |
| | | } |
| | | }; |
| | |
| | | }) |
| | | } |
| | | const getList = () => { |
| | | qualityInspectDetailByProductId(currentProductId.value).then(res => { |
| | | tableData.value = res.data; |
| | | if (!currentProductId.value) { |
| | | testStandardOptions.value = []; |
| | | tableData.value = []; |
| | | return; |
| | | } |
| | | let params = { |
| | | productId: currentProductId.value, |
| | | inspectType: 2 |
| | | } |
| | | qualityInspectDetailByProductId(params).then(res => { |
| | | // ä¿å䏿æ¡éé¡¹æ°æ® |
| | | testStandardOptions.value = res.data || []; |
| | | // æ¸
ç©ºè¡¨æ ¼æ°æ®ï¼çå¾
ç¨æ·éæ©ææ |
| | | tableData.value = []; |
| | | // æ¸
ç©ºææ éæ© |
| | | form.value.testStandardId = ''; |
| | | }) |
| | | } |
| | | |
| | | // ææ éæ©ååå¤ç |
| | | const handleTestStandardChange = (testStandardId) => { |
| | | if (!testStandardId) { |
| | | tableData.value = []; |
| | | return; |
| | | } |
| | | tableLoading.value = true; |
| | | getQualityTestStandardParamByTestStandardId(testStandardId).then(res => { |
| | | tableData.value = res.data || []; |
| | | }).catch(error => { |
| | | console.error('è·åæ ååæ°å¤±è´¥:', error); |
| | | tableData.value = []; |
| | | }).finally(() => { |
| | | tableLoading.value = false; |
| | | }) |
| | | } |
| | | const getQualityInspectParamList = (id) => { |
| | | qualityInspectParamInfo(id).then(res => { |
| | |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | tableData.value = []; |
| | | testStandardOptions.value = []; |
| | | form.value.testStandardId = ''; |
| | | dialogFormVisible.value = false; |
| | | emit('close') |
| | | }; |
| | |
| | | :isSelection="false" |
| | | :rowClassName="rowClassNameCenter" |
| | | :tableLoading="tableLoading" |
| | | :rowClick="handleTableRowClick" |
| | | @pagination="handlePagination" |
| | | :total="page.total" |
| | | > |
| | |
| | | } |
| | | |
| | | const standardColumns = ref([ |
| | | { label: 'æ åç¼å·', prop: 'standardNo', dataType: 'slot', slot: 'standardNoCell', minWidth: 160, headerSlot: 'standardNoHeader' }, |
| | | { label: 'æ ååç§°', prop: 'standardName', minWidth: 180, headerSlot: 'standardNameHeader' }, |
| | | { label: 'æ åç¼å·', prop: 'standardNo', dataType: 'slot', slot: 'standardNoCell', minWidth: 160, align: 'center', headerSlot: 'standardNoHeader' }, |
| | | { label: 'æ ååç§°', prop: 'standardName', minWidth: 180, align: 'center', headerSlot: 'standardNameHeader' }, |
| | | { |
| | | label: 'ç±»å«', |
| | | prop: 'inspectType', |
| | | headerSlot: 'inspectTypeHeader', |
| | | align: 'center', |
| | | dataType: 'tag', |
| | | formatData: (val) => { |
| | | const map = { 0: 'åæææ£éª', 1: 'è¿ç¨æ£éª', 2: 'åºåæ£éª' } |
| | |
| | | { |
| | | label: 'å·¥åº', |
| | | prop: 'processId', |
| | | align: 'center', |
| | | dataType: 'tag', |
| | | formatData: (val) => { |
| | | const target = processOptions.value.find( |
| | |
| | | { |
| | | label: '夿³¨', |
| | | prop: 'remark', |
| | | minWidth: 160 |
| | | minWidth: 160, |
| | | align: 'center' |
| | | } |
| | | // { |
| | | // label: 'ç¶æ', |
| | |
| | | }) |
| | | } |
| | | |
| | | // è¡¨æ ¼è¡ç¹å»ï¼å è½½å³ä¾§ç»å®å表 |
| | | const handleTableRowClick = (row) => { |
| | | currentStandard.value = row |
| | | loadBindingList() |
| | | } |
| | | |
| | | // 左侧è¡ç¹å»ï¼å è½½å³ä¾§ç»å®å表ï¼ä¿çç¨äºæ åç¼å·åçç¹å»ï¼ |
| | | const handleStandardRowClick = (row) => { |
| | | currentStandard.value = row |
| | | loadBindingList() |
| | |
| | | :deep(.center-table .el-table__body-wrapper td .cell) { |
| | | text-align: center !important; |
| | | } |
| | | |
| | | /* PIMTable 表头å±
ä¸ */ |
| | | :deep(.lims-table .pim-table-header-cell) { |
| | | text-align: center; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | :deep(.lims-table .pim-table-header-title) { |
| | | text-align: center; |
| | | width: 100%; |
| | | } |
| | | |
| | | :deep(.lims-table .pim-table-header-extra) { |
| | | width: 100%; |
| | | margin-top: 4px; |
| | | } |
| | | </style> |
| | |
| | | :isSelection="true" |
| | | :tableLoading="tableLoading" |
| | | :rowClassName="rowClassNameCenter" |
| | | :rowClick="handleTableRowClick" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="handlePagination" |
| | | :total="page.total" |
| | |
| | | standardNo: [{ required: true, message: '请è¾å
¥æ åç¼å·', trigger: 'blur' }], |
| | | standardName: [{ required: true, message: '请è¾å
¥æ ååç§°', trigger: 'blur' }], |
| | | inspectType: [{ required: true, message: 'è¯·éæ©æ£æµç±»å', trigger: 'change' }], |
| | | processId: [{ required: true, message: 'è¯·éæ©å·¥åº', trigger: 'change' }] |
| | | processId: [{ required: false, message: 'è¯·éæ©å·¥åº', trigger: 'change' }] |
| | | } |
| | | }) |
| | | |
| | |
| | | dataType: 'slot', |
| | | slot: 'standardNoCell', |
| | | minWidth: 160, |
| | | align: 'center', |
| | | headerSlot: 'standardNoHeader' |
| | | }, |
| | | { |
| | | label: 'æ ååç§°', |
| | | prop: 'standardName', |
| | | minWidth: 180, |
| | | align: 'center', |
| | | headerSlot: 'standardNameHeader' |
| | | }, |
| | | { |
| | | label: 'ç±»å«', |
| | | prop: 'inspectType', |
| | | headerSlot: 'inspectTypeHeader', |
| | | align: 'center', |
| | | dataType: 'tag', |
| | | formatData: (val) => { |
| | | const map = { |
| | |
| | | { |
| | | label: 'å·¥åº', |
| | | prop: 'processId', |
| | | align: 'center', |
| | | dataType: 'tag', |
| | | formatData: (val) => { |
| | | const target = processOptions.value.find( |
| | |
| | | label: 'ç¶æ', |
| | | prop: 'state', |
| | | headerSlot: 'stateHeader', |
| | | align: 'center', |
| | | dataType: 'tag', |
| | | formatData: (val) => { |
| | | const map = { |
| | |
| | | { |
| | | label: '夿³¨', |
| | | prop: 'remark', |
| | | minWidth: 160 |
| | | minWidth: 160, |
| | | align: 'center' |
| | | }, |
| | | { |
| | | dataType: 'action', |
| | |
| | | getStandardList() |
| | | } |
| | | |
| | | // 左侧è¡ç¹å»ï¼å è½½å³ä¾§åæ° |
| | | // è¡¨æ ¼è¡ç¹å»ï¼å è½½å³ä¾§åæ° |
| | | const handleTableRowClick = (row) => { |
| | | currentStandard.value = row |
| | | loadDetail(row.id) |
| | | } |
| | | |
| | | // 左侧è¡ç¹å»ï¼å è½½å³ä¾§åæ°ï¼ä¿çç¨äºæ åç¼å·åçç¹å»ï¼ |
| | | const handleStandardRowClick = (row) => { |
| | | currentStandard.value = row |
| | | loadDetail(row.id) |
| | |
| | | processId: '' |
| | | }) |
| | | } else if (type === 'edit' && row) { |
| | | Object.assign(standardForm.value, row) |
| | | Object.assign(standardForm.value, { |
| | | ...row, |
| | | // ç¡®ä¿ inspectType å state 转æ¢ä¸ºå符串ï¼ä»¥å¹é
el-select ç value ç±»å |
| | | inspectType: row.inspectType !== null && row.inspectType !== undefined ? String(row.inspectType) : '', |
| | | state: row.state !== null && row.state !== undefined ? String(row.state) : '0', |
| | | // ç¡®ä¿ processId 转æ¢ä¸ºåç¬¦ä¸²ææ°åï¼æ ¹æ®å®é
éè¦ï¼ |
| | | processId: row.processId !== null && row.processId !== undefined ? row.processId : '' |
| | | }) |
| | | } else if (type === 'copy' && row) { |
| | | const { id, ...rest } = row |
| | | Object.assign(standardForm.value, { |
| | | ...rest, |
| | | id: undefined, |
| | | standardNo: '', |
| | | state: '0' |
| | | state: '0', |
| | | // ç¡®ä¿ inspectType 转æ¢ä¸ºå符串 |
| | | inspectType: rest.inspectType !== null && rest.inspectType !== undefined ? String(rest.inspectType) : '' |
| | | }) |
| | | } |
| | | standardDialogVisible.value = true |
| | |
| | | .metric-maintenance { |
| | | display: flex; |
| | | gap: 16px; |
| | | min-width: 0; /* å
许 flex åå
ç´ æ¶ç¼© */ |
| | | } |
| | | |
| | | .left-panel, |
| | | .right-panel { |
| | | flex: 1; |
| | | min-width: 0; /* å
许 flex åå
ç´ æ¶ç¼© */ |
| | | background: #ffffff; |
| | | padding: 16px; |
| | | box-sizing: border-box; |
| | | overflow: hidden; /* 鲿¢å
å®¹æº¢åº */ |
| | | } |
| | | |
| | | /* ä½å辨çéé
*/ |
| | | @media (max-width: 1400px) { |
| | | .metric-maintenance { |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .left-panel, |
| | | .right-panel { |
| | | width: 100%; |
| | | min-width: 0; |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .metric-maintenance { |
| | | gap: 12px; |
| | | } |
| | | |
| | | .left-panel, |
| | | .right-panel { |
| | | padding: 12px; |
| | | } |
| | | } |
| | | |
| | | .toolbar { |
| | |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .toolbar-left { |
| | |
| | | |
| | | .toolbar-right { |
| | | flex-shrink: 0; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .search-label { |
| | |
| | | :deep(.center-table .el-table__body-wrapper td .cell) { |
| | | text-align: center !important; |
| | | } |
| | | |
| | | /* PIMTable 表头å±
ä¸ */ |
| | | :deep(.lims-table .pim-table-header-cell) { |
| | | text-align: center; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | :deep(.lims-table .pim-table-header-title) { |
| | | text-align: center; |
| | | width: 100%; |
| | | } |
| | | |
| | | :deep(.lims-table .pim-table-header-extra) { |
| | | width: 100%; |
| | | margin-top: 4px; |
| | | } |
| | | </style> |
| | |
| | | <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å·¥åºï¼" prop="process"> |
| | | <el-input v-model="form.process" placeholder="请è¾å
¥" clearable/> |
| | | <el-form-item label="å·¥åºï¼" prop="processId"> |
| | | <el-select |
| | | v-model="form.processId" |
| | | placeholder="è¯·éæ©å·¥åº" |
| | | clearable |
| | | @change="handleProcessChange" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in processOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="è§æ ¼åå·ï¼" prop="model"> |
| | | <el-input v-model="form.model" placeholder="请è¾å
¥" clearable/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ææ éæ©ï¼" prop="testStandardId"> |
| | | <el-select |
| | | v-model="form.testStandardId" |
| | | placeholder="è¯·éæ©ææ " |
| | | clearable |
| | | @change="handleTestStandardChange" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in testStandardOptions" |
| | | :key="item.id" |
| | | :label="item.standardName || item.standardNo" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref} from "vue"; |
| | | import {ref, reactive, toRefs, getCurrentInstance, nextTick} from "vue"; |
| | | import {getOptions} from "@/api/procurementManagement/procurementLedger.js"; |
| | | import {productTreeList} from "@/api/basicData/product.js"; |
| | | import {productProcessListPage} from "@/api/basicData/productProcess.js"; |
| | | import {qualityInspectAdd, qualityInspectUpdate} from "@/api/qualityManagement/rawMaterialInspection.js"; |
| | | import {qualityInspectDetailByProductId} from "@/api/qualityManagement/metricMaintenance.js"; |
| | | import {qualityInspectDetailByProductId, getQualityTestStandardParamByTestStandardId} from "@/api/qualityManagement/metricMaintenance.js"; |
| | | import {userListNoPage} from "@/api/system/user.js"; |
| | | import {qualityInspectParamInfo} from "@/api/qualityManagement/qualityInspectParam.js"; |
| | | const { proxy } = getCurrentInstance() |
| | |
| | | const data = reactive({ |
| | | form: { |
| | | checkTime: "", |
| | | process: "", |
| | | processId: "", |
| | | checkName: "", |
| | | productName: "", |
| | | productId: "", |
| | | model: "", |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | checkCompany: "", |
| | |
| | | }, |
| | | rules: { |
| | | checkTime: [{ required: true, message: "请è¾å
¥", trigger: "blur" },], |
| | | process: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | processId: [{ required: true, message: "è¯·éæ©å·¥åº", trigger: "change" }], |
| | | checkName: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | productId: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | model: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | testStandardId: [{required: true, message: "è¯·éæ©ææ ", trigger: "change"}], |
| | | unit: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkCompany: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const currentProductId = ref(0); |
| | | const processOptions = ref([]); // å·¥åºä¸ææ¡æ°æ® |
| | | const testStandardOptions = ref([]); // ææ éæ©ä¸ææ¡æ°æ® |
| | | |
| | | // è·åå·¥åºå表 |
| | | const getProcessList = async () => { |
| | | try { |
| | | const res = await productProcessListPage({ current: 1, size: 1000 }) |
| | | if (res?.code === 200) { |
| | | const records = res?.data?.records || [] |
| | | processOptions.value = records.map(item => ({ |
| | | label: item.processName || item.name || item.label, |
| | | value: item.id || item.processId || item.value |
| | | })) |
| | | } |
| | | } catch (error) { |
| | | console.error('è·åå·¥åºå表失败:', error) |
| | | } |
| | | } |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = async (type, row) => { |
| | |
| | | let userLists = await userListNoPage(); |
| | | userList.value = userLists.data; |
| | | form.value = {} |
| | | testStandardOptions.value = []; |
| | | tableData.value = []; |
| | | getProductOptions(); |
| | | // å
å 载工åºå表 |
| | | await getProcessList(); |
| | | if (operationType.value === 'edit') { |
| | | form.value = {...row} |
| | | // å
ä¿å testStandardIdï¼é¿å
被æ¸
空 |
| | | const savedTestStandardId = row.testStandardId; |
| | | // å
è®¾ç½®è¡¨åæ°æ®ï¼ä½ææ¶æ¸
空 testStandardIdï¼çé项å è½½å®æåå设置 |
| | | form.value = {...row, testStandardId: ''} |
| | | // å
¼å®¹æ§æ°æ®ï¼å¦æ row 䏿 process åæ®µï¼è½¬æ¢ä¸º processId |
| | | if (row.process && !row.processId) { |
| | | // å°è¯ä» processOptions 䏿¥æ¾å¹é
çå·¥åº |
| | | const processOption = processOptions.value.find(p => p.label === row.process); |
| | | if (processOption) { |
| | | form.value.processId = processOption.value; |
| | | } |
| | | } |
| | | currentProductId.value = row.productId || 0 |
| | | getQualityInspectParamList(row.id) |
| | | // ç¼è¾æ¨¡å¼ä¸ï¼å
å è½½ææ é项ï¼ç¶åå è½½åæ°å表 |
| | | if (currentProductId.value) { |
| | | // å
å è½½ææ é项 |
| | | let params = { |
| | | productId: currentProductId.value, |
| | | inspectType: 1, |
| | | process: form.value.processId ? processOptions.value.find(p => p.value === form.value.processId)?.label : '' |
| | | } |
| | | qualityInspectDetailByProductId(params).then(res => { |
| | | testStandardOptions.value = res.data || []; |
| | | // ä½¿ç¨ nextTick å setTimeout ç¡®ä¿éé¡¹å·²ç»æ¸²æå° DOM |
| | | nextTick(() => { |
| | | setTimeout(() => { |
| | | // 妿ç¼è¾æ°æ®ä¸æ testStandardIdï¼å设置并å 载对åºçåæ° |
| | | if (savedTestStandardId) { |
| | | // ç¡®ä¿ç±»åå¹é
ï¼item.id å¯è½æ¯æ°åæåç¬¦ä¸²ï¼ |
| | | const matchedOption = testStandardOptions.value.find(item => |
| | | item.id == savedTestStandardId || String(item.id) === String(savedTestStandardId) |
| | | ); |
| | | if (matchedOption) { |
| | | // ç¡®ä¿ä½¿ç¨å¹é
项ç idï¼ä¿æç±»åä¸è´ï¼ |
| | | form.value.testStandardId = matchedOption.id; |
| | | handleTestStandardChange(matchedOption.id); |
| | | } else { |
| | | // 妿æ¾ä¸å°å¹é
项ï¼å°è¯ç´æ¥ä½¿ç¨åå¼ |
| | | console.warn('æªæ¾å°å¹é
çææ é项ï¼testStandardId:', savedTestStandardId, 'å¯ç¨é项:', testStandardOptions.value); |
| | | form.value.testStandardId = savedTestStandardId; |
| | | handleTestStandardChange(savedTestStandardId); |
| | | } |
| | | } else { |
| | | // å¦åä½¿ç¨æ§çé»è¾ |
| | | getQualityInspectParamList(row.id); |
| | | } |
| | | }, 100); |
| | | }); |
| | | }); |
| | | } else { |
| | | getQualityInspectParamList(row.id); |
| | | } |
| | | } |
| | | } |
| | | const getProductOptions = () => { |
| | |
| | | const getModels = (value) => { |
| | | currentProductId.value = value |
| | | form.value.productName = findNodeById(productOptions.value, value); |
| | | if (currentProductId) { |
| | | if (currentProductId.value) { |
| | | getList(); |
| | | } |
| | | }; |
| | |
| | | return newItem; |
| | | }); |
| | | } |
| | | // å·¥åºååå¤ç |
| | | const handleProcessChange = () => { |
| | | // å·¥åºååæ¶ï¼å¦æå·²éæ©äº§åï¼éæ°å è½½ææ å表 |
| | | if (currentProductId.value) { |
| | | getList(); |
| | | } |
| | | } |
| | | |
| | | // æäº¤äº§å表å |
| | | const submitForm = () => { |
| | | proxy.$refs.formRef.validate(valid => { |
| | | if (valid) { |
| | | form.value.inspectType = 1 |
| | | // å° processId 转æ¢ä¸º process åç§°ï¼å¦æå端éè¦ process åæ®µï¼ |
| | | const processName = form.value.processId ? processOptions.value.find(p => p.value === form.value.processId)?.label : ''; |
| | | if (operationType.value === "add") { |
| | | tableData.value.forEach((item) => { |
| | | delete item.id |
| | | }) |
| | | } |
| | | const data = {...form.value, qualityInspectParams: tableData.value} |
| | | const data = { |
| | | ...form.value, |
| | | process: processName, // ä¿ç process åæ®µä»¥å
¼å®¹å端 |
| | | qualityInspectParams: tableData.value |
| | | } |
| | | if (operationType.value === "add") { |
| | | qualityInspectAdd(data).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | |
| | | }) |
| | | } |
| | | const getList = () => { |
| | | qualityInspectDetailByProductId(currentProductId.value).then(res => { |
| | | tableData.value = res.data; |
| | | if (!currentProductId.value) { |
| | | testStandardOptions.value = []; |
| | | tableData.value = []; |
| | | return; |
| | | } |
| | | // è·åå·¥åºåç§° |
| | | const processName = form.value.processId ? processOptions.value.find(p => p.value === form.value.processId)?.label : ''; |
| | | let params = { |
| | | productId: currentProductId.value, |
| | | inspectType: 1, |
| | | process: processName |
| | | } |
| | | qualityInspectDetailByProductId(params).then(res => { |
| | | // ä¿å䏿æ¡éé¡¹æ°æ® |
| | | testStandardOptions.value = res.data || []; |
| | | // æ¸
ç©ºè¡¨æ ¼æ°æ®ï¼çå¾
ç¨æ·éæ©ææ |
| | | tableData.value = []; |
| | | // æ¸
ç©ºææ éæ© |
| | | form.value.testStandardId = ''; |
| | | }) |
| | | } |
| | | |
| | | // ææ éæ©ååå¤ç |
| | | const handleTestStandardChange = (testStandardId) => { |
| | | if (!testStandardId) { |
| | | tableData.value = []; |
| | | return; |
| | | } |
| | | tableLoading.value = true; |
| | | getQualityTestStandardParamByTestStandardId(testStandardId).then(res => { |
| | | tableData.value = res.data || []; |
| | | }).catch(error => { |
| | | console.error('è·åæ ååæ°å¤±è´¥:', error); |
| | | tableData.value = []; |
| | | }).finally(() => { |
| | | tableLoading.value = false; |
| | | }) |
| | | } |
| | | const getQualityInspectParamList = (id) => { |
| | |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | tableData.value = []; |
| | | testStandardOptions.value = []; |
| | | form.value.testStandardId = ''; |
| | | dialogFormVisible.value = false; |
| | | emit('close') |
| | | }; |
| | |
| | | <el-input v-model="form.model" placeholder="请è¾å
¥" clearable/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ææ éæ©ï¼" prop="testStandardId"> |
| | | <el-select |
| | | v-model="form.testStandardId" |
| | | placeholder="è¯·éæ©ææ " |
| | | clearable |
| | | @change="handleTestStandardChange" |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="item in testStandardOptions" |
| | | :key="item.id" |
| | | :label="item.standardName || item.standardNo" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref} from "vue"; |
| | | import {ref, reactive, toRefs, getCurrentInstance, nextTick} from "vue"; |
| | | import {getOptions} from "@/api/procurementManagement/procurementLedger.js"; |
| | | import {productTreeList} from "@/api/basicData/product.js"; |
| | | import {qualityInspectAdd, qualityInspectUpdate} from "@/api/qualityManagement/rawMaterialInspection.js"; |
| | | import {ElMessageBox} from "element-plus"; |
| | | import {qualityInspectParamDel, qualityInspectParamInfo} from "@/api/qualityManagement/qualityInspectParam.js"; |
| | | import {qualityInspectDetailByProductId} from "@/api/qualityManagement/metricMaintenance.js"; |
| | | import {qualityInspectDetailByProductId, getQualityTestStandardParamByTestStandardId} from "@/api/qualityManagement/metricMaintenance.js"; |
| | | |
| | | const {proxy} = getCurrentInstance() |
| | | const emit = defineEmits(['close']) |
| | |
| | | productName: "", |
| | | productId: "", |
| | | model: "", |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | checkCompany: "", |
| | |
| | | checkName: [{required: false, message: "请è¾å
¥", trigger: "blur"}], |
| | | productId: [{required: true, message: "请è¾å
¥", trigger: "blur"}], |
| | | model: [{required: false, message: "请è¾å
¥", trigger: "blur"}], |
| | | testStandardId: [{required: true, message: "è¯·éæ©ææ ", trigger: "change"}], |
| | | unit: [{required: false, message: "请è¾å
¥", trigger: "blur"}], |
| | | quantity: [{required: true, message: "请è¾å
¥", trigger: "blur"}], |
| | | checkCompany: [{required: false, message: "请è¾å
¥", trigger: "blur"}], |
| | |
| | | const supplierList = ref([]); |
| | | const productOptions = ref([]); |
| | | const currentProductId = ref(0); |
| | | const testStandardOptions = ref([]); // ææ éæ©ä¸ææ¡æ°æ® |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = (type, row) => { |
| | |
| | | supplierList.value = res.data; |
| | | }); |
| | | form.value = {} |
| | | testStandardOptions.value = []; |
| | | tableData.value = []; |
| | | getProductOptions(); |
| | | if (operationType.value === 'edit') { |
| | | // å
ä¿å testStandardIdï¼é¿å
被æ¸
空 |
| | | const savedTestStandardId = row.testStandardId; |
| | | form.value = {...row} |
| | | currentProductId.value = row.productId || 0 |
| | | getQualityInspectParamList(row.id) |
| | | // ç¼è¾æ¨¡å¼ä¸ï¼å
å è½½ææ é项ï¼ç¶åå è½½åæ°å表 |
| | | if (currentProductId.value) { |
| | | // å
å è½½ææ é项 |
| | | let params = { |
| | | productId: currentProductId.value, |
| | | inspectType: 0 |
| | | } |
| | | qualityInspectDetailByProductId(params).then(res => { |
| | | testStandardOptions.value = res.data || []; |
| | | // ä½¿ç¨ nextTick å setTimeout ç¡®ä¿éé¡¹å·²ç»æ¸²æå° DOM |
| | | nextTick(() => { |
| | | setTimeout(() => { |
| | | // 妿ç¼è¾æ°æ®ä¸æ testStandardIdï¼å设置并å 载对åºçåæ° |
| | | if (savedTestStandardId) { |
| | | // ç¡®ä¿ç±»åå¹é
ï¼item.id å¯è½æ¯æ°åæåç¬¦ä¸²ï¼ |
| | | const matchedOption = testStandardOptions.value.find(item => |
| | | item.id == savedTestStandardId || String(item.id) === String(savedTestStandardId) |
| | | ); |
| | | if (matchedOption) { |
| | | // ç¡®ä¿ä½¿ç¨å¹é
项ç idï¼ä¿æç±»åä¸è´ï¼ |
| | | form.value.testStandardId = matchedOption.id; |
| | | handleTestStandardChange(matchedOption.id); |
| | | } else { |
| | | // 妿æ¾ä¸å°å¹é
项ï¼å°è¯ç´æ¥ä½¿ç¨åå¼ |
| | | console.warn('æªæ¾å°å¹é
çææ é项ï¼testStandardId:', savedTestStandardId, 'å¯ç¨é项:', testStandardOptions.value); |
| | | form.value.testStandardId = savedTestStandardId; |
| | | handleTestStandardChange(savedTestStandardId); |
| | | } |
| | | } else { |
| | | // å¦åä½¿ç¨æ§çé»è¾ |
| | | getQualityInspectParamList(row.id); |
| | | } |
| | | }, 100); |
| | | }); |
| | | }); |
| | | } else { |
| | | getQualityInspectParamList(row.id); |
| | | } |
| | | } |
| | | } |
| | | const getProductOptions = () => { |
| | |
| | | const getModels = (value) => { |
| | | currentProductId.value = value |
| | | form.value.productName = findNodeById(productOptions.value, value); |
| | | if (currentProductId) { |
| | | if (currentProductId.value) { |
| | | getList(); |
| | | } |
| | | }; |
| | |
| | | } |
| | | |
| | | const getList = () => { |
| | | qualityInspectDetailByProductId(currentProductId.value).then(res => { |
| | | tableData.value = res.data; |
| | | if (!currentProductId.value) { |
| | | testStandardOptions.value = []; |
| | | tableData.value = []; |
| | | return; |
| | | } |
| | | let params = { |
| | | productId: currentProductId.value, |
| | | inspectType: 0 |
| | | } |
| | | qualityInspectDetailByProductId(params).then(res => { |
| | | // ä¿å䏿æ¡éé¡¹æ°æ® |
| | | testStandardOptions.value = res.data || []; |
| | | // æ¸
ç©ºè¡¨æ ¼æ°æ®ï¼çå¾
ç¨æ·éæ©ææ |
| | | tableData.value = []; |
| | | // æ¸
ç©ºææ éæ© |
| | | form.value.testStandardId = ''; |
| | | }) |
| | | } |
| | | |
| | | // ææ éæ©ååå¤ç |
| | | const handleTestStandardChange = (testStandardId) => { |
| | | if (!testStandardId) { |
| | | tableData.value = []; |
| | | return; |
| | | } |
| | | tableLoading.value = true; |
| | | getQualityTestStandardParamByTestStandardId(testStandardId).then(res => { |
| | | tableData.value = res.data || []; |
| | | }).catch(error => { |
| | | console.error('è·åæ ååæ°å¤±è´¥:', error); |
| | | tableData.value = []; |
| | | }).finally(() => { |
| | | tableLoading.value = false; |
| | | }) |
| | | } |
| | | |
| | |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | tableData.value = [] |
| | | tableData.value = []; |
| | | testStandardOptions.value = []; |
| | | form.value.testStandardId = ''; |
| | | dialogFormVisible.value = false; |
| | | emit('close') |
| | | }; |
| | |
| | | <div class="left-panel"> |
| | | <!-- 客æ·ä¿¡æ¯ç»è®¡åæ --> |
| | | <div class="panel-header"> |
| | | <span class="panel-title">客æ·ä¿¡æ¯ç»è®¡åæ</span> |
| | | <span class="panel-title">å¨å¶åç»è®¡åæ</span> |
| | | </div> |
| | | <div class="panel-item-customers"> |
| | | <div class="panel-title-second"> |
| | | <div class="panel-title-icon"></div> |
| | | <div class="total-customers"> |
| | | <span class="label">æ»ååéé¢(å
)</span> |
| | | <span class="value">{{sum}}</span> |
| | | <div class="quality-cards"> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card one"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>æ»å¨å¶æ°é</div> |
| | | <div>{{workInProcessStatistics.totalQuantity}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | <!-- <div class="jiantou"></div>--> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card two"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>å¹³åå¨è½¬å¤©æ°</div> |
| | | <div>{{workInProcessStatistics.avgTurnoverDays}}天</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card three"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>å¨è½¬æç</div> |
| | | <div>{{workInProcessStatistics.turnoverEfficiency}}%</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- 饼å¾åºå --> |
| | | <div style="display: flex;align-items: center;gap: 20px;justify-content: space-evenly;height: 82%;margin-top: 20px"> |
| | | <div style="width: 240px; height: 240px; background-image: url('/src/assets/BI/zonghetongbingtubiankuang@2x.png'); background-size: contain; background-position: center; background-repeat: no-repeat; display: flex; align-items: center; justify-content: center;"> |
| | | <Echarts ref="chart" :legend="pieLegend" :chartStyle="chartStylePie" |
| | | :series="materialPieSeries" |
| | | :tooltip="pieTooltip" |
| | | :options="{backgroundColor: 'transparent'}" |
| | | style="margin-left: 5px;"></Echarts> |
| | | </div> |
| | | <ul class="contract-list" style="margin: 0; padding: 0; display: flex; flex-direction: column;justify-content: space-around; height: 100%; overflow-y: auto; scroll-behavior: smooth;" ref="refContractList"> |
| | | <li v-for="item in materialPieSeries[0].data" :key="item.name" style="list-style: none; margin-bottom: 12px;"> |
| | | <div style="display: flex;align-items: center;justify-content: space-between;width: 100%"> |
| | | <div class="line" :style="{color: item.itemStyle.color}">â {{item.name}}</div> |
| | | <div style="font-weight: 700;font-size: 16px;color: #85B1E4;">ï¿¥{{item.value}}</div> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | <!-- å·¥åºå¨å¶åæ°éæ±ç¶å¾ --> |
| | | <div style="height: 82%;margin-top: 20px"> |
| | | <Echarts ref="chart" |
| | | :chartStyle="chartStyle" |
| | | :grid="grid" |
| | | :legend="workInProcessBarLegend" |
| | | :series="workInProcessBarSeries" |
| | | :tooltip="tooltip" |
| | | :xAxis="workInProcessXAxis" |
| | | :yAxis="workInProcessYAxis" |
| | | :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}" |
| | | style="height: 100%"></Echarts> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card one"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>åææå·²æ£æµæ°</div> |
| | | <div>åæææ£æ°</div> |
| | | <div>{{qualityStatisticsObject.supplierNum}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card two"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>è¿ç¨æ£éªæ°é</div> |
| | | <div>è¿ç¨æ£æ°</div> |
| | | <div>{{qualityStatisticsObject.processNum}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card three"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>åºåå·²æ£æ°é</div> |
| | | <div>åºåæ£æ°</div> |
| | | <div>{{qualityStatisticsObject.factoryNum}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | |
| | | </div> |
| | | <div class="main-panel"> |
| | | <div class="panel-item-customers"> |
| | | <div class="event-header"> |
| | | <img src="@/assets/BI/shijianmingxiicon@2x.png" alt="徿 " class="event-icon" /> |
| | | <span class="event-title">ç»è¥åæ</span> |
| | | <div class="order-statistics-cards" style="margin-bottom: 0px;"> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card four"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>æ»è®¢åæ°</div> |
| | | <div>{{orderStatisticsObject.totalOrderCount}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card five"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>æªå®æè®¢åæ°</div> |
| | | <div>{{orderStatisticsObject.uncompletedOrderCount}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card six"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>é¨åå®æè®¢åæ°</div> |
| | | <div>{{orderStatisticsObject.partialCompletedOrderCount}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-cardSec"> |
| | | <div class="quality-card seven"></div> |
| | | <div class="quality-cardTitle"> |
| | | <div>å·²å®æè®¢åæ°</div> |
| | | <div>{{orderStatisticsObject.completedOrderCount}}ä»¶</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <Echarts ref="chart" |
| | | :chartStyle="chartStyle" |
| | | :grid="grid" |
| | | :legend="barLegend1" |
| | | :series="barSeries11" |
| | | :tooltip="tooltip" |
| | | :xAxis="xAxis3" |
| | | :yAxis="yAxis3" |
| | | :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}" |
| | | style="height: 170px"></Echarts> |
| | | <div class="progress-table-container" ref="progressTableRef" style="margin-top: 0px;" @scroll="handleTableScroll"> |
| | | <table class="progress-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>ç产订åå·</th> |
| | | <th>产ååç§°</th> |
| | | <th>è§æ ¼</th> |
| | | <th>éæ±æ°é</th> |
| | | <th>宿æ°é</th> |
| | | <th>宿è¿åº¦</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr |
| | | v-for="(item, index) in progressTableData" |
| | | :key="index" |
| | | :ref="el => setRowRef(el, index)" |
| | | :class="{ 'row-under-header': isRowUnderHeader(index) }" |
| | | > |
| | | <td>{{ item.npsNo || '-' }}</td> |
| | | <td>{{ item.productCategory || '-' }}</td> |
| | | <td>{{ item.specificationModel || '-' }}</td> |
| | | <td>{{ item.quantity || 0 }}</td> |
| | | <td>{{ item.completeQuantity || 0 }}</td> |
| | | <td> |
| | | <el-progress |
| | | :percentage="calculateProgress(item)" |
| | | :color="progressColor(calculateProgress(item))" |
| | | :status="calculateProgress(item) >= 100 ? 'success' : ''" |
| | | :stroke-width="8" |
| | | /> |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | getProgressStatistics, |
| | | getWorkInProcessTurnover |
| | | } from "@/api/viewIndex.js"; |
| | | import {staffOnJobListPage} from "@/api/personnelManagement/staffOnJob.js"; |
| | | import {staffOnJobListPage} from "@/api/personnelManagement/employeeRecord.js"; |
| | | import {listCustomer} from "@/api/basicData/customerFile.js"; |
| | | import {listSupplier} from "@/api/basicData/supplierManageFile.js"; |
| | | import {getLedgerPage} from "@/api/equipmentManagement/ledger.js"; |
| | |
| | | import {getUpkeepPage} from "@/api/equipmentManagement/upkeep.js"; |
| | | import {measuringInstrumentListPage} from "@/api/equipmentManagement/measurementEquipment.js"; |
| | | import {listPageAnalysis} from "@/api/financialManagement/expenseManagement.js"; |
| | | import {productOrderListPage} from "@/api/productionManagement/productionOrder.js"; |
| | | |
| | | // å
¨å±ç¸å
³ç¶æ |
| | | const isFullscreen = ref(false); |
| | |
| | | const realtimeLineChartRef = ref(null) |
| | | const refContractList = ref(null) |
| | | const refTodoList = ref(null) |
| | | const progressTableRef = ref(null) |
| | | const timerScroll = ref(null) |
| | | const progressTableScrollTimer = ref(null) |
| | | const isTableScrolling = ref(false) |
| | | const tableScrollTimeout = ref(null) |
| | | const tableRowRefs = ref([]) |
| | | const rowsUnderHeader = ref(new Set()) |
| | | |
| | | const chartStylePie = { |
| | | width: '140%', |
| | | height: '140%' // 设置å¾è¡¨å®¹å¨çé«åº¦ |
| | | width: '100%', |
| | | height: '100%' // 设置å¾è¡¨å®¹å¨çé«åº¦ |
| | | } |
| | | const materialPieSeries = ref([ |
| | | { |
| | |
| | | supplierNum: 0, |
| | | processNum: 0, |
| | | factoryNum: 0, |
| | | }) |
| | | |
| | | // 订åç»è®¡å¯¹è±¡ |
| | | const orderStatisticsObject = ref({ |
| | | totalOrderCount: 0, |
| | | uncompletedOrderCount: 0, |
| | | partialCompletedOrderCount: 0, |
| | | completedOrderCount: 0, |
| | | }) |
| | | |
| | | // å¨å¶åå¨è½¬ç»è®¡å¯¹è±¡ |
| | | const workInProcessStatistics = ref({ |
| | | totalQuantity: 0, |
| | | avgTurnoverDays: 0, |
| | | turnoverEfficiency: 0, |
| | | }) |
| | | const chartStyle = { |
| | | width: '100%', |
| | |
| | | axisLabel: { color: '#B8C8E0' } |
| | | }] |
| | | |
| | | // å¨å¶åå·¥åºæ±ç¶å¾é
ç½® |
| | | const workInProcessXAxis = ref([{ |
| | | type: 'category', |
| | | axisTick: { show: false }, |
| | | axisLabel: { color: '#B8C8E0' }, |
| | | data: [] |
| | | }]) |
| | | const workInProcessYAxis = [{ |
| | | type: 'value', |
| | | axisLabel: { color: '#B8C8E0' }, |
| | | name: '' |
| | | }] |
| | | const workInProcessBarLegend = { |
| | | show: false, |
| | | textStyle: { color: '#B8C8E0' }, |
| | | data: [] |
| | | } |
| | | const workInProcessBarSeries = ref([ |
| | | { |
| | | name: 'å¨å¶åæ°é', |
| | | type: 'bar', |
| | | barWidth: 25, // åºå®æ±ç¶å¾å®½åº¦ä¸º40px |
| | | barGap: 0, |
| | | emphasis: { |
| | | focus: 'series' |
| | | }, |
| | | itemStyle: { |
| | | color: { |
| | | type: 'linear', |
| | | x: 0, |
| | | y: 0, |
| | | x2: 0, |
| | | y2: 1, |
| | | colorStops: [ |
| | | { offset: 0, color: '#4EE4FF' }, |
| | | { offset: 1, color: '#00A4ED' } |
| | | ] |
| | | } |
| | | }, |
| | | label: { |
| | | show: true, |
| | | position: 'top', |
| | | color: '#B8C8E0' |
| | | }, |
| | | data: [] |
| | | } |
| | | ]) |
| | | |
| | | // å¾
åäºé¡¹ |
| | | const todoList = ref([]) |
| | | |
| | | // ç产订å宿è¿åº¦è¡¨æ ¼æ°æ® |
| | | const progressTableData = ref([]) |
| | | |
| | | // 计ç®å®æè¿åº¦ç¾åæ¯ |
| | | const calculateProgress = (item) => { |
| | | if (!item) return 0 |
| | | // ä¼å
使ç¨completionStatusåæ®µ |
| | | if (item.completionStatus !== undefined && item.completionStatus !== null) { |
| | | const percentage = Number(item.completionStatus) |
| | | if (isNaN(percentage)) return 0 |
| | | return Math.min(Math.max(Math.round(percentage), 0), 100) |
| | | } |
| | | // å¦ææ²¡æcompletionStatusï¼åæ ¹æ®å®ææ°éåéæ±æ°éè®¡ç® |
| | | if (!item.quantity || item.quantity === 0) return 0 |
| | | const percentage = (item.completeQuantity || 0) / item.quantity * 100 |
| | | return Math.min(Math.max(Math.round(percentage), 0), 100) |
| | | } |
| | | |
| | | // æ ¹æ®è¿åº¦ç¾åæ¯è¿åé¢è² |
| | | const progressColor = (percentage) => { |
| | | const p = percentage || 0 |
| | | if (p < 30) return "#f56c6c" |
| | | if (p < 50) return "#e6a23c" |
| | | if (p < 80) return "#409eff" |
| | | return "#67c23a" |
| | | } |
| | | |
| | | // 计ç®ç¼©æ¾æ¯ä¾ |
| | | const calculateScale = () => { |
| | |
| | | })) |
| | | }) |
| | | } |
| | | // å¨å¶åå¨è½¬ç»è®¡ |
| | | const workInProcessTurnoverInfo = () => { |
| | | getWorkInProcessTurnover().then((res) => { |
| | | console.log("å¨å¶åå¨è½¬ç»è®¡æ°æ®:", res) |
| | | |
| | | if (!res || !res.data) { |
| | | console.warn('å¨å¶åå¨è½¬ç»è®¡æ°æ®ä¸ºç©º') |
| | | return |
| | | } |
| | | |
| | | // 仿¥å£è·åç»è®¡æ°æ® |
| | | workInProcessStatistics.value = { |
| | | totalQuantity: res.data.totalOrderCount || 0, |
| | | avgTurnoverDays: res.data.averageTurnoverDays || 0, |
| | | turnoverEfficiency: res.data.turnoverEfficiency || 0, |
| | | } |
| | | |
| | | // è®¾ç½®å·¥åºæ±ç¶å¾æ°æ® |
| | | // Xè½´ï¼processDetails (å·¥åºè¯¦æ
æ°ç») |
| | | // Yè½´ï¼processQuantityDetails (å·¥åºæ°é详æ
æ°ç») |
| | | if (res.data.processDetails && Array.isArray(res.data.processDetails)) { |
| | | // 设置Xè½´æ°æ®ï¼å·¥åºåç§°ï¼ |
| | | workInProcessXAxis.value[0].data = res.data.processDetails |
| | | } else { |
| | | workInProcessXAxis.value[0].data = [] |
| | | } |
| | | |
| | | if (res.data.processQuantityDetails && Array.isArray(res.data.processQuantityDetails)) { |
| | | // 设置Yè½´æ°æ®ï¼å¨å¶åæ°éï¼ |
| | | workInProcessBarSeries.value[0].data = res.data.processQuantityDetails |
| | | } else { |
| | | workInProcessBarSeries.value[0].data = [] |
| | | } |
| | | }).catch((error) => { |
| | | console.error('è·åå¨å¶åå¨è½¬ç»è®¡å¤±è´¥:', error) |
| | | }) |
| | | } |
| | | // è´¨æ£ç»è®¡ |
| | | const qualityStatisticsInfo = () => { |
| | | qualityStatistics().then((res) => { |
| | |
| | | } |
| | | // åç产订åç宿è¿åº¦ç»è®¡ |
| | | const progressStatisticsInfo = () => { |
| | | // ä»ç»è®¡æ¥å£è·åç»è®¡æ°æ® |
| | | getProgressStatistics().then((res) => { |
| | | console.log("ç产订å宿è¿åº¦ç»è®¡æ°æ®:", res) |
| | | |
| | |
| | | return |
| | | } |
| | | |
| | | // 设置Xè½´æ°æ® - 使ç¨åç±»åç§° |
| | | xAxis3.value[0].data = ['已宿è¿åº¦æ°', 'æ»è®¢åæ°', 'æªå®æè®¢åæ°', 'å·²å®æè®¢åæ°'] |
| | | |
| | | // 设置å个系åçæ°æ® - æ¯ä¸ªXè½´å类对åºä¸ä¸ªå¼ |
| | | if (barSeries11.value && barSeries11.value.length > 0) { |
| | | barSeries11.value[0].data = [ |
| | | res.data.completedProgressCount || 0, |
| | | res.data.totalOrderCount || 0, |
| | | res.data.uncompletedOrderCount || 0, |
| | | res.data.completedOrderCount || 0 |
| | | ] |
| | | // 仿¥å£è·åç»è®¡æ°æ® |
| | | orderStatisticsObject.value = { |
| | | totalOrderCount: res.data.totalOrderCount || 0, |
| | | uncompletedOrderCount: res.data.uncompletedOrderCount || 0, |
| | | partialCompletedOrderCount: res.data.partialCompletedOrderCount || 0, |
| | | completedOrderCount: res.data.completedOrderCount || 0 |
| | | } |
| | | progressTableData.value = res.data.completedOrderDetails || [] |
| | | // éç½®è¡å¼ç¨ |
| | | tableRowRefs.value = [] |
| | | rowsUnderHeader.value.clear() |
| | | |
| | | console.log('å¾è¡¨æ°æ®è®¾ç½®å®æ:', { |
| | | xAxis: xAxis3.value[0].data, |
| | | series: barSeries11.value[0]?.data |
| | | // å¨è·åå°æ°æ®åï¼åå§åæ»å¨åè½ |
| | | nextTick(() => { |
| | | initProgressTableScroll() |
| | | }) |
| | | |
| | | }).catch((error) => { |
| | | console.error('è·åç产订å宿è¿åº¦ç»è®¡å¤±è´¥:', error) |
| | | }) |
| | |
| | | |
| | | // èªå¨è½®æ¢å¨ãæãå£åº¦ç宿¶å¨ |
| | | const autoSwitchTimer = ref(null) |
| | | |
| | | // 设置è¡å¼ç¨ |
| | | const setRowRef = (el, index) => { |
| | | if (el) { |
| | | tableRowRefs.value[index] = el |
| | | } |
| | | } |
| | | |
| | | // å¤æè¡æ¯å¦å¨è¡¨å¤´ä¸æ¹ |
| | | const isRowUnderHeader = (index) => { |
| | | return rowsUnderHeader.value.has(index) |
| | | } |
| | | |
| | | // å¤çè¡¨æ ¼æ»å¨äºä»¶ |
| | | const handleTableScroll = () => { |
| | | const tableContainer = progressTableRef.value |
| | | if (!tableContainer) return |
| | | |
| | | const thead = tableContainer.querySelector('thead') |
| | | if (!thead) return |
| | | |
| | | const theadHeight = thead.offsetHeight |
| | | const containerRect = tableContainer.getBoundingClientRect() |
| | | const containerTop = containerRect.top |
| | | const theadBottom = containerTop + theadHeight |
| | | |
| | | // æ¸
空ä¹åçè®°å½ |
| | | rowsUnderHeader.value.clear() |
| | | |
| | | // æ£æ¥æ¯ä¸è¡æ¯å¦å¨è¡¨å¤´ä¸æ¹ï¼è¢«è¡¨å¤´é®æ¡ï¼ |
| | | tableRowRefs.value.forEach((row, index) => { |
| | | if (row) { |
| | | const rowRect = row.getBoundingClientRect() |
| | | const rowTop = rowRect.top |
| | | const rowBottom = rowRect.bottom |
| | | |
| | | // 妿è¡ä¸è¡¨å¤´æéå ï¼è¡å¨è¡¨å¤´ä¸æ¹è¢«é®æ¡ï¼ |
| | | // è¡çé¡¶é¨å¨è¡¨å¤´åºé¨ä¸æ¹ï¼ä½è¡çåºé¨å¨è¡¨å¤´åºé¨ä¸æ¹ï¼è¯´æè¢«é®æ¡ |
| | | if (rowTop < theadBottom && rowBottom > containerTop) { |
| | | rowsUnderHeader.value.add(index) |
| | | } |
| | | } |
| | | }) |
| | | |
| | | // æ¸
é¤ä¹åç宿¶å¨ |
| | | if (tableScrollTimeout.value) { |
| | | clearTimeout(tableScrollTimeout.value) |
| | | } |
| | | |
| | | // æ»å¨åæ¢åæ¸
ç©ºæ·¡åæ è®° |
| | | tableScrollTimeout.value = setTimeout(() => { |
| | | rowsUnderHeader.value.clear() |
| | | }, 150) |
| | | } |
| | | |
| | | // åå§åç产订åè¿åº¦è¡¨æ ¼æ»å¨åè½ |
| | | const initProgressTableScroll = () => { |
| | | const tableContainer = progressTableRef.value |
| | | if (!tableContainer) return |
| | | |
| | | // æ¸
çä¹åçæ»å¨å¨ç»å宿¶å¨ |
| | | if (progressTableScrollTimer.value) { |
| | | cancelAnimationFrame(progressTableScrollTimer.value) |
| | | progressTableScrollTimer.value = null |
| | | } |
| | | if (tableContainer._pauseTimer) { |
| | | clearInterval(tableContainer._pauseTimer) |
| | | tableContainer._pauseTimer = null |
| | | } |
| | | |
| | | const tbody = tableContainer.querySelector('tbody') |
| | | if (!tbody) return |
| | | |
| | | // æ¸
çä¹åå¯è½åå¨çå
éè¡ï¼ä¿çåå§æ°æ®è¡ï¼ |
| | | // åå§æ°æ®è¡çæ°éåºè¯¥çäº progressTableData.value.length |
| | | const originalCount = progressTableData.value.length |
| | | const allRows = Array.from(tbody.querySelectorAll('tr')) |
| | | if (allRows.length > originalCount) { |
| | | // ç§»é¤ææè¶
è¿åå§æ°éçè¡ï¼è¿äºæ¯å
éçè¡ï¼ |
| | | for (let i = originalCount; i < allRows.length; i++) { |
| | | allRows[i].remove() |
| | | } |
| | | } |
| | | |
| | | const scrollItems = Array.from(tbody.querySelectorAll('tr')) |
| | | if (scrollItems.length === 0) return |
| | | |
| | | // è·ååå§æ°æ®é¡¹æ°é |
| | | const originalItemCount = scrollItems.length |
| | | |
| | | // 计ç®å®¹å¨é«åº¦å表头é«åº¦ |
| | | const thead = tableContainer.querySelector('thead') |
| | | const theadHeight = thead ? thead.offsetHeight : 40 |
| | | const containerHeight = tableContainer.clientHeight |
| | | const visibleHeight = containerHeight - theadHeight |
| | | |
| | | // 计ç®åå§æ°æ®çæ»é«åº¦ |
| | | const itemHeight = scrollItems[0]?.offsetHeight || 40 |
| | | const totalContentHeight = itemHeight * originalItemCount |
| | | |
| | | // å¦ææ°æ®éä¸å¤ï¼å®¹å¨å¯ä»¥å®å
¨æ¾ç¤ºæææ°æ®ï¼å°±ä¸éè¦æ»å¨åå
é |
| | | if (totalContentHeight <= visibleHeight) { |
| | | // æ°æ®éå°ï¼ä¸éè¦æ»å¨ï¼ç´æ¥è¿å |
| | | return |
| | | } |
| | | |
| | | // æ°æ®éè¶³å¤ï¼éè¦æ»å¨ï¼è¿è¡å
é以å®ç°æ ç¼æ»å¨ |
| | | const cloneCount = Math.ceil(visibleHeight / itemHeight) + 2 |
| | | |
| | | // å
éåå 个项ç®å¹¶æ·»å å°å表æ«å°¾ï¼å®ç°æ ç¼æ»å¨ |
| | | for (let i = 0; i < cloneCount; i++) { |
| | | const clone = scrollItems[i % originalItemCount].cloneNode(true) |
| | | tbody.appendChild(clone) |
| | | } |
| | | |
| | | let scrollPosition = 0 |
| | | const scrollSpeed = 1.5 |
| | | const pauseTime = 3000 |
| | | let isPaused = false |
| | | let lastTimestamp = 0 |
| | | |
| | | // è¿ç»æ»å¨å¨ç»å½æ° |
| | | function scrollAnimation(timestamp) { |
| | | if (!lastTimestamp) lastTimestamp = timestamp |
| | | const deltaTime = timestamp - lastTimestamp |
| | | lastTimestamp = timestamp |
| | | |
| | | if (!isPaused) { |
| | | scrollPosition += scrollSpeed * (deltaTime / 16) |
| | | |
| | | // è®¡ç®æå¤§æ»å¨ä½ç½®ï¼åå§å
容çé«åº¦ï¼ |
| | | const maxScroll = itemHeight * originalItemCount |
| | | |
| | | // 彿»å¨è¶
è¿åå§å
容é¿åº¦æ¶ï¼éç½®ä½ç½®å®ç°æ ç¼æ»å¨ |
| | | if (scrollPosition >= maxScroll) { |
| | | scrollPosition = 0 |
| | | tableContainer.scrollTop = 0 |
| | | } else { |
| | | tableContainer.scrollTop = scrollPosition |
| | | } |
| | | } |
| | | |
| | | progressTableScrollTimer.value = requestAnimationFrame(scrollAnimation) |
| | | } |
| | | |
| | | // å¯å¨æ»å¨å¨ç» |
| | | progressTableScrollTimer.value = requestAnimationFrame(scrollAnimation) |
| | | |
| | | // 设置æ»å¨-æå-æ»å¨çå¾ªç¯ææ |
| | | const pauseTimer = setInterval(() => { |
| | | isPaused = !isPaused |
| | | }, pauseTime) |
| | | |
| | | // æ¸
ç宿¶å¨ |
| | | tableContainer._pauseTimer = pauseTimer |
| | | } |
| | | |
| | | // åå§åå¾
åäºé¡¹å表æ»å¨åè½ |
| | | const initTodoListScroll = () => { |
| | | const todoList = refTodoList.value |
| | |
| | | window.addEventListener('webkitfullscreenchange', handleFullscreenChange) |
| | | window.addEventListener('MSFullscreenChange', handleFullscreenChange) |
| | | analysisCustomer() |
| | | workInProcessTurnoverInfo() |
| | | qualityStatisticsInfo() |
| | | // accountStatisticsInfo() |
| | | progressStatisticsInfo() |
| | |
| | | clearInterval(todoList._pauseTimer) |
| | | todoList._pauseTimer = null |
| | | } |
| | | } |
| | | |
| | | // æ¸
çç产订åè¿åº¦è¡¨æ ¼çå¨ç»å宿¶å¨ |
| | | const progressTable = progressTableRef.value |
| | | if (progressTable) { |
| | | if (progressTableScrollTimer.value) { |
| | | cancelAnimationFrame(progressTableScrollTimer.value) |
| | | progressTableScrollTimer.value = null |
| | | } |
| | | if (progressTable._pauseTimer) { |
| | | clearInterval(progressTable._pauseTimer) |
| | | progressTable._pauseTimer = null |
| | | } |
| | | } |
| | | |
| | | // æ¸
çè¡¨æ ¼æ»å¨å®æ¶å¨ |
| | | if (tableScrollTimeout.value) { |
| | | clearTimeout(tableScrollTimeout.value) |
| | | tableScrollTimeout.value = null |
| | | } |
| | | |
| | | // æ¸
çèªå¨è½®æ¢å¨ãæãå£åº¦ç宿¶å¨ |
| | |
| | | } |
| | | .quality-card.three { |
| | | background-image: url("@/assets/BI/chuchangyijianicon@2x.png"); |
| | | |
| | | } |
| | | |
| | | /* 订åç»è®¡å¡çæ ·å¼ */ |
| | | .order-statistics-cards { |
| | | display: flex; |
| | | gap: 12px; |
| | | width: 100%; |
| | | height: 94px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .quality-card.four { |
| | | background-image: url("@/assets/BI/yuancailiaoyijianicon@2x.png"); |
| | | } |
| | | |
| | | .quality-card.five { |
| | | background-image: url("@/assets/BI/guochengyijianicon@2x.png"); |
| | | } |
| | | |
| | | .quality-card.six { |
| | | background-image: url("@/assets/BI/chuchangyijianicon@2x.png"); |
| | | } |
| | | |
| | | .quality-card.seven { |
| | | background-image: url("@/assets/BI/yuancailiaoyijianicon@2x.png"); |
| | | } |
| | | .panel-title-icon { |
| | | width: 60px; |
| | |
| | | border-color: rgba(255, 255, 255, 0.5); |
| | | box-shadow: -1px 0 0 0 rgba(255, 255, 255, 0.5); |
| | | } |
| | | |
| | | /* ç产订åè¿åº¦è¡¨æ ¼æ ·å¼ */ |
| | | .progress-table-container { |
| | | height: 250px; |
| | | overflow-y: auto; |
| | | overflow-x: hidden; |
| | | margin-top: 10px; |
| | | scrollbar-width: none; /* Firefox */ |
| | | -ms-overflow-style: none; /* IEåEdge */ |
| | | } |
| | | |
| | | .progress-table-container::-webkit-scrollbar { |
| | | display: none; /* ChromeãSafariåOpera */ |
| | | } |
| | | |
| | | .progress-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | color: #B8C8E0; |
| | | font-size: 12px; |
| | | table-layout: fixed; |
| | | } |
| | | |
| | | .progress-table thead { |
| | | position: sticky; |
| | | top: 0; |
| | | background-color: rgba(26, 88, 176, 0.9); |
| | | z-index: 10; |
| | | } |
| | | |
| | | .progress-table th { |
| | | padding: 8px 6px; |
| | | text-align: left; |
| | | font-weight: 500; |
| | | border-bottom: 1px solid rgba(184, 200, 224, 0.3); |
| | | color: #B8C8E0; |
| | | font-size: 12px; |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | |
| | | .progress-table th:nth-child(1) { width: 15%; } /* ç产订åå· */ |
| | | .progress-table th:nth-child(2) { width: 15%; } /* 产ååç§° */ |
| | | .progress-table th:nth-child(3) { width: 15%; } /* è§æ ¼ */ |
| | | .progress-table th:nth-child(4) { width: 12%; } /* éæ±æ°é */ |
| | | .progress-table th:nth-child(5) { width: 12%; } /* 宿æ°é */ |
| | | .progress-table th:nth-child(6) { width: 31%; } /* 宿è¿åº¦ */ |
| | | |
| | | .progress-table td { |
| | | padding: 8px 6px; |
| | | border-bottom: 1px solid rgba(184, 200, 224, 0.1); |
| | | white-space: nowrap; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | font-size: 12px; |
| | | transition: opacity 0.3s ease; |
| | | } |
| | | |
| | | .progress-table tbody tr:hover { |
| | | background-color: rgba(184, 200, 224, 0.1); |
| | | } |
| | | |
| | | .progress-table tbody tr.row-under-header { |
| | | opacity: 0.5; |
| | | } |
| | | |
| | | /* el-progress ç»ä»¶æ ·å¼è°æ´ */ |
| | | .progress-table :deep(.el-progress) { |
| | | width: 100%; |
| | | } |
| | | |
| | | .progress-table :deep(.el-progress-bar__outer) { |
| | | background-color: rgba(184, 200, 224, 0.2); |
| | | } |
| | | |
| | | .progress-table :deep(.el-progress__text) { |
| | | color: #B8C8E0; |
| | | font-size: 11px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="report-management"> |
| | | <!-- ç鿡件 --> |
| | | <el-card class="filter-card" shadow="never"> |
| | | <el-form :model="filterForm" inline> |
| | | <el-form-item label="æ¶é´èå´"> |
| | | <el-date-picker |
| | | style="width: 300px" |
| | | v-model="filterForm.dateRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | @change="handleFilterChange" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¥è¡¨ç±»å"> |
| | | <el-select v-model="filterForm.reportType" placeholder="è¯·éæ©æ¥è¡¨ç±»å" @change="handleFilterChange" style="width: 300px"> |
| | | <el-option label="æ ·åè¿åº¦æ¥è¡¨" value="sample" /> |
| | | <el-option label="设å¤ä½¿ç¨æ¥è¡¨" value="equipment" /> |
| | | <el-option label="æ£æµé¡¹ç®æ¥è¡¨" value="inspection" /> |
| | | <el-option label="é¢ç¨è®°å½æ¥è¡¨" value="usage" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleFilterChange">æ¥è¯¢</el-button> |
| | | <el-button @click="resetFilter">éç½®</el-button> |
| | | <el-button type="success" @click="exportReport">å¯¼åºæ¥è¡¨</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </el-card> |
| | | |
| | | <!-- ç»è®¡å¡ç --> |
| | | <div class="statistics-cards"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="6"> |
| | | <el-card class="stat-card" shadow="hover"> |
| | | <div class="stat-content"> |
| | | <div class="stat-icon"> |
| | | <el-icon><Box /></el-icon> |
| | | </div> |
| | | <div class="stat-info"> |
| | | <div class="stat-number">{{ statistics.totalSamples }}</div> |
| | | <div class="stat-label">æ»æ ·åæ°</div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="stat-card" shadow="hover"> |
| | | <div class="stat-content"> |
| | | <div class="stat-icon"> |
| | | <el-icon><Tools /></el-icon> |
| | | </div> |
| | | <div class="stat-info"> |
| | | <div class="stat-number">{{ statistics.activeEquipment }}</div> |
| | | <div class="stat-label">å¨ç¨è®¾å¤</div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="stat-card" shadow="hover"> |
| | | <div class="stat-content"> |
| | | <div class="stat-icon"> |
| | | <el-icon><Document /></el-icon> |
| | | </div> |
| | | <div class="stat-info"> |
| | | <div class="stat-number">{{ statistics.completedInspections }}</div> |
| | | <div class="stat-label">å·²å®ææ£æµ</div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-card class="stat-card" shadow="hover"> |
| | | <div class="stat-content"> |
| | | <div class="stat-icon"> |
| | | <el-icon><ShoppingCart /></el-icon> |
| | | </div> |
| | | <div class="stat-info"> |
| | | <div class="stat-number">{{ statistics.totalUsage }}</div> |
| | | <div class="stat-label">æ»é¢ç¨æ¬¡æ°</div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | |
| | | <!-- å¾è¡¨åºå --> |
| | | <div class="charts-container"> |
| | | <el-row :gutter="20"> |
| | | <!-- æ ·åè¿åº¦å¾è¡¨ --> |
| | | <el-col :span="12"> |
| | | <el-card class="chart-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>æ ·åè¿åº¦ç»è®¡</span> |
| | | <el-button link @click="refreshSampleChart">å·æ°</el-button> |
| | | </div> |
| | | </template> |
| | | <div ref="sampleChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | |
| | | <!-- 设å¤ä½¿ç¨å¾è¡¨ --> |
| | | <el-col :span="12"> |
| | | <el-card class="chart-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>设å¤ä½¿ç¨çç»è®¡</span> |
| | | <el-button link @click="refreshEquipmentChart">å·æ°</el-button> |
| | | </div> |
| | | </template> |
| | | <div ref="equipmentChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="20" style="margin-top: 20px;"> |
| | | <!-- æ£æµé¡¹ç®ç»è®¡ --> |
| | | <el-col :span="12"> |
| | | <el-card class="chart-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>æ£æµé¡¹ç®åå¸</span> |
| | | <el-button link @click="refreshInspectionChart">å·æ°</el-button> |
| | | </div> |
| | | </template> |
| | | <div ref="inspectionChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | |
| | | <!-- é¢ç¨è®°å½è¶å¿ --> |
| | | <el-col :span="12"> |
| | | <el-card class="chart-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>é¢ç¨è®°å½è¶å¿</span> |
| | | <el-button link @click="refreshUsageChart">å·æ°</el-button> |
| | | </div> |
| | | </template> |
| | | <div ref="usageChartRef" class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | |
| | | <!-- è¯¦ç»æ°æ®è¡¨æ ¼ --> |
| | | <el-card class="table-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <span>è¯¦ç»æ°æ®</span> |
| | | <div> |
| | | <el-button type="primary" size="small" @click="refreshTable">å·æ°</el-button> |
| | | <el-button type="success" size="small" @click="exportTable">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <el-table |
| | | :data="tableData" |
| | | style="width: 100%" |
| | | v-loading="tableLoading" |
| | | stripe |
| | | border |
| | | > |
| | | <el-table-column prop="id" label="ç¼å·" width="80" /> |
| | | <el-table-column prop="name" label="åç§°" /> |
| | | <el-table-column prop="status" label="ç¶æ"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getStatusType(scope.row.status)"> |
| | | {{ scope.row.status }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="progress" label="è¿åº¦"> |
| | | <template #default="scope"> |
| | | <el-progress :percentage="scope.row.progress" :status="getProgressStatus(scope.row.progress)" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="createTime" label="å建æ¶é´" width="180" /> |
| | | <el-table-column prop="updateTime" label="æ´æ°æ¶é´" width="180" /> |
| | | <el-table-column label="æä½" width="150" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button link size="small" @click="viewDetail(scope.row)">æ¥ç</el-button> |
| | | <el-button link size="small" @click="editItem(scope.row)">ç¼è¾</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <div class="pagination-container"> |
| | | <el-pagination |
| | | v-model:current-page="pagination.currentPage" |
| | | v-model:page-size="pagination.pageSize" |
| | | :page-sizes="[10, 20, 50, 100]" |
| | | :total="pagination.total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | @size-change="handleSizeChange" |
| | | @current-change="handleCurrentChange" |
| | | /> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | <div class="report-management"> |
| | | <!-- å¾è¡¨åºå --> |
| | | <div class="charts-container"> |
| | | <el-row :gutter="20"> |
| | | <!-- åç±»å宿æ°é --> |
| | | <el-col :span="9"> |
| | | <el-card class="chart-card" |
| | | shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <div class="chart-title-line"></div> |
| | | <span>åç±»å宿æ°é</span> |
| | | </div> |
| | | </template> |
| | | <div class="top-container"> |
| | | <div class="typeNum"> |
| | | <div class="typeNum-left"> |
| | | <img src="~@/assets/images/chartCard.svg" |
| | | alt="å¾è¡¨" |
| | | style="width: 40px; height: 40px; object-fit: contain;"> |
| | | <div class="typeNum-left-text">åææ</div> |
| | | </div> |
| | | <div class="typeNum-center"> |
| | | <div class="typeNum-leftLine">-</div> |
| | | <div class="typeNum-rightLine"></div> |
| | | </div> |
| | | <div class="typeNum-right"> |
| | | <div class="typeNum-right-top"> |
| | | <div class="typeNum-right-top-name">æ»æ°é</div> |
| | | <div class="typeNum-right-top-text">2099 <span class="unit">个</span></div> |
| | | </div> |
| | | <div class="typeNum-right-bottom"> |
| | | <div class="typeNum-right-top-name">已宿æ°</div> |
| | | <div class="typeNum-right-top-text">2099 <span class="unit">个</span></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="typeNum"> |
| | | <div class="typeNum-left"> |
| | | <img src="~@/assets/images/chartCard2.svg" |
| | | alt="å¾è¡¨" |
| | | style="width: 40px; height: 40px; object-fit: contain;"> |
| | | <div class="typeNum-left-text" |
| | | style="color: #5EB334;">åæå</div> |
| | | </div> |
| | | <div class="typeNum-center"> |
| | | <div class="typeNum-leftLine2">-</div> |
| | | <div class="typeNum-rightLine2"></div> |
| | | </div> |
| | | <div class="typeNum-right"> |
| | | <div class="typeNum-right-top"> |
| | | <div class="typeNum-right-top-name">æ»æ°é</div> |
| | | <div class="typeNum-right-top-text">2099 <span class="unit">个</span></div> |
| | | </div> |
| | | <div class="typeNum-right-bottom"> |
| | | <div class="typeNum-right-top-name">已宿æ°</div> |
| | | <div class="typeNum-right-top-text">2099 <span class="unit">个</span></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="typeNum"> |
| | | <div class="typeNum-left"> |
| | | <img src="~@/assets/images/chartCard3.svg" |
| | | alt="å¾è¡¨" |
| | | style="width: 40px; height: 40px; object-fit: contain;"> |
| | | <div class="typeNum-left-text" |
| | | style="color: #8000FF;">æå</div> |
| | | </div> |
| | | <div class="typeNum-center"> |
| | | <div class="typeNum-leftLine3">-</div> |
| | | <div class="typeNum-rightLine3"></div> |
| | | </div> |
| | | <div class="typeNum-right"> |
| | | <div class="typeNum-right-top"> |
| | | <div class="typeNum-right-top-name">æ»æ°é</div> |
| | | <div class="typeNum-right-top-text">2099 <span class="unit">个</span></div> |
| | | </div> |
| | | <div class="typeNum-right-bottom"> |
| | | <div class="typeNum-right-top-name">已宿æ°</div> |
| | | <div class="typeNum-right-top-text">2099 <span class="unit">个</span></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | <!-- è´¨æ£åæ ¼ç --> |
| | | <el-col :span="15"> |
| | | <el-card class="chart-card" |
| | | shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <div class="chart-title-line"></div> |
| | | <span>è´¨æ£åæ ¼ç</span> |
| | | </div> |
| | | </template> |
| | | <div class="top-container flex-center"> |
| | | <div class="quality-card blue-card"> |
| | | <div class="quality-card-title"> |
| | | <img src="~@/assets/images/chartCard.svg" |
| | | alt="åææ" |
| | | style="width: 24px; height: 24px; margin-right: 8px;"> |
| | | åææåæ ¼ç |
| | | </div> |
| | | <div class="quality-card-content"> |
| | | <div class="quality-item"> |
| | | <div> |
| | | <div class="quality-item-label blue-label">宿ç</div> |
| | | <div class="quality-item-tip">å æ¯</div> |
| | | <div class="quality-item-value">80%</div> |
| | | </div> |
| | | <div class="quality-item-chart" |
| | | ref="materialCompletionChart"></div> |
| | | </div> |
| | | <div class="quality-item"> |
| | | <div> |
| | | <div class="quality-item-label green-label">åæ ¼ç</div> |
| | | <div class="quality-item-tip">å æ¯</div> |
| | | <div class="quality-item-value">80%</div> |
| | | </div> |
| | | <div class="quality-item-chart" |
| | | ref="materialQualityChart"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-card green-card"> |
| | | <div class="quality-card-title"> |
| | | <img src="~@/assets/images/chartCard2.svg" |
| | | alt="åæå" |
| | | style="width: 24px; height: 24px; margin-right: 8px;"> |
| | | åæååæ ¼ç |
| | | </div> |
| | | <div class="quality-card-content"> |
| | | <div class="quality-item"> |
| | | <div> |
| | | <div class="quality-item-label blue-label">宿ç</div> |
| | | <div class="quality-item-tip">å æ¯</div> |
| | | <div class="quality-item-value">80%</div> |
| | | </div> |
| | | <div class="quality-item-chart" |
| | | ref="semiCompletionChart"></div> |
| | | </div> |
| | | <div class="quality-item"> |
| | | <div> |
| | | <div class="quality-item-label green-label">åæ ¼ç</div> |
| | | <div class="quality-item-tip">å æ¯</div> |
| | | <div class="quality-item-value">80%</div> |
| | | </div> |
| | | <div class="quality-item-chart" |
| | | ref="semiQualityChart"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="quality-card purple-card"> |
| | | <div class="quality-card-title"> |
| | | <img src="~@/assets/images/chartCard3.svg" |
| | | alt="æå" |
| | | style="width: 24px; height: 24px; margin-right: 8px;"> |
| | | æååæ ¼ç |
| | | </div> |
| | | <div class="quality-card-content"> |
| | | <div class="quality-item"> |
| | | <div> |
| | | <div class="quality-item-label blue-label">宿ç</div> |
| | | <div class="quality-item-tip">å æ¯</div> |
| | | <div class="quality-item-value">80%</div> |
| | | </div> |
| | | <div class="quality-item-chart" |
| | | ref="finalCompletionChart"></div> |
| | | </div> |
| | | <div class="quality-item"> |
| | | <div> |
| | | <div class="quality-item-label green-label">åæ ¼ç</div> |
| | | <div class="quality-item-tip">å æ¯</div> |
| | | <div class="quality-item-value">80%</div> |
| | | </div> |
| | | <div class="quality-item-chart" |
| | | ref="finalQualityChart"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <div class="charts-container"> |
| | | <el-row :gutter="20"> |
| | | <!-- è´¨æ£åæ ¼ç --> |
| | | <el-col :span="24"> |
| | | <el-card class="chart-card" |
| | | shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <div class="chart-title-line"></div> |
| | | <span>è´¨æ£åæ ¼ç</span> |
| | | </div> |
| | | </template> |
| | | <div class="chart-container-line"> |
| | | <div class="container-line-left"> |
| | | <div style="height: 100%; width: 100%;" |
| | | ref="usageChartRef"> |
| | | </div> |
| | | </div> |
| | | <div class="container-line-right"> |
| | | <div style="height: 80%; width: 100%;" |
| | | ref="inspectionChartRef"> |
| | | </div> |
| | | <div class="container-line-right-bottom"> |
| | | <div class="inspection-chart-box"> |
| | | <div class="chart-box-title">åæææ½æ£æ°</div> |
| | | <div class="chart-box-num">600</div> |
| | | </div> |
| | | <div class="inspection-chart-box"> |
| | | <div class="chart-box-title">åæåæ½æ£æ°</div> |
| | | <div class="chart-box-num">200</div> |
| | | </div> |
| | | <div class="inspection-chart-box"> |
| | | <div class="chart-box-title">æåæ½æ£æ°</div> |
| | | <div class="chart-box-num">200</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- </div> --> |
| | | <!-- <div ref="sampleChartRef" |
| | | class="chart-container"></div> --> |
| | | <div class="yearchange"> |
| | | <div style="margin-right: 8px;font-size: 14px;">年份:</div> |
| | | <el-date-picker v-model="value3" |
| | | size="mini" |
| | | :clearable="false" |
| | | style="width: 60px;" |
| | | type="year" |
| | | :disabled-date="disabledDate" |
| | | placeholder=""> |
| | | </el-date-picker> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | <div class="charts-container"> |
| | | <el-row :gutter="20"> |
| | | <!-- æ ·åè¿åº¦å¾è¡¨ --> |
| | | <el-col :span="12"> |
| | | <el-card class="chart-card" |
| | | shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <div class="chart-title-line"></div> |
| | | <span>è´¨é宿æç»</span> |
| | | </div> |
| | | </template> |
| | | <div ref="equipmentChartRef" |
| | | class="chart-container"></div> |
| | | </el-card> |
| | | </el-col> |
| | | <!-- 设å¤ä½¿ç¨å¾è¡¨ --> |
| | | <el-col :span="12"> |
| | | <el-card class="chart-card" |
| | | shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <div class="chart-title-line"></div> |
| | | <span>æ£æµé¡¹ç®åç±»</span> |
| | | </div> |
| | | </template> |
| | | <div class="chart-container-line"> |
| | | <div class="container-line2-left"> |
| | | <div class="info-box"> |
| | | <div class="info-box-header">项ç®åå¸</div> |
| | | <div class="info-line"> |
| | | <div class="info-icon" |
| | | style="background-color: #165DFF"></div> |
| | | <div class="info-line-title">ç©çæ§è½</div> |
| | | <div class="info-line-value1">30%</div> |
| | | <div class="info-line-value2">300</div> |
| | | </div> |
| | | <div class="info-line"> |
| | | <div class="info-icon" |
| | | style="background-color: #14C9C9;"></div> |
| | | <div class="info-line-title">ç©çæ§è½</div> |
| | | <div class="info-line-value1">30%</div> |
| | | <div class="info-line-value2">300</div> |
| | | </div> |
| | | <div class="info-line"> |
| | | <div class="info-icon" |
| | | style="background-color: #F7BA1E;"></div> |
| | | <div class="info-line-title">ç©çæ§è½</div> |
| | | <div class="info-line-value1">30%</div> |
| | | <div class="info-line-value2">300</div> |
| | | </div> |
| | | <div class="info-line"> |
| | | <div class="info-icon" |
| | | style="background-color: #722ED1;"></div> |
| | | <div class="info-line-title">ç©çæ§è½</div> |
| | | <div class="info-line-value1">30%</div> |
| | | <div class="info-line-value2">300</div> |
| | | </div> |
| | | <div class="info-line"> |
| | | <div class="info-icon" |
| | | style="background-color: #3491FA;"></div> |
| | | <div class="info-line-title">ç©çæ§è½</div> |
| | | <div class="info-line-value1">30%</div> |
| | | <div class="info-line-value2">300</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div ref="sampleChartRef" |
| | | style="height: 100%; width: 50%;" |
| | | class="chart-container"></div> |
| | | </div> |
| | | <!-- Tab éæ©å¨ --> |
| | | <div class="tab-selector"> |
| | | <div class="tab-item" |
| | | :class="{ active: activeTab === 'raw' }" |
| | | @click="activeTab = 'raw'">åææ</div> |
| | | <div class="tab-item" |
| | | :class="{ active: activeTab === 'semi' }" |
| | | @click="activeTab = 'semi'">åæå</div> |
| | | <div class="tab-item" |
| | | :class="{ active: activeTab === 'final' }" |
| | | @click="activeTab = 'final'">æå</div> |
| | | </div> |
| | | </el-card> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, nextTick } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import * as echarts from 'echarts' |
| | | import { Box, Tools, Document, ShoppingCart } from '@element-plus/icons-vue' |
| | | import { ref, reactive, onMounted, nextTick } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import * as echarts from "echarts"; |
| | | import { Box, Tools, Document, ShoppingCart } from "@element-plus/icons-vue"; |
| | | |
| | | // ååºå¼æ°æ® |
| | | const filterForm = reactive({ |
| | | dateRange: [], |
| | | reportType: 'sample' |
| | | }) |
| | | // ååºå¼æ°æ® |
| | | const filterForm = reactive({ |
| | | dateRange: [], |
| | | reportType: "sample", |
| | | }); |
| | | |
| | | const statistics = reactive({ |
| | | totalSamples: 1250, |
| | | activeEquipment: 45, |
| | | completedInspections: 890, |
| | | totalUsage: 2340 |
| | | }) |
| | | const statistics = reactive({ |
| | | totalSamples: 1250, |
| | | activeEquipment: 45, |
| | | completedInspections: 890, |
| | | totalUsage: 2340, |
| | | }); |
| | | |
| | | const tableData = ref([]) |
| | | const tableLoading = ref(false) |
| | | const pagination = reactive({ |
| | | currentPage: 1, |
| | | pageSize: 20, |
| | | total: 0 |
| | | }) |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const pagination = reactive({ |
| | | currentPage: 1, |
| | | pageSize: 20, |
| | | total: 0, |
| | | }); |
| | | |
| | | // å¾è¡¨å¼ç¨ |
| | | const sampleChartRef = ref(null) |
| | | const equipmentChartRef = ref(null) |
| | | const inspectionChartRef = ref(null) |
| | | const usageChartRef = ref(null) |
| | | // åå§å年份为å½å年份ï¼ä½¿ç¨Dateå¯¹è±¡ï¼ |
| | | const currentYear = new Date().getFullYear(); |
| | | const value3 = ref(new Date(currentYear, 0, 1)); |
| | | |
| | | // å¾è¡¨å®ä¾ |
| | | let sampleChart = null |
| | | let equipmentChart = null |
| | | let inspectionChart = null |
| | | let usageChart = null |
| | | // éå¶æ¥æéæ©ï¼ä¸å
è®¸éæ©ä»å¹´ä¹åç年份 |
| | | const disabledDate = time => { |
| | | const currentYear = new Date().getFullYear(); |
| | | return time.getFullYear() > currentYear; |
| | | }; |
| | | |
| | | // åå§åæ°æ® |
| | | const initData = () => { |
| | | // 模æè¡¨æ ¼æ°æ® |
| | | tableData.value = [ |
| | | { |
| | | id: 'SP001', |
| | | name: 'æ ·åA-001', |
| | | type: 'é屿æ', |
| | | status: 'æ£æµä¸', |
| | | progress: 75, |
| | | createTime: '2025-01-15 09:30:00', |
| | | updateTime: '2025-01-20 14:20:00' |
| | | }, |
| | | { |
| | | id: 'SP002', |
| | | name: 'æ ·åB-002', |
| | | type: '塿å¶å', |
| | | status: '已宿', |
| | | progress: 100, |
| | | createTime: '2025-01-10 10:15:00', |
| | | updateTime: '2025-01-18 16:45:00' |
| | | }, |
| | | { |
| | | id: 'SP003', |
| | | name: 'æ ·åC-003', |
| | | type: 'çµåå
ä»¶', |
| | | status: 'å¾
æ£æµ', |
| | | progress: 0, |
| | | createTime: '2025-01-22 08:45:00', |
| | | updateTime: '2025-01-22 08:45:00' |
| | | }, |
| | | { |
| | | id: 'EQ001', |
| | | name: 'æ£æµè®¾å¤A', |
| | | type: 'å
谱仪', |
| | | status: '使ç¨ä¸', |
| | | progress: 60, |
| | | createTime: '2025-01-05 14:20:00', |
| | | updateTime: '2025-01-20 11:30:00' |
| | | }, |
| | | { |
| | | id: 'EQ002', |
| | | name: 'æ£æµè®¾å¤B', |
| | | type: 'æ¾å¾®é', |
| | | status: '空é²', |
| | | progress: 0, |
| | | createTime: '2025-01-08 16:10:00', |
| | | updateTime: '2025-01-19 09:15:00' |
| | | } |
| | | ] |
| | | |
| | | pagination.total = tableData.value.length |
| | | } |
| | | // Tab éæ©å¨å½åæ¿æ´»é¡¹ |
| | | const activeTab = ref("raw"); |
| | | |
| | | // åå§åæ ·åè¿åº¦å¾è¡¨ |
| | | const initSampleChart = () => { |
| | | if (sampleChartRef.value) { |
| | | sampleChart = echarts.init(sampleChartRef.value) |
| | | const option = { |
| | | title: { |
| | | show: false |
| | | }, |
| | | tooltip: { |
| | | trigger: 'item', |
| | | formatter: '{a} <br/>{b}: {c} ({d}%)' |
| | | }, |
| | | legend: { |
| | | orient: 'vertical', |
| | | left: 'left' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'æ ·åç¶æ', |
| | | type: 'pie', |
| | | radius: ['40%', '70%'], |
| | | avoidLabelOverlap: false, |
| | | label: { |
| | | show: false, |
| | | position: 'center' |
| | | }, |
| | | emphasis: { |
| | | label: { |
| | | show: true, |
| | | fontSize: '18', |
| | | fontWeight: 'bold' |
| | | } |
| | | }, |
| | | labelLine: { |
| | | show: false |
| | | }, |
| | | data: [ |
| | | { value: 450, name: '已宿' }, |
| | | { value: 320, name: 'æ£æµä¸' }, |
| | | { value: 280, name: 'å¾
æ£æµ' }, |
| | | { value: 200, name: 'å·²æå' } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| | | sampleChart.setOption(option) |
| | | } |
| | | } |
| | | // å¾è¡¨å¼ç¨ |
| | | const sampleChartRef = ref(null); |
| | | const equipmentChartRef = ref(null); |
| | | const inspectionChartRef = ref(null); |
| | | const usageChartRef = ref(null); |
| | | |
| | | // åå§å设å¤ä½¿ç¨å¾è¡¨ |
| | | const initEquipmentChart = () => { |
| | | if (equipmentChartRef.value) { |
| | | equipmentChart = echarts.init(equipmentChartRef.value) |
| | | const option = { |
| | | title: { |
| | | show: false |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis', |
| | | axisPointer: { |
| | | type: 'shadow' |
| | | } |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: ['å
谱仪', 'æ¾å¾®é', '硬度计', 'æåæº', 'å²å»æº', 'éç¸ä»ª'] |
| | | }, |
| | | yAxis: { |
| | | type: 'value', |
| | | name: '使ç¨ç(%)' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: '使ç¨ç', |
| | | type: 'bar', |
| | | data: [85, 60, 75, 90, 45, 70], |
| | | itemStyle: { |
| | | color: function(params) { |
| | | const colors = ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399', '#9C27B0'] |
| | | return colors[params.dataIndex] |
| | | } |
| | | } |
| | | } |
| | | ] |
| | | } |
| | | equipmentChart.setOption(option) |
| | | } |
| | | } |
| | | // è´¨æ£åæ ¼çå¾è¡¨å¼ç¨ |
| | | const materialCompletionChart = ref(null); |
| | | const materialQualityChart = ref(null); |
| | | const semiCompletionChart = ref(null); |
| | | const semiQualityChart = ref(null); |
| | | const finalCompletionChart = ref(null); |
| | | const finalQualityChart = ref(null); |
| | | |
| | | // åå§åæ£æµé¡¹ç®å¾è¡¨ |
| | | const initInspectionChart = () => { |
| | | if (inspectionChartRef.value) { |
| | | inspectionChart = echarts.init(inspectionChartRef.value) |
| | | const option = { |
| | | title: { |
| | | show: false |
| | | }, |
| | | tooltip: { |
| | | trigger: 'item' |
| | | }, |
| | | legend: { |
| | | orient: 'vertical', |
| | | left: 'left' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'æ£æµé¡¹ç®', |
| | | type: 'pie', |
| | | radius: '50%', |
| | | data: [ |
| | | { value: 335, name: 'ç©çæ§è½' }, |
| | | { value: 310, name: 'åå¦åæ' }, |
| | | { value: 234, name: '尺寸æµé' }, |
| | | { value: 135, name: 'å¤è§æ£æ¥' }, |
| | | { value: 148, name: 'å
¶ä»æ£æµ' } |
| | | ], |
| | | emphasis: { |
| | | itemStyle: { |
| | | shadowBlur: 10, |
| | | shadowOffsetX: 0, |
| | | shadowColor: 'rgba(0, 0, 0, 0.5)' |
| | | } |
| | | } |
| | | } |
| | | ] |
| | | } |
| | | inspectionChart.setOption(option) |
| | | } |
| | | } |
| | | // å¾è¡¨å®ä¾ |
| | | let sampleChart = null; |
| | | let equipmentChart = null; |
| | | let inspectionChart = null; |
| | | let usageChart = null; |
| | | |
| | | // åå§åé¢ç¨è®°å½å¾è¡¨ |
| | | const initUsageChart = () => { |
| | | if (usageChartRef.value) { |
| | | usageChart = echarts.init(usageChartRef.value) |
| | | const option = { |
| | | title: { |
| | | show: false |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis' |
| | | }, |
| | | legend: { |
| | | data: ['é¢ç¨æ¬¡æ°', 'å½è¿æ¬¡æ°'] |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | boundaryGap: false, |
| | | data: ['1æ', '2æ', '3æ', '4æ', '5æ', '6æ', '7æ', '8æ', '9æ', '10æ', '11æ', '12æ'] |
| | | }, |
| | | yAxis: { |
| | | type: 'value' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'é¢ç¨æ¬¡æ°', |
| | | type: 'line', |
| | | stack: 'Total', |
| | | data: [120, 132, 101, 134, 90, 230, 210, 182, 191, 234, 290, 330] |
| | | }, |
| | | { |
| | | name: 'å½è¿æ¬¡æ°', |
| | | type: 'line', |
| | | stack: 'Total', |
| | | data: [110, 125, 95, 128, 85, 220, 200, 175, 185, 225, 280, 320] |
| | | } |
| | | ] |
| | | } |
| | | usageChart.setOption(option) |
| | | } |
| | | } |
| | | // è´¨æ£åæ ¼çå¾è¡¨å®ä¾ |
| | | let materialCompletionChartInstance = null; |
| | | let materialQualityChartInstance = null; |
| | | let semiCompletionChartInstance = null; |
| | | let semiQualityChartInstance = null; |
| | | let finalCompletionChartInstance = null; |
| | | let finalQualityChartInstance = null; |
| | | |
| | | // äºä»¶å¤ç彿° |
| | | const handleFilterChange = () => { |
| | | ElMessage.success('çéæ¡ä»¶å·²æ´æ°') |
| | | // è¿éå¯ä»¥æ ¹æ®ç鿡件鿰å è½½æ°æ® |
| | | } |
| | | // åå§åæ°æ® |
| | | const initData = () => { |
| | | // 模æè¡¨æ ¼æ°æ® |
| | | tableData.value = [ |
| | | { |
| | | id: "SP001", |
| | | name: "æ ·åA-001", |
| | | type: "é屿æ", |
| | | status: "æ£æµä¸", |
| | | progress: 75, |
| | | createTime: "2025-01-15 09:30:00", |
| | | updateTime: "2025-01-20 14:20:00", |
| | | }, |
| | | { |
| | | id: "SP002", |
| | | name: "æ ·åB-002", |
| | | type: "塿å¶å", |
| | | status: "已宿", |
| | | progress: 100, |
| | | createTime: "2025-01-10 10:15:00", |
| | | updateTime: "2025-01-18 16:45:00", |
| | | }, |
| | | { |
| | | id: "SP003", |
| | | name: "æ ·åC-003", |
| | | type: "çµåå
ä»¶", |
| | | status: "å¾
æ£æµ", |
| | | progress: 0, |
| | | createTime: "2025-01-22 08:45:00", |
| | | updateTime: "2025-01-22 08:45:00", |
| | | }, |
| | | { |
| | | id: "EQ001", |
| | | name: "æ£æµè®¾å¤A", |
| | | type: "åææ", |
| | | status: "使ç¨ä¸", |
| | | progress: 60, |
| | | createTime: "2025-01-05 14:20:00", |
| | | updateTime: "2025-01-20 11:30:00", |
| | | }, |
| | | { |
| | | id: "EQ002", |
| | | name: "æ£æµè®¾å¤B", |
| | | type: "åæå", |
| | | status: "空é²", |
| | | progress: 0, |
| | | createTime: "2025-01-08 16:10:00", |
| | | updateTime: "2025-01-19 09:15:00", |
| | | }, |
| | | ]; |
| | | |
| | | const resetFilter = () => { |
| | | filterForm.dateRange = [] |
| | | filterForm.reportType = 'sample' |
| | | ElMessage.info('ç鿡件已éç½®') |
| | | } |
| | | pagination.total = tableData.value.length; |
| | | }; |
| | | |
| | | const exportReport = () => { |
| | | ElMessage.success('æ¥è¡¨å¯¼åºåè½å¼åä¸...') |
| | | } |
| | | // åå§åæ ·åè¿åº¦å¾è¡¨ |
| | | const initSampleChart = () => { |
| | | if (sampleChartRef.value) { |
| | | sampleChart = echarts.init(sampleChartRef.value); |
| | | const option = { |
| | | title: { |
| | | show: false, |
| | | }, |
| | | tooltip: { |
| | | trigger: "item", |
| | | formatter: "{a} <br/>{b}: {c} ({d}%)", |
| | | }, |
| | | // legend: { |
| | | // orient: "vertical", |
| | | // left: "left", |
| | | // }, |
| | | series: [ |
| | | { |
| | | name: "æ ·åç¶æ", |
| | | type: "pie", |
| | | radius: ["40%", "80%"], |
| | | avoidLabelOverlap: false, |
| | | label: { |
| | | show: false, |
| | | position: "center", |
| | | }, |
| | | emphasis: { |
| | | label: { |
| | | show: true, |
| | | fontSize: "18", |
| | | fontWeight: "bold", |
| | | }, |
| | | }, |
| | | labelLine: { |
| | | show: false, |
| | | }, |
| | | data: [ |
| | | { value: 450, name: "已宿" }, |
| | | { value: 320, name: "æ£æµä¸" }, |
| | | { value: 280, name: "å¾
æ£æµ" }, |
| | | { value: 200, name: "å·²æå" }, |
| | | ], |
| | | }, |
| | | ], |
| | | }; |
| | | sampleChart.setOption(option); |
| | | } |
| | | }; |
| | | |
| | | const refreshSampleChart = () => { |
| | | initSampleChart() |
| | | ElMessage.success('æ ·åè¿åº¦å¾è¡¨å·²å·æ°') |
| | | } |
| | | // åå§å设å¤ä½¿ç¨å¾è¡¨ |
| | | const initEquipmentChart = () => { |
| | | if (equipmentChartRef.value) { |
| | | equipmentChart = echarts.init(equipmentChartRef.value); |
| | | const option = { |
| | | title: { |
| | | show: false, |
| | | }, |
| | | tooltip: { |
| | | trigger: "axis", |
| | | axisPointer: { |
| | | type: "shadow", |
| | | }, |
| | | }, |
| | | grid: { |
| | | left: "1%", |
| | | right: "1%", |
| | | bottom: "1%", |
| | | containLabel: true, |
| | | }, |
| | | legend: { |
| | | data: ["åææ", "åæå", "æå"], // å¾ä¾æ°æ® |
| | | icon: ["circle", "circle", "circle"], |
| | | itemWidth: 10, // è®¾ç½®å¾æ 宽度 |
| | | itemHeight: 10, |
| | | itemGap: 30, |
| | | right: 10, |
| | | }, |
| | | xAxis: { |
| | | type: "category", |
| | | data: [ |
| | | value3.value.getFullYear() + "-1", |
| | | value3.value.getFullYear() + "-2", |
| | | value3.value.getFullYear() + "-3", |
| | | value3.value.getFullYear() + "-4", |
| | | value3.value.getFullYear() + "-5", |
| | | value3.value.getFullYear() + "-6", |
| | | value3.value.getFullYear() + "-7", |
| | | value3.value.getFullYear() + "-8", |
| | | value3.value.getFullYear() + "-9", |
| | | value3.value.getFullYear() + "-10", |
| | | value3.value.getFullYear() + "-11", |
| | | value3.value.getFullYear() + "-12", |
| | | ], // æ¹ä¸ºåäºä¸ªæ |
| | | }, |
| | | yAxis: { |
| | | type: "value", |
| | | name: "æ°(个)", |
| | | }, |
| | | series: [ |
| | | { |
| | | name: "åææ", |
| | | type: "bar", |
| | | barWidth: "15%", |
| | | data: [85, 75, 80, 85, 90, 88, 92, 87, 89, 91, 93, 95], |
| | | itemStyle: { |
| | | color: "#409EFF", |
| | | }, |
| | | }, |
| | | { |
| | | name: "åæå", |
| | | type: "bar", |
| | | barWidth: "15%", |
| | | |
| | | const refreshEquipmentChart = () => { |
| | | initEquipmentChart() |
| | | ElMessage.success('设å¤ä½¿ç¨å¾è¡¨å·²å·æ°') |
| | | } |
| | | data: [60, 65, 70, 68, 72, 75, 78, 80, 79, 82, 84, 85], |
| | | itemStyle: { |
| | | color: "#67C23A", |
| | | }, |
| | | }, |
| | | { |
| | | name: "æå", |
| | | type: "bar", |
| | | barWidth: "15%", |
| | | |
| | | const refreshInspectionChart = () => { |
| | | initInspectionChart() |
| | | ElMessage.success('æ£æµé¡¹ç®å¾è¡¨å·²å·æ°') |
| | | } |
| | | data: [75, 78, 80, 82, 85, 83, 86, 88, 87, 89, 90, 92], |
| | | itemStyle: { |
| | | color: "#E6A23C", |
| | | }, |
| | | }, |
| | | ], |
| | | }; |
| | | equipmentChart.setOption(option); |
| | | } |
| | | }; |
| | | |
| | | const refreshUsageChart = () => { |
| | | initUsageChart() |
| | | ElMessage.success('é¢ç¨è®°å½å¾è¡¨å·²å·æ°') |
| | | } |
| | | // åå§åæ£æµé¡¹ç®å¾è¡¨ |
| | | const initInspectionChart = () => { |
| | | if (inspectionChartRef.value) { |
| | | inspectionChart = echarts.init(inspectionChartRef.value); |
| | | const option = { |
| | | title: { |
| | | show: false, |
| | | }, |
| | | tooltip: { |
| | | trigger: "item", |
| | | }, |
| | | series: [ |
| | | { |
| | | type: "pie", |
| | | radius: "80%", |
| | | data: [ |
| | | { value: 335, name: "åææ", itemStyle: { color: "#1890FF" } }, |
| | | { value: 310, name: "åæå", itemStyle: { color: "#F7BA1E" } }, |
| | | { value: 234, name: "æå", itemStyle: { color: "#14C9C9" } }, |
| | | ], |
| | | emphasis: { |
| | | itemStyle: { |
| | | shadowBlur: 10, |
| | | shadowOffsetX: 0, |
| | | shadowColor: "rgba(0, 0, 0, 0.5)", |
| | | }, |
| | | }, |
| | | }, |
| | | ], |
| | | }; |
| | | inspectionChart.setOption(option); |
| | | } |
| | | }; |
| | | |
| | | const refreshTable = () => { |
| | | tableLoading.value = true |
| | | setTimeout(() => { |
| | | tableLoading.value = false |
| | | ElMessage.success('è¡¨æ ¼æ°æ®å·²å·æ°') |
| | | }, 1000) |
| | | } |
| | | // åå§åé¢ç¨è®°å½å¾è¡¨ |
| | | const initUsageChart = () => { |
| | | // æ£æ¥å¾è¡¨å®¹å¨æ¯å¦åå¨ |
| | | if (usageChartRef.value) { |
| | | // åå§å ECharts å®ä¾ |
| | | usageChart = echarts.init(usageChartRef.value); |
| | | // é
ç½®å¾è¡¨é项 |
| | | const option = { |
| | | // æ é¢é
ç½®ï¼éèï¼ |
| | | title: { |
| | | show: false, |
| | | }, |
| | | |
| | | const exportTable = () => { |
| | | ElMessage.success('è¡¨æ ¼å¯¼åºåè½å¼åä¸...') |
| | | } |
| | | // ç½æ ¼é
ç½®ï¼è°æ´è¾¹è·ï¼ |
| | | grid: { |
| | | left: "1%", |
| | | right: "4%", |
| | | bottom: "3%", |
| | | top: "14%", |
| | | containLabel: true, |
| | | }, |
| | | // æç¤ºæ¡é
ç½® |
| | | tooltip: { |
| | | trigger: "axis", // 触åç±»åä¸ºåæ è½´è§¦å |
| | | }, |
| | | // å¾ä¾é
ç½® |
| | | legend: { |
| | | data: ["åææ", "åæå", "æå"], // å¾ä¾æ°æ® |
| | | icon: ["circle", "circle", "circle"], |
| | | itemWidth: 10, // è®¾ç½®å¾æ 宽度 |
| | | itemHeight: 10, |
| | | itemGap: 30, |
| | | }, |
| | | // Xè½´é
ç½® |
| | | xAxis: { |
| | | type: "category", // ç±»å«è½´ |
| | | boundaryGap: false, // åæ è½´ä¸¤è¾¹çç½çç¥ |
| | | data: [ |
| | | value3.value.getFullYear() + "-1", |
| | | value3.value.getFullYear() + "-2", |
| | | value3.value.getFullYear() + "-3", |
| | | value3.value.getFullYear() + "-4", |
| | | value3.value.getFullYear() + "-5", |
| | | value3.value.getFullYear() + "-6", |
| | | value3.value.getFullYear() + "-7", |
| | | value3.value.getFullYear() + "-8", |
| | | value3.value.getFullYear() + "-9", |
| | | value3.value.getFullYear() + "-10", |
| | | value3.value.getFullYear() + "-11", |
| | | value3.value.getFullYear() + "-12", |
| | | ], // Xè½´æ°æ® |
| | | }, |
| | | // Yè½´é
ç½® |
| | | yAxis: { |
| | | type: "value", // æ°å¼è½´ |
| | | name: "åä½ï¼%", |
| | | }, |
| | | // ç³»åæ°æ® |
| | | series: [ |
| | | { |
| | | name: "åææ", // ç³»ååç§° |
| | | type: "line", // å¾è¡¨ç±»å为æçº¿å¾ |
| | | stack: "Total", // å å åç§° |
| | | symbol: "none", |
| | | itemStyle: { |
| | | color: "#1890FF", // è®¾ç½®è¿æ¡çº¿çé¢è² |
| | | }, |
| | | data: [120, 132, 101, 134, 90, 230, 210, 182, 191, 234, 290, 330], // é¢ç¨æ¬¡æ°æ°æ® |
| | | }, |
| | | { |
| | | name: "åæå", // ç³»ååç§° |
| | | type: "line", // å¾è¡¨ç±»å为æçº¿å¾ |
| | | stack: "Total", // å å åç§° |
| | | symbol: "none", |
| | | itemStyle: { |
| | | color: "#F7BA1E", // è®¾ç½®è¿æ¡çº¿çé¢è² |
| | | }, |
| | | data: [110, 125, 95, 128, 85, 220, 200, 175, 185, 225, 280, 320], // å½è¿æ¬¡æ°æ°æ® |
| | | }, |
| | | { |
| | | name: "æå", // ç³»ååç§° |
| | | type: "line", // å¾è¡¨ç±»å为æçº¿å¾ |
| | | stack: "Total", // å å åç§° |
| | | symbol: "none", |
| | | itemStyle: { |
| | | color: "#14C9C9", // è®¾ç½®è¿æ¡çº¿çé¢è² |
| | | }, |
| | | data: [110, 125, 95, 128, 85, 220, 200, 175, 185, 225, 280, 320], // å½è¿æ¬¡æ°æ°æ® |
| | | }, |
| | | ], |
| | | }; |
| | | // å°é
ç½®åºç¨å°å¾è¡¨ |
| | | usageChart.setOption(option); |
| | | } |
| | | }; |
| | | |
| | | const handleSizeChange = (val) => { |
| | | pagination.pageSize = val |
| | | // éæ°å è½½æ°æ® |
| | | } |
| | | // åå§åè´¨æ£åæ ¼çå¾è¡¨ |
| | | const initQualityChart = (chartRef, color) => { |
| | | if (chartRef.value) { |
| | | const chart = echarts.init(chartRef.value); |
| | | const option = { |
| | | series: [ |
| | | { |
| | | type: "pie", |
| | | radius: ["45%", "90%"], |
| | | itemStyle: { |
| | | borderColor: "#f5f5f5", |
| | | // borderWidth: 2, |
| | | }, |
| | | labelLine: { |
| | | show: false, |
| | | }, |
| | | data: [ |
| | | { value: 0.8, itemStyle: { color: color } }, |
| | | { value: 0.2, itemStyle: { color: "#f5f5f5" } }, |
| | | ], |
| | | }, |
| | | ], |
| | | }; |
| | | chart.setOption(option); |
| | | return chart; |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const handleCurrentChange = (val) => { |
| | | pagination.currentPage = val |
| | | // éæ°å è½½æ°æ® |
| | | } |
| | | // åå§åææè´¨æ£åæ ¼çå¾è¡¨ |
| | | const initAllQualityCharts = () => { |
| | | materialCompletionChartInstance = initQualityChart( |
| | | materialCompletionChart, |
| | | "#1890ff" |
| | | ); |
| | | materialQualityChartInstance = initQualityChart( |
| | | materialQualityChart, |
| | | "#52c41a" |
| | | ); |
| | | semiCompletionChartInstance = initQualityChart( |
| | | semiCompletionChart, |
| | | "#1890ff" |
| | | ); |
| | | semiQualityChartInstance = initQualityChart(semiQualityChart, "#52c41a"); |
| | | finalCompletionChartInstance = initQualityChart( |
| | | finalCompletionChart, |
| | | "#1890ff" |
| | | ); |
| | | finalQualityChartInstance = initQualityChart(finalQualityChart, "#722ed1"); |
| | | }; |
| | | |
| | | const getStatusType = (status) => { |
| | | const statusMap = { |
| | | '已宿': 'success', |
| | | 'æ£æµä¸': 'warning', |
| | | 'å¾
æ£æµ': 'info', |
| | | 'å·²æå': 'danger', |
| | | '使ç¨ä¸': 'primary', |
| | | '空é²': 'info' |
| | | } |
| | | return statusMap[status] || 'info' |
| | | } |
| | | // äºä»¶å¤ç彿° |
| | | const handleFilterChange = () => { |
| | | ElMessage.success("çéæ¡ä»¶å·²æ´æ°"); |
| | | // è¿éå¯ä»¥æ ¹æ®ç鿡件鿰å è½½æ°æ® |
| | | }; |
| | | |
| | | const getProgressStatus = (progress) => { |
| | | if (progress === 100) return 'success' |
| | | if (progress >= 80) return 'warning' |
| | | if (progress >= 50) return '' |
| | | return 'exception' |
| | | } |
| | | const resetFilter = () => { |
| | | filterForm.dateRange = []; |
| | | filterForm.reportType = "sample"; |
| | | ElMessage.info("ç鿡件已éç½®"); |
| | | }; |
| | | |
| | | const viewDetail = (row) => { |
| | | ElMessage.info(`æ¥ç详æ
: ${row.name}`) |
| | | } |
| | | const exportReport = () => { |
| | | ElMessage.success("æ¥è¡¨å¯¼åºåè½å¼åä¸..."); |
| | | }; |
| | | |
| | | const editItem = (row) => { |
| | | ElMessage.info(`ç¼è¾é¡¹ç®: ${row.name}`) |
| | | } |
| | | const refreshSampleChart = () => { |
| | | initSampleChart(); |
| | | ElMessage.success("æ ·åè¿åº¦å¾è¡¨å·²å·æ°"); |
| | | }; |
| | | |
| | | // çå½å¨æ |
| | | onMounted(() => { |
| | | initData() |
| | | nextTick(() => { |
| | | initSampleChart() |
| | | initEquipmentChart() |
| | | initInspectionChart() |
| | | initUsageChart() |
| | | }) |
| | | |
| | | // çå¬çªå£å¤§å°ååï¼éæ°è°æ´å¾è¡¨å¤§å° |
| | | window.addEventListener('resize', () => { |
| | | sampleChart?.resize() |
| | | equipmentChart?.resize() |
| | | inspectionChart?.resize() |
| | | usageChart?.resize() |
| | | }) |
| | | }) |
| | | const refreshEquipmentChart = () => { |
| | | initEquipmentChart(); |
| | | ElMessage.success("设å¤ä½¿ç¨å¾è¡¨å·²å·æ°"); |
| | | }; |
| | | |
| | | const refreshInspectionChart = () => { |
| | | initInspectionChart(); |
| | | ElMessage.success("æ£æµé¡¹ç®å¾è¡¨å·²å·æ°"); |
| | | }; |
| | | |
| | | const refreshUsageChart = () => { |
| | | initUsageChart(); |
| | | ElMessage.success("é¢ç¨è®°å½å¾è¡¨å·²å·æ°"); |
| | | }; |
| | | |
| | | const refreshTable = () => { |
| | | tableLoading.value = true; |
| | | setTimeout(() => { |
| | | tableLoading.value = false; |
| | | ElMessage.success("è¡¨æ ¼æ°æ®å·²å·æ°"); |
| | | }, 1000); |
| | | }; |
| | | |
| | | const exportTable = () => { |
| | | ElMessage.success("è¡¨æ ¼å¯¼åºåè½å¼åä¸..."); |
| | | }; |
| | | |
| | | const handleSizeChange = val => { |
| | | pagination.pageSize = val; |
| | | // éæ°å è½½æ°æ® |
| | | }; |
| | | |
| | | const handleCurrentChange = val => { |
| | | pagination.currentPage = val; |
| | | // éæ°å è½½æ°æ® |
| | | }; |
| | | |
| | | const getStatusType = status => { |
| | | const statusMap = { |
| | | 已宿: "success", |
| | | æ£æµä¸: "warning", |
| | | å¾
æ£æµ: "info", |
| | | å·²æå: "danger", |
| | | 使ç¨ä¸: "primary", |
| | | 空é²: "info", |
| | | }; |
| | | return statusMap[status] || "info"; |
| | | }; |
| | | |
| | | const getProgressStatus = progress => { |
| | | if (progress === 100) return "success"; |
| | | if (progress >= 80) return "warning"; |
| | | if (progress >= 50) return ""; |
| | | return "exception"; |
| | | }; |
| | | |
| | | const viewDetail = row => { |
| | | ElMessage.info(`æ¥ç详æ
: ${row.name}`); |
| | | }; |
| | | |
| | | const editItem = row => { |
| | | ElMessage.info(`ç¼è¾é¡¹ç®: ${row.name}`); |
| | | }; |
| | | |
| | | // çå½å¨æ |
| | | onMounted(() => { |
| | | initData(); |
| | | nextTick(() => { |
| | | initSampleChart(); |
| | | initEquipmentChart(); |
| | | initInspectionChart(); |
| | | initUsageChart(); |
| | | initAllQualityCharts(); |
| | | }); |
| | | // çå¬çªå£å¤§å°ååï¼éæ°è°æ´å¾è¡¨å¤§å° |
| | | window.addEventListener("resize", () => { |
| | | sampleChart?.resize(); |
| | | equipmentChart?.resize(); |
| | | inspectionChart?.resize(); |
| | | usageChart?.resize(); |
| | | |
| | | // è°æ´è´¨æ£åæ ¼çå¾è¡¨å¤§å° |
| | | materialCompletionChartInstance?.resize(); |
| | | materialQualityChartInstance?.resize(); |
| | | semiCompletionChartInstance?.resize(); |
| | | semiQualityChartInstance?.resize(); |
| | | finalCompletionChartInstance?.resize(); |
| | | finalQualityChartInstance?.resize(); |
| | | }); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .report-management { |
| | | padding: 20px; |
| | | background-color: #f5f5f5; |
| | | min-height: 100vh; |
| | | } |
| | | .report-management { |
| | | padding: 20px; |
| | | background-color: #f5f5f5; |
| | | min-height: 100vh; |
| | | /* height: 87vh; |
| | | overflow: hidden; */ |
| | | } |
| | | |
| | | .page-header { |
| | | margin-bottom: 20px; |
| | | text-align: center; |
| | | } |
| | | .page-header { |
| | | margin-bottom: 20px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .page-header h2 { |
| | | color: #303133; |
| | | margin-bottom: 8px; |
| | | font-size: 24px; |
| | | font-weight: 600; |
| | | } |
| | | .page-header h2 { |
| | | color: #303133; |
| | | margin-bottom: 8px; |
| | | font-size: 24px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .page-header p { |
| | | color: #909399; |
| | | font-size: 14px; |
| | | margin: 0; |
| | | } |
| | | .page-header p { |
| | | color: #909399; |
| | | font-size: 14px; |
| | | margin: 0; |
| | | } |
| | | |
| | | .filter-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | .filter-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .statistics-cards { |
| | | margin-bottom: 20px; |
| | | } |
| | | .statistics-cards { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .stat-card { |
| | | height: 120px; |
| | | } |
| | | .stat-card { |
| | | height: 120px; |
| | | } |
| | | |
| | | .stat-content { |
| | | display: flex; |
| | | align-items: center; |
| | | height: 100%; |
| | | } |
| | | .stat-content { |
| | | display: flex; |
| | | align-items: center; |
| | | height: 100%; |
| | | } |
| | | |
| | | .stat-icon { |
| | | width: 60px; |
| | | height: 60px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-right: 20px; |
| | | font-size: 24px; |
| | | color: white; |
| | | } |
| | | .stat-icon { |
| | | width: 60px; |
| | | height: 60px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-right: 20px; |
| | | font-size: 24px; |
| | | color: white; |
| | | } |
| | | |
| | | .stat-card:nth-child(1) .stat-icon { |
| | | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | | } |
| | | .stat-card:nth-child(1) .stat-icon { |
| | | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | | } |
| | | |
| | | .stat-card:nth-child(2) .stat-icon { |
| | | background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); |
| | | } |
| | | .stat-card:nth-child(2) .stat-icon { |
| | | background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); |
| | | } |
| | | |
| | | .stat-card:nth-child(3) .stat-icon { |
| | | background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); |
| | | } |
| | | .stat-card:nth-child(3) .stat-icon { |
| | | background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); |
| | | } |
| | | |
| | | .stat-card:nth-child(4) .stat-icon { |
| | | background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); |
| | | } |
| | | .stat-card:nth-child(4) .stat-icon { |
| | | background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); |
| | | } |
| | | |
| | | .stat-info { |
| | | flex: 1; |
| | | } |
| | | .stat-info { |
| | | flex: 1; |
| | | } |
| | | |
| | | .stat-number { |
| | | font-size: 28px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 8px; |
| | | } |
| | | .stat-number { |
| | | font-size: 28px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .stat-label { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | .stat-label { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .charts-container { |
| | | margin-bottom: 20px; |
| | | } |
| | | .charts-container { |
| | | /* margin-bottom: 20px; */ |
| | | position: relative; |
| | | } |
| | | |
| | | .chart-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | .chart-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | .container-line-right-bottom { |
| | | height: 20%; |
| | | width: 100%; |
| | | display: flex; |
| | | justify-content: space-evenly; |
| | | align-items: center; |
| | | /* background-color: #5b3f3f; */ |
| | | } |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | font-family: Source Han Sans, Source Han Sans; |
| | | font-weight: 700; |
| | | font-size: 18px; |
| | | color: #000000; |
| | | /* line-height: 27px; */ |
| | | text-align: left; |
| | | font-style: normal; |
| | | text-transform: none; |
| | | } |
| | | .chart-title-line { |
| | | width: 6px; |
| | | height: 22px; |
| | | background-color: #161a9a; |
| | | margin-right: 16px; |
| | | border-radius: 3px; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | .chart-container { |
| | | height: 250px; |
| | | width: 100%; |
| | | } |
| | | .chart-container-line { |
| | | height: 250px; |
| | | width: 100%; |
| | | display: flex; |
| | | position: relative; |
| | | } |
| | | |
| | | .chart-container { |
| | | height: 300px; |
| | | width: 100%; |
| | | } |
| | | /* Tab 鿩卿 ·å¼ */ |
| | | .tab-selector { |
| | | position: absolute; |
| | | top: 20px; |
| | | right: 40px; |
| | | display: flex; |
| | | border: 1px solid #dcdfe6; |
| | | border-radius: 4px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .table-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | .tab-item { |
| | | padding: 4px 12px; |
| | | cursor: pointer; |
| | | font-size: 14px; |
| | | color: #606266; |
| | | background-color: #fff; |
| | | border-right: 1px solid #dcdfe6; |
| | | transition: all 0.3s; |
| | | } |
| | | |
| | | .pagination-container { |
| | | margin-top: 20px; |
| | | text-align: right; |
| | | } |
| | | .tab-item:last-child { |
| | | border-right: none; |
| | | } |
| | | |
| | | :deep(.el-card__header) { |
| | | padding: 15px 20px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | background-color: #fafafa; |
| | | } |
| | | .tab-item:hover { |
| | | color: #409eff; |
| | | } |
| | | |
| | | :deep(.el-card__body) { |
| | | padding: 20px; |
| | | } |
| | | .tab-item.active { |
| | | color: #fff; |
| | | background-color: #409eff; |
| | | } |
| | | .container-line-left { |
| | | height: 100%; |
| | | width: 66%; |
| | | } |
| | | .container-line-right { |
| | | height: 100%; |
| | | width: 34%; |
| | | } |
| | | .container-line2-left { |
| | | height: 100%; |
| | | width: 50%; |
| | | } |
| | | .info-box { |
| | | width: 92%; |
| | | margin-left: 4%; |
| | | height: 100%; |
| | | background-color: #f7f8fa; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: space-around; |
| | | } |
| | | .info-box-header { |
| | | width: 100%; |
| | | margin-left: 20px; |
| | | color: #1d2129; |
| | | font-size: 16px; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | margin-bottom: 20px; |
| | | } |
| | | .info-line { |
| | | width: 100%; |
| | | display: flex; |
| | | padding-left: 20px; |
| | | align-items: center; |
| | | } |
| | | .info-icon { |
| | | width: 7px; |
| | | height: 7px; |
| | | border-radius: 50%; |
| | | margin-right: 8px; |
| | | } |
| | | .info-line-title { |
| | | font-size: 12px; |
| | | color: #4e5969; |
| | | flex: 1; |
| | | } |
| | | .info-line-value1 { |
| | | font-size: 12px; |
| | | color: #3d3d3d; |
| | | color: #1d2129; |
| | | font-weight: 500; |
| | | margin-right: 15%; |
| | | } |
| | | .info-line-value2 { |
| | | font-size: 12px; |
| | | color: #3d3d3d; |
| | | color: #1d2129; |
| | | font-weight: 500; |
| | | margin-right: 10%; |
| | | } |
| | | .top-container { |
| | | height: 130px; |
| | | width: 100%; |
| | | display: flex; |
| | | } |
| | | .typeNum { |
| | | height: 100%; |
| | | width: 33.33%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .typeNum-left { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .typeNum-left-text { |
| | | font-size: 12px; |
| | | color: #3491fa; |
| | | font-weight: 500; |
| | | margin-top: 5px; |
| | | } |
| | | .table-card { |
| | | margin-bottom: 20px; |
| | | } |
| | | .typeNum-center { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-left: 10px; |
| | | } |
| | | .typeNum-leftLine { |
| | | color: #3491fa; |
| | | font-size: 12px; |
| | | } |
| | | .typeNum-rightLine { |
| | | border-top: 1px solid #3491fa; |
| | | border-left: 1px solid #3491fa; |
| | | border-bottom: 1px solid #3491fa; |
| | | height: 80px; |
| | | width: 8px; |
| | | } |
| | | .typeNum-leftLine2 { |
| | | color: #5eb334; |
| | | font-size: 12px; |
| | | } |
| | | .typeNum-rightLine2 { |
| | | border-top: 1px solid #3491fa; |
| | | border-left: 1px solid #5eb334; |
| | | border-bottom: 1px solid #5eb334; |
| | | height: 80px; |
| | | width: 8px; |
| | | } |
| | | .typeNum-leftLine3 { |
| | | color: #8000ff; |
| | | font-size: 12px; |
| | | } |
| | | .typeNum-rightLine3 { |
| | | border-top: 1px solid #8000ff; |
| | | border-left: 1px solid #8000ff; |
| | | border-bottom: 1px solid #8000ff; |
| | | height: 80px; |
| | | width: 8px; |
| | | } |
| | | .typeNum-right { |
| | | margin-left: 10px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | height: 90%; |
| | | justify-content: space-between; |
| | | } |
| | | .typeNum-right-top-name { |
| | | font-weight: 400; |
| | | font-size: 12px; |
| | | color: #3d3d3d; |
| | | } |
| | | .typeNum-right-top-text { |
| | | font-weight: 400; |
| | | font-size: 16px; |
| | | color: rgba(0, 0, 0, 0.85); |
| | | margin-top: 5px; |
| | | } |
| | | .unit { |
| | | font-size: 12px; |
| | | color: #3d3d3d; |
| | | } |
| | | .inspection-chart-box { |
| | | height: 50px; |
| | | width: 30%; |
| | | background-color: #f7f8fa; |
| | | border-radius: 8px; |
| | | padding-left: 15px; |
| | | } |
| | | .chart-box-title { |
| | | font-size: 12px; |
| | | color: #4e5969; |
| | | margin-top: 5px; |
| | | } |
| | | .unit { |
| | | font-size: 12px; |
| | | color: #3d3d3d; |
| | | } |
| | | .chart-box-num { |
| | | font-size: 18px; |
| | | color: #000; |
| | | margin-top: 5px; |
| | | font-weight: 500; |
| | | } |
| | | /* è´¨æ£åæ ¼çå¡çæ ·å¼ */ |
| | | .top-containeråæ ¼ç { |
| | | height: 130px; |
| | | width: 100%; |
| | | display: flex; |
| | | gap: 15px; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | .flex-center { |
| | | justify-content: space-evenly; |
| | | } |
| | | .quality-card { |
| | | /* flex: 1; */ |
| | | width: 32%; |
| | | /* height: 100px; */ |
| | | border-radius: 8px; |
| | | padding: 12px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | :deep(.el-progress) { |
| | | margin: 0; |
| | | } |
| | | .blue-card { |
| | | background-color: #e6f7ff; |
| | | } |
| | | |
| | | :deep(.el-tag) { |
| | | margin: 0; |
| | | } |
| | | .green-card { |
| | | background-color: #f6ffed; |
| | | color: #000000; |
| | | } |
| | | |
| | | .purple-card { |
| | | background-color: #f9f0ff; |
| | | } |
| | | |
| | | .quality-card-title { |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | margin-bottom: 10px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .quality-item-tip { |
| | | font-size: 12px; |
| | | color: #666666; |
| | | margin-bottom: 3px; |
| | | } |
| | | .blue-label { |
| | | color: #1890ff; |
| | | } |
| | | .green-label { |
| | | color: #52c41a; |
| | | } |
| | | |
| | | .quality-card-title { |
| | | color: #000; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .quality-card-content { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | flex: 1; |
| | | } |
| | | |
| | | .quality-item { |
| | | display: flex; |
| | | /* flex-direction: column; */ |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-top: 5px; |
| | | flex: 1; |
| | | } |
| | | |
| | | .quality-item-label { |
| | | font-size: 12px; |
| | | /* color: #666; */ |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .quality-item-value { |
| | | font-size: 20px; |
| | | font-weight: 500; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .quality-item-chart { |
| | | width: 60px; |
| | | height: 60px; |
| | | margin-left: 10px; |
| | | } |
| | | /* .flex-center { |
| | | justify-content: space-evenly; |
| | | } */ |
| | | |
| | | .blue-chart { |
| | | /* background-color: rgba(24, 144, 255, 0.1); */ |
| | | } |
| | | |
| | | .green-chart { |
| | | /* background-color: rgba(82, 196, 26, 0.1); */ |
| | | } |
| | | |
| | | .purple-chart { |
| | | /* background-color: rgba(114, 46, 209, 0.1); */ |
| | | } |
| | | |
| | | .chart-ring { |
| | | width: 60px; |
| | | height: 60px; |
| | | border-radius: 50%; |
| | | border: 15px solid transparent; |
| | | position: relative; |
| | | } |
| | | |
| | | .blue-chart .chart-ring { |
| | | border-top-color: #1890ff; |
| | | border-right-color: #1890ff; |
| | | border-bottom-color: #1890ff; |
| | | transform: rotate(45deg); |
| | | } |
| | | |
| | | .green-chart .chart-ring { |
| | | border-top-color: #52c41a; |
| | | border-right-color: #52c41a; |
| | | border-bottom-color: #52c41a; |
| | | transform: rotate(45deg); |
| | | } |
| | | |
| | | .purple-chart .chart-ring { |
| | | border-top-color: #722ed1; |
| | | border-right-color: #722ed1; |
| | | border-bottom-color: #722ed1; |
| | | transform: rotate(45deg); |
| | | } |
| | | |
| | | .pagination-container { |
| | | margin-top: 20px; |
| | | text-align: right; |
| | | } |
| | | .yearchange { |
| | | position: absolute; |
| | | right: 40px; |
| | | top: 20px; |
| | | display: flex; |
| | | align-items: center; |
| | | /* width: 60px; */ |
| | | } |
| | | |
| | | :deep(.el-card__header) { |
| | | padding: 15px 20px; |
| | | border-bottom: 1px solid #ffffff; |
| | | background-color: #ffffff; |
| | | } |
| | | |
| | | :deep(.el-card__body) { |
| | | padding: 20px; |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | :deep(.el-progress) { |
| | | margin: 0; |
| | | } |
| | | |
| | | :deep(.el-tag) { |
| | | margin: 0; |
| | | } |
| | | :deep(.el-input__prefix) { |
| | | display: none !important; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="dialogVisible" title="éä»¶" width="40%" :before-close="handleClose"> |
| | | <el-table :data="tableData" border height="40vh"> |
| | | <el-table-column label="éä»¶åç§°" prop="name" min-width="400" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">ä¸è½½</el-button> |
| | | <el-button link type="primary" size="small" @click="lookFile(scope.row)">é¢è§</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-dialog> |
| | | <filePreview ref="filePreviewRef" /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | import filePreview from '@/components/filePreview/index.vue' |
| | | |
| | | const dialogVisible = ref(false) |
| | | const tableData = ref([]) |
| | | const { proxy } = getCurrentInstance(); |
| | | const filePreviewRef = ref() |
| | | const handleClose = () => { |
| | | dialogVisible.value = false |
| | | } |
| | | const open = (list) => { |
| | | dialogVisible.value = true |
| | | tableData.value = list |
| | | } |
| | | const downLoadFile = (row) => { |
| | | proxy.$download.name(row.url); |
| | | |
| | | } |
| | | const lookFile = (row) => { |
| | | filePreviewRef.value.open(row.url) |
| | | } |
| | | defineExpose({ |
| | | open |
| | | }) |
| | | </script> |
| | | |
| | | <style></style> |
| | |
| | | <el-input v-model="searchForm.customerName" placeholder="请è¾å
¥" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="客æ·ååå·ï¼"> |
| | | <el-input v-model="searchForm.customerContractNo" placeholder="请è¾å
¥" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="éå®ååå·ï¼"> |
| | | <el-input v-model="searchForm.salesContractNo" placeholder="请è¾å
¥" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="项ç®åç§°ï¼"> |
| | | <el-input v-model="searchForm.projectName" placeholder="请è¾å
¥" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="å½å
¥æ¥æï¼"> |
| | |
| | | <el-button type="primary" @click="openForm('add')"> |
| | | æ°å¢å°è´¦ |
| | | </el-button> |
| | | <el-button @click="handleImport">导å
¥</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | <el-button type="primary" plain @click="handlePrint">æå°</el-button> |
| | |
| | | </div> |
| | | <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary style="width: 100%" |
| | | :summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 21em)"> |
| | | :summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 18.5em)"> |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column type="expand"> |
| | | <template #default="props"> |
| | |
| | | <el-table-column label="产å大类" prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" prop="specificationModel" /> |
| | | <el-table-column label="åä½" prop="unit" /> |
| | | <el-table-column label="产åç¶æ" width="100px" align="center"> |
| | | <template #default="scope"> |
| | | <el-tag v-if="scope.row.approveStatus === 0" type="info">æªåºåº</el-tag> |
| | | <el-tag v-if="scope.row.approveStatus === 1" type="success">å·²åºåº</el-tag> |
| | | <el-tag v-if="scope.row.approveStatus === 2" type="warning">å®¡æ ¸ä¸</el-tag> |
| | | <el-tag v-if="scope.row.approveStatus === 3" type="success">å®¡æ ¸æå</el-tag> |
| | | <el-tag v-if="scope.row.approveStatus === 4" type="danger">å®¡æ ¸å¤±è´¥</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å货车ç" minWidth="100px" align="center"> |
| | | <template #default="scope"> |
| | | <div> |
| | | <el-tag type="success" v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</el-tag> |
| | | <el-tag v-else type="info">æªåè´§</el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åè´§æ¥æ" minWidth="100px" align="center"> |
| | | <template #default="scope"> |
| | | <div> |
| | | <div v-if="scope.row.shippingDate">{{ scope.row.shippingDate }}</div> |
| | | <el-tag v-else type="info">æªåè´§</el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ°é" prop="quantity" /> |
| | | <el-table-column label="ç¨ç(%)" prop="taxRate" /> |
| | | <el-table-column label="å«ç¨åä»·(å
)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> |
| | | <el-table-column label="ä¸å«ç¨æ»ä»·(å
)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> |
| | | <!--æä½--> |
| | | <el-table-column Width="60px" label="æä½" align="center"> |
| | | <template #default="scope"> |
| | | <el-button :disabled="scope.row.approveStatus!==2 || scope.row.approveStatus!==5" link type="primary" size="small" @click="openDeliveryForm(scope.row)">åè´§</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="éå®ååå·" prop="salesContractNo" width="180" show-overflow-tooltip /> |
| | | <el-table-column label="客æ·ååå·" prop="customerContractNo" width="180" show-overflow-tooltip /> |
| | | <el-table-column label="客æ·åç§°" prop="customerName" width="300" show-overflow-tooltip /> |
| | | <el-table-column label="ä¸å¡å" prop="salesman" width="100" show-overflow-tooltip /> |
| | | <el-table-column label="项ç®åç§°" prop="projectName" width="180" show-overflow-tooltip /> |
| | | <el-table-column label="仿¬¾æ¹å¼" prop="paymentMethod" show-overflow-tooltip /> |
| | | <el-table-column label="ååéé¢(å
)" prop="contractAmount" width="220" show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="å½å
¥äºº" prop="entryPersonName" width="100" show-overflow-tooltip /> |
| | | <el-table-column label="çäº§ç¶æ" prop="productionStatus" width="100" show-overflow-tooltip > |
| | | <template #default="scope"> |
| | | <div> |
| | | <el-tag v-if="scope.row.productionStatus === '已宿'" type="success">已宿</el-tag> |
| | | <el-tag v-if="scope.row.productionStatus === 'ç产ä¸'" type="warning">ç产ä¸</el-tag> |
| | | <el-tag v-if="scope.row.productionStatus === 'æªå¼å§'" type="danger">æªå¼å§</el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å货车ç" prop="shippingCarNumber" width="120" show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <div> |
| | | <div v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</div> |
| | | <el-tag v-else type="warning">æªåè´§</el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åè´§æ¥æ" prop="shippingDate" width="120" show-overflow-tooltip /> |
| | | <el-table-column label="ç¾è®¢æ¥æ" prop="executionDate" width="120" show-overflow-tooltip /> |
| | | <el-table-column label="å½å
¥æ¥æ" prop="entryDate" width="120" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" min-width="200" align="center"> |
| | | <el-table-column label="ç¾è®¢æ¥æ" prop="executionDate" width="120" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" min-width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">ç¼è¾</el-button> |
| | | <!-- <el-button link type="primary" size="small" @click="openForm('view', scope.row)">详æ
</el-button>--> |
| | | <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">éä»¶</el-button> |
| | | <el-button v-if="!scope.row.shippingCarNumber" link type="primary" size="small" @click="openDeliveryForm(scope.row)">åè´§</el-button> |
| | | <!-- <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">åè´§</el-button>--> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" :limit="page.size" @pagination="paginationChange" /> |
| | | </div> |
| | | <FormDialog |
| | | v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢éå®å°è´¦é¡µé¢' : 'ç¼è¾éå®å°è´¦é¡µé¢'" |
| | | :width="'70%'" |
| | | :operation-type="operationType" |
| | | @close="closeDia" |
| | | @confirm="submitForm" |
| | | @cancel="closeDia"> |
| | | <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? 'æ°å¢éå®å°è´¦é¡µé¢' : 'ç¼è¾éå®å°è´¦é¡µé¢'" width="70%" |
| | | @close="closeDia"> |
| | | <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> |
| | | <el-row v-if="operationType !== 'view'"> |
| | | <el-col :span="24" style="display:flex; justify-content:flex-end; gap:10px; margin-bottom: 6px;"> |
| | | <el-button type="primary" plain @click="openQuotationDialog">ä»å®¡æ¹éè¿çæ¥ä»·å导å
¥</el-button> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éå®ååå·ï¼" prop="salesContractNo"> |
| | |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¸å¡åï¼" prop="salesman"> |
| | | <el-select v-model="form.salesman" |
| | | filterable |
| | | :reserve-keyword="false" placeholder="è¯·éæ©" clearable :disabled="operationType === 'view'"> |
| | | <el-select v-model="form.salesman" placeholder="è¯·éæ©" clearable :disabled="operationType === 'view'"> |
| | | <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" |
| | | :value="item.nickName" /> |
| | | </el-select> |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="客æ·ååå·ï¼" prop="customerContractNo"> |
| | | <el-input v-model="form.customerContractNo" placeholder="请è¾å
¥" clearable :disabled="operationType === 'view'"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="客æ·åç§°ï¼" prop="customerId"> |
| | | <el-select v-model="form.customerId" placeholder="è¯·éæ©" clearable :disabled="operationType === 'view'" filterable> |
| | | <el-select v-model="form.customerId" placeholder="è¯·éæ©" clearable :disabled="operationType === 'view'"> |
| | | <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id"> |
| | | {{ |
| | | item.customerName + "ââ" + item.taxpayerIdentificationNumber |
| | | }} |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="项ç®åç§°ï¼" prop="projectName"> |
| | | <el-input v-model="form.projectName" placeholder="请è¾å
¥" clearable :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å½å
¥äººï¼" prop="entryPerson"> |
| | | <el-select v-model="form.entryPerson" |
| | | filterable |
| | | default-first-option |
| | | :reserve-keyword="false" placeholder="è¯·éæ©" clearable @change="changs"> |
| | | <el-select v-model="form.entryPerson" placeholder="è¯·éæ©" clearable @change="changs" disabled> |
| | | <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="仿¬¾æ¹å¼"> |
| | | <el-input v-model="form.paymentMethod" placeholder="请è¾å
¥" clearable :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-form-item label="产åä¿¡æ¯ï¼" prop="entryDate"> |
| | | <el-button v-if="operationType !== 'view'" type="primary" @click="openProductForm('add')">æ·»å </el-button> |
| | |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | |
| | | <!-- 仿¥ä»·å导å
¥ï¼ä»
审æ¹éè¿ï¼ --> |
| | | <el-dialog |
| | | v-model="quotationDialogVisible" |
| | | title="鿩审æ¹éè¿çé宿¥ä»·å" |
| | | width="80%" |
| | | :close-on-click-modal="false" |
| | | > |
| | | <div style="margin-bottom: 12px; display:flex; gap: 12px; align-items:center;"> |
| | | <el-input |
| | | v-model="quotationSearchForm.quotationNo" |
| | | placeholder="请è¾å
¥æ¥ä»·åå·" |
| | | clearable |
| | | style="max-width: 260px;" |
| | | @change="fetchQuotationList" |
| | | /> |
| | | <el-input |
| | | v-model="quotationSearchForm.customer" |
| | | placeholder="请è¾å
¥å®¢æ·åç§°" |
| | | clearable |
| | | style="max-width: 260px;" |
| | | @change="fetchQuotationList" |
| | | /> |
| | | <el-button type="primary" @click="fetchQuotationList">æç´¢</el-button> |
| | | <el-button @click="resetQuotationSearch">éç½®</el-button> |
| | | </div> |
| | | |
| | | <el-table |
| | | :data="quotationList" |
| | | border |
| | | stripe |
| | | v-loading="quotationLoading" |
| | | height="420px" |
| | | > |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column prop="quotationNo" label="æ¥ä»·åå·" width="180" show-overflow-tooltip /> |
| | | <el-table-column prop="customer" label="客æ·åç§°" min-width="220" show-overflow-tooltip /> |
| | | <el-table-column prop="salesperson" label="ä¸å¡å" width="120" show-overflow-tooltip /> |
| | | <el-table-column prop="quotationDate" label="æ¥ä»·æ¥æ" width="140" /> |
| | | <el-table-column prop="status" label="审æ¹ç¶æ" width="120" align="center" /> |
| | | <el-table-column prop="totalAmount" label="æ¥ä»·éé¢(å
)" width="160" align="right"> |
| | | <template #default="scope"> |
| | | {{ Number(scope.row.totalAmount ?? 0).toFixed(2) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" label="æä½" width="120" align="center"> |
| | | <template #default="scope"> |
| | | <el-button type="primary" link @click="applyQuotation(scope.row)">éæ©</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <template #footer> |
| | | <el-button @click="quotationDialogVisible = false">å
³é</el-button> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <FormDialog |
| | | v-model="productFormVisible" |
| | | :title="productOperationType === 'add' ? 'æ°å¢äº§å' : 'ç¼è¾äº§å'" |
| | | :width="'40%'" |
| | | :operation-type="productOperationType" |
| | | @close="closeProductDia" |
| | | @confirm="submitProduct" |
| | | @cancel="closeProductDia"> |
| | | <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? 'æ°å¢äº§å' : 'ç¼è¾äº§å'" width="40%" @close="closeProductDia"> |
| | | <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="è§æ ¼åå·ï¼" prop="productModelId"> |
| | | <el-select v-model="productForm.productModelId" placeholder="è¯·éæ©" clearable @change="getProductModel" filterable> |
| | | <el-select v-model="productForm.productModelId" placeholder="è¯·éæ©" clearable @change="getProductModel"> |
| | | <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitProduct">确认</el-button> |
| | | <el-button @click="closeProductDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- æå°é¢è§å¼¹çª --> |
| | | <el-dialog |
| | | v-model="printPreviewVisible" |
| | |
| | | <span class="value">{{ formatDate(item.createTime) }}</span> |
| | | </div> |
| | | <div> |
| | | <span class="label">å货车çå·ï¼</span> |
| | | <span class="value">{{ item.shippingCarNumber }}</span> |
| | | </div> |
| | | </div> |
| | | <div class="info-row"> |
| | | <div> |
| | | |
| | | <span class="label">客æ·åç§°ï¼</span> |
| | | <span class="value">{{ item.customerName || 'å¼ ç±æ' }}</span> |
| | | </div> |
| | | </div> |
| | | <div class="info-row"> |
| | | <span class="label">åå·ï¼</span> |
| | | <span class="value">{{ item.salesContractNo }}</span> |
| | | </div> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="审æ¹äººï¼" prop="approverId"> |
| | | <el-select v-model="deliveryForm.approverId" placeholder="è¯·éæ©å®¡æ¹äºº" clearable :disabled="operationType === 'view'"> |
| | | <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | |
| | | import { UploadFilled } from "@element-plus/icons-vue"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import FileListDialog from '@/components/Dialog/FileListDialog.vue'; |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue'; |
| | | import { getQuotationList } from "@/api/salesManagement/salesQuotation.js"; |
| | | import FileList from "./fileList.vue"; |
| | | import { |
| | | ledgerListPage, |
| | | productList, |
| | | customerList, |
| | | addOrUpdateSalesLedger, |
| | | getSalesLedgerWithProducts, |
| | | delLedger, |
| | | addOrUpdateSalesLedgerProduct, |
| | | delProduct, |
| | | delLedgerFile, getProductInventory, |
| | | ledgerListPage, |
| | | productList, |
| | | customerList, |
| | | addOrUpdateSalesLedger, |
| | | getSalesLedgerWithProducts, |
| | | delLedger, |
| | | addOrUpdateSalesLedgerProduct, |
| | | delProduct, |
| | | delLedgerFile, getProductInventory, |
| | | } from "@/api/salesManagement/salesLedger.js"; |
| | | import { modelList, productTreeList } from "@/api/basicData/product.js"; |
| | | import useFormData from "@/hooks/useFormData.js"; |
| | | import dayjs from "dayjs"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | |
| | | const userStore = useUserStore(); |
| | | const { proxy } = getCurrentInstance(); |
| | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | customerName: "", // 客æ·åç§° |
| | | customerContractNo: "", // 客æ·ååç¼å· |
| | | salesContractNo: "", // éå®ååç¼å· |
| | | projectName: "", // 项ç®åç§° |
| | | entryDate: null, // å½å
¥æ¥æ |
| | | entryDateStart: undefined, |
| | | entryDateEnd: undefined, |
| | |
| | | form: { |
| | | salesContractNo: "", |
| | | salesman: "", |
| | | customerContractNo: "", |
| | | customerId: "", |
| | | projectName: "", |
| | | entryPerson: "", |
| | | entryDate: "", |
| | | maintenanceTime: "", |
| | | productData: [], |
| | | executionDate: "", |
| | | paymentMethod: "", |
| | | }, |
| | | rules: { |
| | | salesman: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | customerContractNo: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | customerId: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | projectName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | entryPerson: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | entryDate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | executionDate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | |
| | | const printPreviewVisible = ref(false); |
| | | const printData = ref([]); |
| | | |
| | | // æ¥ä»·å导å
¥ç¸å
³ |
| | | const quotationDialogVisible = ref(false); |
| | | const quotationLoading = ref(false); |
| | | const quotationList = ref([]); |
| | | const quotationSearchForm = reactive({ |
| | | quotationNo: "", |
| | | customer: "", |
| | | }); |
| | | const selectedQuotation = ref(null); |
| | | |
| | | // åè´§ç¸å
³ |
| | | const deliveryFormVisible = ref(false); |
| | | const currentDeliveryRow = ref(null); |
| | |
| | | shippingCarNumber: [ |
| | | { required: true, message: "请è¾å
¥å货车çå·", trigger: "blur" } |
| | | ], |
| | | approverId:[ |
| | | { |
| | | required: true,message: "", |
| | | } |
| | | ] |
| | | }, |
| | | }); |
| | | const { deliveryForm, deliveryRules } = toRefs(deliveryFormData); |
| | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | // åªæå¨ç¹å»æç´¢æé®æ¶æé置页ç å°ç¬¬ä¸é¡µ |
| | | // é¿å
表ååæ®µchangeäºä»¶å¹²æ°å页 |
| | | if (arguments.length === 0) { |
| | | page.current = 1; |
| | | } |
| | | page.current = 1; |
| | | expandedRowKeys.value = []; |
| | | getList(); |
| | | }; |
| | |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | const getList =async () => { |
| | | let userLists = await userListNoPage(); |
| | | userList.value = userLists.data; |
| | | tableLoading.value = true; |
| | | const { entryDate, ...rest } = searchForm; |
| | | // å°èå´æ¥æåæ®µä¼ éç»å端 |
| | | const params = { ...rest, ...page }; |
| | | // ç§»é¤å½å
¥æ¥æçé»è®¤å¼è®¾ç½®ï¼åªä¿çèå´æ¥æå段 |
| | | delete params.entryDate; |
| | | ledgerListPage(params) |
| | | ledgerListPage({ ...rest, ...page }) |
| | | .then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.records; |
| | |
| | | }; |
| | | // è·å产å大类treeæ°æ® |
| | | const getProductOptions = () => { |
| | | // è¿å Promiseï¼ä¾¿äºå¨ç¼è¾äº§åæ¶çå¾
å è½½å®æ |
| | | return productTreeList().then((res) => { |
| | | // å
¼å®¹æ¥å£è¿å { data: [] } æç´æ¥è¿åæ°ç» |
| | | const list = Array.isArray(res) ? res : (res?.data ?? []); |
| | | productOptions.value = convertIdToValue(list); |
| | | return productOptions.value; |
| | | productTreeList().then((res) => { |
| | | productOptions.value = convertIdToValue(res); |
| | | }); |
| | | }; |
| | | const formattedNumber = (row, column, cellValue) => { |
| | |
| | | return newItem; |
| | | }); |
| | | } |
| | | // æ ¹æ®åç§°åæ¥äº§å大类 idï¼ä¾¿äºä»
ååç§°æ¶çåæ¾ |
| | | function findNodeIdByLabel(nodes, label) { |
| | | if (!label) return null; |
| | | for (let i = 0; i < nodes.length; i++) { |
| | | const node = nodes[i]; |
| | | if (node.label === label) return node.value; |
| | | if (node.children && node.children.length > 0) { |
| | | const found = findNodeIdByLabel(node.children, label); |
| | | if (found !== null && found !== undefined) return found; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | // è¿æ»¤æåæ°æ® |
| | |
| | | productSelectedRows.value = selectedRows; |
| | | }; |
| | | const expandedRowKeys = ref([]); |
| | | // å±å¼è¡ |
| | | const expandChange = (row, expandedRows) => { |
| | | if (expandedRows.length > 0) { |
| | | // å±å¼è¡ï¼å§ç»åªå±å¼ä¸è¡ï¼ |
| | | const expandChange = (row) => { |
| | | const rowKey = row.id; |
| | | const isExpanded = expandedRowKeys.value.includes(rowKey); |
| | | |
| | | if (isExpanded) { |
| | | // å½åè¡å·²å±å¼ -> æ¶èµ· |
| | | expandedRowKeys.value = []; |
| | | try { |
| | | productList({ salesLedgerId: row.id, type: 1 }).then((res) => { |
| | | const index = tableData.value.findIndex((item) => item.id === row.id); |
| | | if (index > -1) { |
| | | tableData.value[index].children = res.data; |
| | | } |
| | | expandedRowKeys.value.push(row.id); |
| | | }); |
| | | } catch (error) { |
| | | console.log(error); |
| | | } |
| | | } else { |
| | | expandedRowKeys.value = []; |
| | | return; |
| | | } |
| | | |
| | | // å±å¼å½åè¡åï¼å
æ¶èµ·å
¶å®è¡ |
| | | expandedRowKeys.value = []; |
| | | |
| | | try { |
| | | productList({ salesLedgerId: row.id, type: 1 }).then((res) => { |
| | | const index = tableData.value.findIndex((item) => item.id === row.id); |
| | | if (index > -1) { |
| | | tableData.value[index].children = res.data; |
| | | } |
| | | // åªä¿çå½åè¿ä¸è¡å¤äºå±å¼ç¶æ |
| | | expandedRowKeys.value = [rowKey]; |
| | | }); |
| | | } catch (error) { |
| | | console.log(error); |
| | | } |
| | | }; |
| | | // 主表åè®¡æ¹æ³ |
| | |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | productData.value = []; |
| | | selectedQuotation.value = null; |
| | | let userLists = await userListNoPage(); |
| | | userList.value = userLists.data; |
| | | customerList().then((res) => { |
| | | customerOption.value = res; |
| | | }); |
| | | form.value.entryPerson = userStore.id; |
| | | if (type === "add") { |
| | | // æ°å¢æ¶è®¾ç½®å½å
¥æ¥æä¸ºå½å¤© |
| | | form.value.entryDate = getCurrentDate(); |
| | | // ç¾è®¢æ¥æé»è®¤ä¸ºå½å¤© |
| | | form.value.executionDate = getCurrentDate(); |
| | | } else { |
| | | if (type !== "add") { |
| | | currentId.value = row.id; |
| | | getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => { |
| | | form.value = { ...res }; |
| | |
| | | // }); |
| | | form.value.entryDate = getCurrentDate(); // 设置é»è®¤å½å
¥æ¥æä¸ºå½åæ¥æ |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | |
| | | // æå¼æ¥ä»·å鿩弹çªï¼ä»
审æ¹éè¿ï¼ |
| | | const openQuotationDialog = async () => { |
| | | if (operationType.value === "view") return; |
| | | quotationDialogVisible.value = true; |
| | | // å
ç¡®ä¿å®¢æ·å表已å è½½ï¼ä¾¿äºåç»åå¡« customerId |
| | | if (!customerOption.value || customerOption.value.length === 0) { |
| | | try { |
| | | const res = await customerList(); |
| | | customerOption.value = res; |
| | | } catch (e) { |
| | | // ignoreï¼å
è®¸ç¨æ·åç»æå¨éæ©å®¢æ· |
| | | } |
| | | } |
| | | await fetchQuotationList(); |
| | | }; |
| | | |
| | | const fetchQuotationList = async () => { |
| | | quotationLoading.value = true; |
| | | try { |
| | | const params = { |
| | | // å
¼å®¹å端å页忮µï¼è¿éæ²¿ç¨æ¥ä»·é¡µé¢å·²æå¯ç¨çåæ®µå½å |
| | | currentPage: 1, |
| | | pageSize: 100, |
| | | ...quotationSearchForm, |
| | | status: "éè¿", |
| | | }; |
| | | const res = await getQuotationList(params); |
| | | quotationList.value = res?.data?.records || []; |
| | | } finally { |
| | | quotationLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const resetQuotationSearch = async () => { |
| | | quotationSearchForm.quotationNo = ""; |
| | | quotationSearchForm.customer = ""; |
| | | await fetchQuotationList(); |
| | | }; |
| | | |
| | | // é䏿¥ä»·åååå¡«å°å°è´¦è¡¨å |
| | | const applyQuotation = (row) => { |
| | | if (!row) return; |
| | | selectedQuotation.value = row; |
| | | |
| | | // ä¸å¡å |
| | | form.value.salesman = row.salesperson || ""; |
| | | |
| | | // 客æ·åç§° -> customerId |
| | | const customer = (customerOption.value || []).find((c) => c.customerName === row.customer); |
| | | if (customer?.id) { |
| | | form.value.customerId = customer.id; |
| | | } else { |
| | | // 妿æ¾ä¸å°ï¼ä¿çåå¼ï¼å
è®¸ç¨æ·æå¨éæ©/䏿æå·²æè¾å
¥ï¼ |
| | | form.value.customerId = form.value.customerId || ""; |
| | | } |
| | | |
| | | // 产åä¿¡æ¯æ å°ï¼æ¥ä»· products -> å°è´¦ productData |
| | | const products = Array.isArray(row.products) ? row.products : []; |
| | | productData.value = products.map((p) => { |
| | | const quantity = Number(p.quantity ?? 0) || 0; |
| | | const unitPrice = Number(p.unitPrice ?? 0) || 0; |
| | | const taxRate = "13"; // é»è®¤ 13%ï¼ä¾¿äºç´æ¥æäº¤ï¼å¦éå¯å¨äº§åä¸èªè¡ä¿®æ¹ï¼ |
| | | const taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); |
| | | const taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(taxInclusiveTotalPrice, taxRate); |
| | | return { |
| | | // å°è´¦å段 |
| | | productCategory: p.product || p.productName || "", |
| | | specificationModel: p.specification || "", |
| | | unit: p.unit || "", |
| | | quantity: quantity, |
| | | taxRate: taxRate, |
| | | taxInclusiveUnitPrice: unitPrice.toFixed(2), |
| | | taxInclusiveTotalPrice: taxInclusiveTotalPrice, |
| | | taxExclusiveTotalPrice: taxExclusiveTotalPrice, |
| | | invoiceType: "墿®ç¥¨", |
| | | }; |
| | | }); |
| | | |
| | | quotationDialogVisible.value = false; |
| | | }; |
| | | function changs(val) { |
| | | console.log(val); |
| | |
| | | |
| | | const productIndex = ref(0); |
| | | // æå¼äº§åå¼¹æ¡ |
| | | const openProductForm = async (type, row, index) => { |
| | | const openProductForm =async (type, row,index) => { |
| | | productOperationType.value = type; |
| | | productForm.value = {}; |
| | | proxy.resetForm("productFormRef"); |
| | |
| | | if (type === "edit") { |
| | | productForm.value = { ...row }; |
| | | productIndex.value = index; |
| | | // ç¼è¾æ¶æ ¹æ®äº§å大类åç§°åæ¥ tree èç¹ idï¼å¹¶å è½½è§æ ¼åå·å表 |
| | | try { |
| | | const options = productOptions.value && productOptions.value.length > 0 |
| | | ? productOptions.value |
| | | : await getProductOptions(); |
| | | const categoryId = findNodeIdByLabel(options, productForm.value.productCategory); |
| | | if (categoryId) { |
| | | const models = await modelList({ id: categoryId }); |
| | | modelOptions.value = models || []; |
| | | // æ ¹æ®å½åè§æ ¼åå·åç§°åæ¥å¹¶è®¾ç½® productModelIdï¼ä¾¿äºä¸ææ¡æ¾ç¤ºå·²éå¼ |
| | | const currentModel = (modelOptions.value || []).find( |
| | | (m) => m.model === productForm.value.specificationModel |
| | | ); |
| | | if (currentModel) { |
| | | productForm.value.productModelId = currentModel.id; |
| | | } |
| | | } |
| | | } catch (e) { |
| | | // å 载失败æ¶ä¿æå¯ç¼è¾ï¼ä¸ä¸æå¼¹çª |
| | | console.error("å 载产åè§æ ¼åå·å¤±è´¥", e); |
| | | } |
| | | } |
| | | productFormVisible.value = true; |
| | | getProductOptions(); |
| | | }; |
| | | // æäº¤äº§å表å |
| | | const submitProduct = () => { |
| | |
| | | const seconds = String(date.getSeconds()).padStart(2, "0"); |
| | | return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`; |
| | | }; |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | |
| | | // 计ç®äº§åæ»æ°é |
| | | const getTotalQuantity = (products) => { |
| | | if (!products || products.length === 0) return '0'; |
| | |
| | | * @param row ä¸è½½æä»¶çç¸å
³ä¿¡æ¯å¯¹è±¡ |
| | | */ |
| | | const fileListRef = ref(null) |
| | | const fileListDialogVisible = ref(false) |
| | | const downLoadFile = (row) => { |
| | | getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => { |
| | | if (fileListRef.value) { |
| | | fileListRef.value.open(res.salesLedgerFiles) |
| | | fileListDialogVisible.value = true |
| | | } |
| | | fileListRef.value.open(res.salesLedgerFiles) |
| | | }); |
| | | } |
| | | |
| | | // æå¼åè´§å¼¹æ¡ |
| | | const openDeliveryForm = (row) => { |
| | | getProductInventory({ salesLedgerId: row.id, type:1 }).then((res) => { |
| | | currentDeliveryRow.value = row; |
| | | deliveryForm.value = { |
| | | shippingDate: getCurrentDate(), |
| | | shippingCarNumber: "", |
| | | }; |
| | | deliveryFormVisible.value = true; |
| | | }).catch(err => { |
| | | ElMessage.error(err.msg); |
| | | }); |
| | | currentDeliveryRow.value = row; |
| | | deliveryForm.value = { |
| | | shippingDate: "", // ç§»é¤é»è®¤å¼è®¾ç½® |
| | | shippingCarNumber: "", |
| | | }; |
| | | deliveryFormVisible.value = true; |
| | | }; |
| | | |
| | | // æäº¤å货表å |
| | |
| | | proxy.$refs["deliveryFormRef"].validate((valid) => { |
| | | if (valid) { |
| | | addShippingInfo({ |
| | | salesLedgerId: currentDeliveryRow.value.id, |
| | | approverId:deliveryForm.value.approverId, |
| | | salesLedgerId: currentDeliveryRow.value.salesLedgerId, |
| | | salesLedgerProductId: currentDeliveryRow.value.id, |
| | | shippingDate: deliveryForm.value.shippingDate, |
| | | shippingCarNumber: deliveryForm.value.shippingCarNumber, |
| | | }) |
| | |
| | | proxy.$modal.msgSuccess("åè´§æå"); |
| | | closeDeliveryDia(); |
| | | getList(); |
| | | expandedRowKeys.value = []; |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("å货失败ï¼è¯·éè¯"); |