@robot-admin/naive-ui-components 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +294 -279
- package/dist/C_ActionBar-DYG0Yf3A.css.map +1 -0
- package/dist/C_ActionBar-MAjRhqcI.css.map +1 -0
- package/dist/C_ActionBar.cjs +1 -1
- package/dist/C_ActionBar.css +47 -47
- package/dist/C_ActionBar.js +1 -1
- package/dist/C_ActionBar.js.map +1 -1
- package/dist/C_ActionBar2.js +1 -1
- package/dist/C_ActionBar2.js.map +1 -1
- package/dist/{C_AntV-A3NXx_sF.css.map → C_AntV-BY8jqqmi.css.map} +1 -1
- package/dist/{C_AntV-D2Zp2qQF.css.map → C_AntV-BbkHc-_a.css.map} +1 -1
- package/dist/C_AntV.cjs +1 -1
- package/dist/C_AntV.css +78 -78
- package/dist/C_AntV.js +1 -1
- package/dist/C_AntV.js.map +1 -1
- package/dist/C_AntV2.js +3 -3
- package/dist/C_AntV2.js.map +1 -1
- package/dist/{C_AudioPlayer-CXl4yP_m.css.map → C_AudioPlayer-DKRIGhi7.css.map} +1 -1
- package/dist/{C_AudioPlayer-CcBtt71m.css.map → C_AudioPlayer-DlB6eNsa.css.map} +1 -1
- package/dist/C_AudioPlayer.cjs +1 -1
- package/dist/C_AudioPlayer.css +47 -47
- package/dist/C_AudioPlayer.js +1 -1
- package/dist/C_AudioPlayer.js.map +1 -1
- package/dist/C_AudioPlayer2.js +1 -1
- package/dist/C_AudioPlayer2.js.map +1 -1
- package/dist/{C_AvatarGroup-CtPhfH9h.css.map → C_AvatarGroup-D02zci-i.css.map} +1 -1
- package/dist/{C_AvatarGroup-M1dNPH3E.css.map → C_AvatarGroup-DatHaUlY.css.map} +1 -1
- package/dist/C_AvatarGroup.css +21 -21
- package/dist/C_AvatarGroup.js.map +1 -1
- package/dist/C_AvatarGroup2.js +1 -1
- package/dist/C_AvatarGroup2.js.map +1 -1
- package/dist/{C_Barcode-DjTmDkbQ.css.map → C_Barcode-DYDRDe2O.css.map} +1 -1
- package/dist/{C_Barcode-Do1Ozsmh.css.map → C_Barcode-muJdc_O4.css.map} +1 -1
- package/dist/C_Barcode.css +7 -7
- package/dist/C_Barcode.js.map +1 -1
- package/dist/C_Barcode2.js +1 -1
- package/dist/C_Barcode2.js.map +1 -1
- package/dist/C_Breadcrumb.cjs +1 -1
- package/dist/C_Breadcrumb.js +1 -1
- package/dist/C_Breadcrumb.js.map +1 -1
- package/dist/C_Breadcrumb2.js +1 -1
- package/dist/C_Breadcrumb2.js.map +1 -1
- package/dist/{C_Captcha-CZmAETly.css.map → C_Captcha-9_hk6VmY.css.map} +1 -1
- package/dist/{C_Captcha-Ccq3DMrR.css.map → C_Captcha-MtASlJ0f.css.map} +1 -1
- package/dist/C_Captcha.css +19 -19
- package/dist/C_Captcha.js.map +1 -1
- package/dist/C_Captcha2.js +1 -1
- package/dist/C_Captcha2.js.map +1 -1
- package/dist/C_Cascade.js.map +1 -1
- package/dist/C_Cascade2.js +1 -1
- package/dist/C_Cascade2.js.map +1 -1
- package/dist/{C_Chat-CJ8KESTM.css.map → C_Chat-Csjz_BFw.css.map} +1 -1
- package/dist/{C_Chat-DzV4AFLd.css.map → C_Chat-DO1ZBA_0.css.map} +1 -1
- package/dist/C_Chat.cjs +1 -1
- package/dist/C_Chat.css +65 -65
- package/dist/C_Chat.js +1 -1
- package/dist/C_Chat.js.map +1 -1
- package/dist/C_Chat2.js +1 -1
- package/dist/C_Chat2.js.map +1 -1
- package/dist/{C_City-Cv5BESaN.css.map → C_City-Bam08Qv3.css.map} +1 -1
- package/dist/{C_City-DNKv4MpH.css.map → C_City-Bb3W-KaN.css.map} +1 -1
- package/dist/C_City.css +29 -29
- package/dist/C_City.js.map +1 -1
- package/dist/C_City2.js +1 -1
- package/dist/C_City2.js.map +1 -1
- package/dist/C_Code-BFi5xxnM.css.map +1 -0
- package/dist/C_Code-CZ7yfnri.css.map +1 -0
- package/dist/C_Code.cjs +1 -1
- package/dist/C_Code.css +3 -3
- package/dist/C_Code.js +1 -1
- package/dist/C_Code.js.map +1 -1
- package/dist/C_Code2.js +1 -1
- package/dist/C_Code2.js.map +1 -1
- package/dist/{C_CollapsePanel-CedsEM0N.css.map → C_CollapsePanel-CWkFCqNQ.css.map} +1 -1
- package/dist/{C_CollapsePanel-BkOivqn3.css.map → C_CollapsePanel-pcVJA_4z.css.map} +1 -1
- package/dist/C_CollapsePanel.cjs +1 -1
- package/dist/C_CollapsePanel.css +35 -35
- package/dist/C_CollapsePanel.js +1 -1
- package/dist/C_CollapsePanel.js.map +1 -1
- package/dist/C_CollapsePanel2.js +1 -1
- package/dist/C_CollapsePanel2.js.map +1 -1
- package/dist/{C_ContextMenu-CCsCeI39.css.map → C_ContextMenu-B3Cgz_wJ.css.map} +1 -1
- package/dist/{C_ContextMenu-DOTBeltf.css.map → C_ContextMenu-u1LixF3_.css.map} +1 -1
- package/dist/C_ContextMenu.cjs +1 -1
- package/dist/C_ContextMenu.css +17 -17
- package/dist/C_ContextMenu.js +1 -1
- package/dist/C_ContextMenu.js.map +1 -1
- package/dist/C_ContextMenu2.js +1 -1
- package/dist/C_ContextMenu2.js.map +1 -1
- package/dist/{C_Cron-C0-8b5af.css.map → C_Cron-Civir5-I.css.map} +1 -1
- package/dist/{C_Cron-DqHQ92LN.css.map → C_Cron-iw3qpMsy.css.map} +1 -1
- package/dist/C_Cron.cjs +1 -1
- package/dist/C_Cron.css +37 -37
- package/dist/C_Cron.js +1 -1
- package/dist/C_Cron.js.map +1 -1
- package/dist/C_Cron2.js +1 -1
- package/dist/C_Cron2.js.map +1 -1
- package/dist/C_Date.js.map +1 -1
- package/dist/C_Date2.js +1 -1
- package/dist/C_Date2.js.map +1 -1
- package/dist/{C_Draggable-Bq6o0qXn.css.map → C_Draggable-BCjIvIwT.css.map} +1 -1
- package/dist/{C_Draggable-r6nhx3yM.css.map → C_Draggable-DwkSlCOS.css.map} +1 -1
- package/dist/C_Draggable.css +46 -46
- package/dist/C_Draggable.js.map +1 -1
- package/dist/C_Draggable2.js +1 -1
- package/dist/C_Draggable2.js.map +1 -1
- package/dist/C_Editor-BfjjYQ9B.css.map +1 -0
- package/dist/C_Editor-Do2StvoJ.css.map +1 -0
- package/dist/C_Editor.css +55 -55
- package/dist/C_Editor.js.map +1 -1
- package/dist/C_Editor2.js +1 -1
- package/dist/C_Editor2.js.map +1 -1
- package/dist/{C_FilePreview-BVarVvnD.css.map → C_FilePreview-BhcbiXsV.css.map} +1 -1
- package/dist/{C_FilePreview-DHGlV4OR.css.map → C_FilePreview-DJudcIbW.css.map} +1 -1
- package/dist/C_FilePreview.cjs +1 -1
- package/dist/C_FilePreview.css +91 -91
- package/dist/C_FilePreview.js +1 -1
- package/dist/C_FilePreview.js.map +1 -1
- package/dist/C_FilePreview2.js +1 -1
- package/dist/C_FilePreview2.js.map +1 -1
- package/dist/{C_Form-BciQUPpS.css.map → C_Form-BtcAPIRi.css.map} +1 -1
- package/dist/{C_Form-CKHvXL3O.css.map → C_Form-D_gwQ7hC.css.map} +1 -1
- package/dist/C_Form.cjs +1 -1
- package/dist/C_Form.css +222 -222
- package/dist/C_Form.js +1 -1
- package/dist/C_Form.js.map +1 -1
- package/dist/C_Form2.js +1 -1
- package/dist/C_Form2.js.map +1 -1
- package/dist/{C_FormSearch-Bmd2CmG6.css.map → C_FormSearch-Bi4XYjjk.css.map} +1 -1
- package/dist/{C_FormSearch-DBNtnjaL.css.map → C_FormSearch-DUGOoX0u.css.map} +1 -1
- package/dist/C_FormSearch.css +45 -45
- package/dist/C_FormSearch.js.map +1 -1
- package/dist/C_FormSearch2.js +1 -1
- package/dist/C_FormSearch2.js.map +1 -1
- package/dist/{C_FormulaEditor-3WG2vtQl.css.map → C_FormulaEditor-CJk3SSUJ.css.map} +1 -1
- package/dist/{C_FormulaEditor-Cm0CokN5.css.map → C_FormulaEditor-Cy7mjfVO.css.map} +1 -1
- package/dist/C_FormulaEditor.cjs +1 -1
- package/dist/C_FormulaEditor.css +78 -78
- package/dist/C_FormulaEditor.js +1 -1
- package/dist/C_FormulaEditor.js.map +1 -1
- package/dist/C_FormulaEditor2.js +1 -1
- package/dist/C_FormulaEditor2.js.map +1 -1
- package/dist/C_FullCalendar-BQA0OjGB.css.map +1 -0
- package/dist/C_FullCalendar-ChJUosAi.css.map +1 -0
- package/dist/C_FullCalendar.css +3 -3
- package/dist/C_FullCalendar.js.map +1 -1
- package/dist/C_FullCalendar2.js +1 -1
- package/dist/C_FullCalendar2.js.map +1 -1
- package/dist/C_GlobalSearch.js.map +1 -1
- package/dist/C_GlobalSearch2.js.map +1 -1
- package/dist/C_Guide.cjs +1 -1
- package/dist/C_Guide.js +1 -1
- package/dist/C_Guide.js.map +1 -1
- package/dist/C_Guide2.js +1 -1
- package/dist/C_Guide2.js.map +1 -1
- package/dist/C_Icon.js.map +1 -1
- package/dist/C_Icon2.js +1 -1
- package/dist/C_Icon2.js.map +1 -1
- package/dist/{C_ImageCropper-D3L2-J_J.css.map → C_ImageCropper-BqZpkZfU.css.map} +1 -1
- package/dist/{C_ImageCropper-DrmUlaLi.css.map → C_ImageCropper-CylwGuzS.css.map} +1 -1
- package/dist/C_ImageCropper.cjs +1 -1
- package/dist/C_ImageCropper.css +10 -10
- package/dist/C_ImageCropper.js +1 -1
- package/dist/C_ImageCropper.js.map +1 -1
- package/dist/C_ImageCropper2.js +1 -1
- package/dist/C_ImageCropper2.js.map +1 -1
- package/dist/C_Language.cjs +1 -1
- package/dist/C_Language.js +1 -1
- package/dist/C_Language.js.map +1 -1
- package/dist/C_Language2.js +1 -1
- package/dist/C_Language2.js.map +1 -1
- package/dist/{C_Login-Cst_W1XC.css.map → C_Login-BkdnkBKX.css.map} +1 -1
- package/dist/{C_Login-DWZ_6K1x.css.map → C_Login-VkMM6OJ2.css.map} +1 -1
- package/dist/C_Login.cjs +1 -1
- package/dist/C_Login.css +72 -72
- package/dist/C_Login.js +1 -1
- package/dist/C_Login.js.map +1 -1
- package/dist/C_Login2.js +1 -1
- package/dist/C_Login2.js.map +1 -1
- package/dist/{C_Map-BCJmDnJT.css.map → C_Map-DNnBcY70.css.map} +1 -1
- package/dist/{C_Map-WUMXSAfy.css.map → C_Map-LEXIx6zM.css.map} +1 -1
- package/dist/C_Map.css +4 -4
- package/dist/C_Map.js.map +1 -1
- package/dist/C_Map2.js +1 -1
- package/dist/C_Map2.js.map +1 -1
- package/dist/{C_Markdown-7J0uPEuk.css.map → C_Markdown-DwmI0_0Q.css.map} +1 -1
- package/dist/{C_Markdown-C7Lg0_9z.css.map → C_Markdown-k0794RW0.css.map} +1 -1
- package/dist/C_Markdown.css +33 -33
- package/dist/C_Markdown.js.map +1 -1
- package/dist/C_Markdown2.js +1 -1
- package/dist/C_Markdown2.js.map +1 -1
- package/dist/C_Menu.js.map +1 -1
- package/dist/C_Menu2.js +1 -1
- package/dist/C_Menu2.js.map +1 -1
- package/dist/C_NotificationCenter.cjs +1 -1
- package/dist/C_NotificationCenter.js +1 -1
- package/dist/C_NotificationCenter.js.map +1 -1
- package/dist/C_NotificationCenter2.js +1 -1
- package/dist/C_NotificationCenter2.js.map +1 -1
- package/dist/C_OrgChart.js.map +1 -1
- package/dist/C_OrgChart2.js +1 -1
- package/dist/C_OrgChart2.js.map +1 -1
- package/dist/C_Progress.js.map +1 -1
- package/dist/C_Progress2.js +1 -1
- package/dist/C_Progress2.js.map +1 -1
- package/dist/{C_QRCode-DMxSyogU.css.map → C_QRCode-CFNTda_1.css.map} +1 -1
- package/dist/{C_QRCode-G7fiAkm4.css.map → C_QRCode-CmWr9lK-.css.map} +1 -1
- package/dist/C_QRCode.css +9 -9
- package/dist/C_QRCode.js.map +1 -1
- package/dist/C_QRCode2.js +1 -1
- package/dist/C_QRCode2.js.map +1 -1
- package/dist/{C_Signature-BJMvVPWT.css.map → C_Signature-BDx4ctsE.css.map} +1 -1
- package/dist/{C_Signature-BJUHx2BF.css.map → C_Signature-Bz_uNbwv.css.map} +1 -1
- package/dist/C_Signature.cjs +1 -1
- package/dist/C_Signature.css +15 -15
- package/dist/C_Signature.js +1 -1
- package/dist/C_Signature.js.map +1 -1
- package/dist/C_Signature2.js +1 -1
- package/dist/C_Signature2.js.map +1 -1
- package/dist/C_Skeleton.js.map +1 -1
- package/dist/C_Skeleton2.js +1 -1
- package/dist/C_Skeleton2.js.map +1 -1
- package/dist/{C_SplitPane-Br2eK8IG.css.map → C_SplitPane-BOwr1C7K.css.map} +1 -1
- package/dist/{C_SplitPane-DuyzUhKB.css.map → C_SplitPane-N-a_D-7F.css.map} +1 -1
- package/dist/C_SplitPane.cjs +1 -1
- package/dist/C_SplitPane.css +31 -31
- package/dist/C_SplitPane.js +1 -1
- package/dist/C_SplitPane.js.map +1 -1
- package/dist/C_SplitPane2.js +1 -1
- package/dist/C_SplitPane2.js.map +1 -1
- package/dist/C_Steps-Bk1krgiR.css.map +1 -0
- package/dist/C_Steps-Dn2CMpy1.css.map +1 -0
- package/dist/C_Steps.css +38 -38
- package/dist/C_Steps.js.map +1 -1
- package/dist/C_Steps2.js +1 -1
- package/dist/C_Steps2.js.map +1 -1
- package/dist/C_Table.cjs +1 -1
- package/dist/C_Table.js +1 -1
- package/dist/C_Table.js.map +1 -1
- package/dist/C_Table2.js +2 -2
- package/dist/C_Table2.js.map +1 -1
- package/dist/{C_TagsView-BsutyC3U.css.map → C_TagsView-DX3LecK1.css.map} +1 -1
- package/dist/{C_TagsView-Crm7yWg9.css.map → C_TagsView-DqOTa8bL.css.map} +1 -1
- package/dist/C_TagsView.cjs +1 -1
- package/dist/C_TagsView.css +36 -36
- package/dist/C_TagsView.js +1 -1
- package/dist/C_TagsView.js.map +1 -1
- package/dist/C_TagsView2.js +1 -1
- package/dist/C_TagsView2.js.map +1 -1
- package/dist/C_Theme.cjs +1 -1
- package/dist/C_Theme.js +1 -1
- package/dist/C_Theme.js.map +1 -1
- package/dist/C_Theme2.js +1 -1
- package/dist/C_Theme2.js.map +1 -1
- package/dist/C_Time-BzyQVvTS.css.map +1 -0
- package/dist/C_Time-DmpKLQHc.css.map +1 -0
- package/dist/C_Time.css +5 -5
- package/dist/C_Time.js.map +1 -1
- package/dist/C_Time2.js +1 -1
- package/dist/C_Time2.js.map +1 -1
- package/dist/{C_Timeline-DG70WtJP.css.map → C_Timeline-BKkimrZx.css.map} +1 -1
- package/dist/{C_Timeline-Dzxmmdjg.css.map → C_Timeline-DTuSCX6p.css.map} +1 -1
- package/dist/C_Timeline.cjs +1 -1
- package/dist/C_Timeline.css +45 -45
- package/dist/C_Timeline.js +1 -1
- package/dist/C_Timeline.js.map +1 -1
- package/dist/C_Timeline2.js +1 -1
- package/dist/C_Timeline2.js.map +1 -1
- package/dist/{C_Transfer-CCEqnC-v.css.map → C_Transfer-BOB6OBqS.css.map} +1 -1
- package/dist/{C_Transfer-CStPm4NP.css.map → C_Transfer-Dpq7ezWC.css.map} +1 -1
- package/dist/C_Transfer.cjs +1 -1
- package/dist/C_Transfer.css +31 -31
- package/dist/C_Transfer.js +1 -1
- package/dist/C_Transfer.js.map +1 -1
- package/dist/C_Transfer2.js +1 -1
- package/dist/C_Transfer2.js.map +1 -1
- package/dist/{C_Tree-B-Le4hjQ.css.map → C_Tree-D98nX9qT.css.map} +1 -1
- package/dist/{C_Tree-DnGc_MPb.css.map → C_Tree-ulfm7b-P.css.map} +1 -1
- package/dist/C_Tree.cjs +1 -1
- package/dist/C_Tree.css +33 -33
- package/dist/C_Tree.js +1 -1
- package/dist/C_Tree.js.map +1 -1
- package/dist/C_Tree2.js +1 -1
- package/dist/C_Tree2.js.map +1 -1
- package/dist/{C_Upload-CFAxVGVz.css.map → C_Upload-BR9fg5r4.css.map} +1 -1
- package/dist/{C_Upload-D8_QeSV0.css.map → C_Upload-CPqf74Ea.css.map} +1 -1
- package/dist/C_Upload.cjs +1 -1
- package/dist/C_Upload.css +4 -4
- package/dist/C_Upload.js +1 -1
- package/dist/C_Upload.js.map +1 -1
- package/dist/C_Upload2.js +2 -2
- package/dist/C_Upload2.js.map +1 -1
- package/dist/{C_VideoPlayer-Cdgv4Zq0.css.map → C_VideoPlayer-4J96tKfK.css.map} +1 -1
- package/dist/{C_VideoPlayer-rm0MODUv.css.map → C_VideoPlayer-D35seHkm.css.map} +1 -1
- package/dist/C_VideoPlayer.css +13 -13
- package/dist/C_VideoPlayer.js.map +1 -1
- package/dist/C_VideoPlayer2.js +3 -3
- package/dist/C_VideoPlayer2.js.map +1 -1
- package/dist/{C_VtableGantt-BpY-Rng3.css.map → C_VtableGantt-C2lxFmWg.css.map} +1 -1
- package/dist/{C_VtableGantt-DB87-jdS.css.map → C_VtableGantt-Dwnkw_WL.css.map} +1 -1
- package/dist/C_VtableGantt.cjs +1 -1
- package/dist/C_VtableGantt.css +15 -15
- package/dist/C_VtableGantt.js +1 -1
- package/dist/C_VtableGantt.js.map +1 -1
- package/dist/C_VtableGantt2.js +1 -1
- package/dist/C_VtableGantt2.js.map +1 -1
- package/dist/C_WaterFall.js.map +1 -1
- package/dist/C_WaterFall2.js +1 -1
- package/dist/C_WaterFall2.js.map +1 -1
- package/dist/{C_WorkFlow-7F6op6qN.css.map → C_WorkFlow-2hJfvvTK.css.map} +1 -1
- package/dist/{C_WorkFlow-Cy3HWA6A.css.map → C_WorkFlow-DHoNjl8-.css.map} +1 -1
- package/dist/C_WorkFlow.cjs +1 -1
- package/dist/C_WorkFlow.css +108 -108
- package/dist/C_WorkFlow.js +1 -1
- package/dist/C_WorkFlow.js.map +1 -1
- package/dist/C_WorkFlow2.js +1 -1
- package/dist/C_WorkFlow2.js.map +1 -1
- package/dist/constants.d.ts +3 -3
- package/dist/constants2.d.ts +4 -4
- package/dist/constants3.d.ts +3 -3
- package/dist/constants4.d.ts +4 -4
- package/dist/constants5.d.ts +2 -2
- package/dist/data.d.ts +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.vue.d.ts +1 -1
- package/dist/index10.vue.d.ts +1 -1
- package/dist/index11.vue.d.ts +4 -4
- package/dist/index12.vue.d.ts +1 -1
- package/dist/index13.vue.d.ts +2 -2
- package/dist/index14.vue.d.ts +3 -3
- package/dist/index15.vue.d.ts +3 -3
- package/dist/index16.vue.d.ts +2 -2
- package/dist/index17.vue.d.ts +1 -1
- package/dist/index18.vue.d.ts +5 -5
- package/dist/index2.vue.d.ts +1 -1
- package/dist/index20.vue.d.ts +1 -1
- package/dist/index22.vue.d.ts +1 -1
- package/dist/index23.vue.d.ts +2 -2
- package/dist/index24.vue.d.ts +1 -1
- package/dist/index26.vue.d.ts +3 -3
- package/dist/index27.vue.d.ts +2 -2
- package/dist/index28.vue.d.ts +3 -3
- package/dist/index3.vue.d.ts +3 -3
- package/dist/index4.vue.d.ts +2 -2
- package/dist/index6.vue.d.ts +6 -6
- package/dist/index7.vue.d.ts +2 -2
- package/dist/index8.vue.d.ts +1 -1
- package/dist/index9.vue.d.ts +2 -2
- package/dist/menuAdapter.js.map +1 -1
- package/dist/resolver.cjs.map +1 -1
- package/dist/resolver.js.map +1 -1
- package/dist/style.css +1483 -1483
- package/dist/themes/glass-morphism.css +1 -0
- package/dist/useCalendarEvents.d.ts +1 -1
- package/dist/useCollapsePanel.d.ts +1 -1
- package/dist/useCropperCore.d.ts +2 -2
- package/dist/useDraggableLayout.d.ts +4 -4
- package/dist/useDynamicFormState.d.ts +21 -21
- package/dist/useEdgeInteraction.d.ts +2 -2
- package/dist/useModalEdit.d.ts +1 -1
- package/dist/useQRCode.d.ts +3 -3
- package/dist/useSearchState.d.ts +2 -2
- package/dist/useSignatureHistory.d.ts +4 -4
- package/dist/useSplitResize.d.ts +2 -2
- package/dist/useTimeSelection.d.ts +2 -2
- package/dist/useTreeOperations.d.ts +3 -3
- package/dist/useWorkflowValidation.d.ts +6 -6
- package/package.json +11 -8
- package/dist/C_ActionBar-jZPsiXtT.css.map +0 -1
- package/dist/C_ActionBar-nnfbZCea.css.map +0 -1
- package/dist/C_Code-DPZlNSxL.css.map +0 -1
- package/dist/C_Code-avZjAnHD.css.map +0 -1
- package/dist/C_Editor-C49qURgb.css.map +0 -1
- package/dist/C_Editor-DuxBD9Qg.css.map +0 -1
- package/dist/C_FullCalendar-1U4VlG7X.css.map +0 -1
- package/dist/C_FullCalendar-DLUdCtqf.css.map +0 -1
- package/dist/C_Steps-BHYNJI1l.css.map +0 -1
- package/dist/C_Steps-DY7vl-4I.css.map +0 -1
- package/dist/C_Time-Bd_e1YDN.css.map +0 -1
- package/dist/C_Time-CKb_fwdm.css.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_AudioPlayer2.js","names":["theme","showCover","showPlaylist","tracks"],"sources":["../src/components/C_AudioPlayer/types.ts","../src/components/C_AudioPlayer/index.vue","../src/components/C_AudioPlayer/index.vue","../src/components/C_AudioPlayer/index.vue"],"sourcesContent":["/**\r\n * @Description: Audio player component type definitions\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\r\n */\r\n\r\n/** Single audio track */\r\nexport interface AudioTrack {\r\n /** Unique identifier */\r\n id: string | number\r\n /** Track title */\r\n title: string\r\n /** Artist / author */\r\n artist?: string\r\n /** Audio source URL */\r\n src: string\r\n /** Cover image URL */\r\n cover?: string\r\n /** Duration in seconds (optional, for static display) */\r\n duration?: number\r\n /** Extra data */\r\n extra?: Record<string, unknown>\r\n}\r\n\r\n/** Component props */\r\nexport interface AudioPlayerProps {\r\n /** Playlist */\r\n tracks: AudioTrack[]\r\n /** Initial active index */\r\n initialIndex?: number\r\n /** Whether to show the playlist panel */\r\n showPlaylist?: boolean\r\n /** Whether to show the cover art */\r\n showCover?: boolean\r\n /** Whether to auto-play on mount */\r\n autoplay?: boolean\r\n /** Playback mode */\r\n mode?: 'list' | 'loop' | 'single' | 'shuffle'\r\n /** Theme appearance */\r\n theme?: 'default' | 'minimal'\r\n}\r\n\r\n/** Default props */\r\nexport const DEFAULT_AUDIO_PLAYER_PROPS: Partial<AudioPlayerProps> = {\r\n initialIndex: 0,\r\n showPlaylist: true,\r\n showCover: true,\r\n autoplay: false,\r\n mode: 'list',\r\n theme: 'default',\r\n}\r\n\r\n/** Playback mode icon map */\r\nexport const MODE_ICON_MAP: Record<string, { icon: string; label: string }> = {\r\n list: { icon: 'mdi:repeat', label: 'List Loop' },\r\n loop: { icon: 'mdi:repeat-once', label: 'Single Loop' },\r\n single: { icon: 'mdi:numeric-1-box', label: 'Play Once' },\r\n shuffle: { icon: 'mdi:shuffle-variant', label: 'Shuffle' },\r\n}\r\n\r\n/** Format seconds to mm:ss */\r\nexport function formatTime(seconds: number): string {\r\n if (!Number.isFinite(seconds) || seconds < 0) return '00:00'\r\n const m = Math.floor(seconds / 60)\r\n const s = Math.floor(seconds % 60)\r\n return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 音频播放器组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-audio-player\"\r\n :class=\"{ 'is-minimal': theme === 'minimal' }\"\r\n >\r\n <!-- ================ Now Playing ================ -->\r\n <div class=\"c-audio-player__now-playing\">\r\n <div\r\n v-if=\"showCover\"\r\n class=\"c-audio-player__cover\"\r\n >\r\n <img\r\n v-if=\"currentTrack?.cover\"\r\n :src=\"currentTrack.cover\"\r\n :alt=\"currentTrack.title\"\r\n />\r\n <C_Icon\r\n v-else\r\n name=\"mdi:music-note\"\r\n class=\"c-audio-player__cover-placeholder\"\r\n />\r\n </div>\r\n <div class=\"c-audio-player__info\">\r\n <div class=\"c-audio-player__title\">{{\r\n currentTrack?.title ?? '未选择曲目'\r\n }}</div>\r\n <div\r\n v-if=\"currentTrack?.artist\"\r\n class=\"c-audio-player__artist\"\r\n >\r\n {{ currentTrack.artist }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ================ Progress ================ -->\r\n <div\r\n v-if=\"theme !== 'minimal'\"\r\n class=\"c-audio-player__progress\"\r\n >\r\n <div\r\n class=\"c-audio-player__progress-bar\"\r\n @click=\"seekByClick\"\r\n >\r\n <div\r\n class=\"c-audio-player__progress-fill\"\r\n :style=\"{ width: `${progressPercent}%` }\"\r\n />\r\n </div>\r\n <div class=\"c-audio-player__time\">\r\n <span>{{ formatTime(currentTime) }}</span>\r\n <span>{{ formatTime(totalDuration) }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- ================ Controls ================ -->\r\n <div class=\"c-audio-player__controls\">\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-mode\"\r\n :title=\"currentModeLabel\"\r\n @click=\"cycleMode\"\r\n >\r\n <C_Icon :name=\"currentModeIcon\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-skip\"\r\n title=\"上一曲\"\r\n @click=\"prev\"\r\n >\r\n <C_Icon name=\"mdi:skip-previous\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-play\"\r\n :title=\"isPlaying ? '暂停' : '播放'\"\r\n @click=\"togglePlay\"\r\n >\r\n <C_Icon :name=\"isPlaying ? 'mdi:pause' : 'mdi:play'\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-skip\"\r\n title=\"下一曲\"\r\n @click=\"next\"\r\n >\r\n <C_Icon name=\"mdi:skip-next\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-mode\"\r\n title=\"播放列表\"\r\n @click=\"playlistVisible = !playlistVisible\"\r\n >\r\n <C_Icon name=\"mdi:playlist-music\" />\r\n </button>\r\n </div>\r\n\r\n <!-- ================ Volume ================ -->\r\n <div\r\n v-if=\"theme !== 'minimal'\"\r\n class=\"c-audio-player__volume\"\r\n >\r\n <C_Icon\r\n :name=\"volumeIcon\"\r\n class=\"c-audio-player__volume-icon\"\r\n @click=\"toggleMute\"\r\n />\r\n <NSlider\r\n v-model:value=\"volume\"\r\n :min=\"0\"\r\n :max=\"100\"\r\n :step=\"1\"\r\n class=\"c-audio-player__volume-slider\"\r\n @update:value=\"handleVolumeChange\"\r\n />\r\n </div>\r\n\r\n <!-- ================ Playlist ================ -->\r\n <div\r\n v-if=\"showPlaylist && playlistVisible && theme !== 'minimal'\"\r\n class=\"c-audio-player__playlist\"\r\n >\r\n <div class=\"c-audio-player__playlist-header\">\r\n <span>播放列表</span>\r\n <span>{{ tracks.length }} 首</span>\r\n </div>\r\n <div\r\n v-for=\"(track, idx) in tracks\"\r\n :key=\"track.id\"\r\n class=\"c-audio-player__track\"\r\n :class=\"{ 'is-active': idx === activeIndex }\"\r\n @click=\"playTrack(idx)\"\r\n >\r\n <span class=\"c-audio-player__track-index\">\r\n <C_Icon\r\n v-if=\"idx === activeIndex && isPlaying\"\r\n name=\"mdi:volume-high\"\r\n />\r\n <template v-else>{{ idx + 1 }}</template>\r\n </span>\r\n <div class=\"c-audio-player__track-info\">\r\n <div class=\"c-audio-player__track-title\">{{ track.title }}</div>\r\n <div\r\n v-if=\"track.artist\"\r\n class=\"c-audio-player__track-artist\"\r\n >\r\n {{ track.artist }}\r\n </div>\r\n </div>\r\n <span\r\n v-if=\"track.duration\"\r\n class=\"c-audio-player__track-duration\"\r\n >\r\n {{ formatTime(track.duration) }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed, onBeforeUnmount, ref, watch } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import {\r\n DEFAULT_AUDIO_PLAYER_PROPS,\r\n formatTime,\r\n MODE_ICON_MAP,\r\n type AudioPlayerProps,\r\n } from './types'\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n tracks: AudioPlayerProps['tracks']\r\n initialIndex?: number\r\n showPlaylist?: boolean\r\n showCover?: boolean\r\n autoplay?: boolean\r\n mode?: AudioPlayerProps['mode']\r\n theme?: AudioPlayerProps['theme']\r\n }>(),\r\n {\r\n initialIndex: DEFAULT_AUDIO_PLAYER_PROPS.initialIndex,\r\n showPlaylist: DEFAULT_AUDIO_PLAYER_PROPS.showPlaylist,\r\n showCover: true,\r\n autoplay: DEFAULT_AUDIO_PLAYER_PROPS.autoplay,\r\n mode: DEFAULT_AUDIO_PLAYER_PROPS.mode,\r\n theme: DEFAULT_AUDIO_PLAYER_PROPS.theme,\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n play: [index: number]\r\n pause: []\r\n ended: [index: number]\r\n modeChange: [mode: string]\r\n }>()\r\n\r\n // ==================== Audio Core ====================\r\n\r\n let audio: HTMLAudioElement | null = null\r\n\r\n const activeIndex = ref(props.initialIndex ?? 0)\r\n const isPlaying = ref(false)\r\n const currentTime = ref(0)\r\n const totalDuration = ref(0)\r\n const volume = ref(70)\r\n const prevVolume = ref(70)\r\n const playlistVisible = ref(props.showPlaylist)\r\n const playMode = ref(props.mode ?? 'list')\r\n\r\n const currentTrack = computed(() => props.tracks[activeIndex.value])\r\n\r\n const progressPercent = computed(() => {\r\n if (totalDuration.value === 0) return 0\r\n return (currentTime.value / totalDuration.value) * 100\r\n })\r\n\r\n const volumeIcon = computed(() => {\r\n if (volume.value === 0) return 'mdi:volume-off'\r\n if (volume.value < 40) return 'mdi:volume-low'\r\n if (volume.value < 70) return 'mdi:volume-medium'\r\n return 'mdi:volume-high'\r\n })\r\n\r\n const currentModeIcon = computed(\r\n () => MODE_ICON_MAP[playMode.value]?.icon ?? 'mdi:repeat'\r\n )\r\n const currentModeLabel = computed(\r\n () => MODE_ICON_MAP[playMode.value]?.label ?? '循环'\r\n )\r\n\r\n /** 初始化音频实例 */\r\n function initAudio() {\r\n if (audio) {\r\n audio.pause()\r\n audio.removeEventListener('timeupdate', onTimeUpdate)\r\n audio.removeEventListener('loadedmetadata', onMetaLoaded)\r\n audio.removeEventListener('ended', onEnded)\r\n }\r\n const track = currentTrack.value\r\n if (!track) return\r\n\r\n audio = new Audio(track.src)\r\n audio.volume = volume.value / 100\r\n audio.addEventListener('timeupdate', onTimeUpdate)\r\n audio.addEventListener('loadedmetadata', onMetaLoaded)\r\n audio.addEventListener('ended', onEnded)\r\n }\r\n\r\n /** 播放进度更新回调 */\r\n function onTimeUpdate() {\r\n if (audio) currentTime.value = audio.currentTime\r\n }\r\n\r\n /** 音频元数据加载完成回调 */\r\n function onMetaLoaded() {\r\n if (audio) totalDuration.value = audio.duration\r\n }\r\n\r\n /** 播放结束回调,根据模式决定下一步 */\r\n function onEnded() {\r\n emit('ended', activeIndex.value)\r\n switch (playMode.value) {\r\n case 'loop':\r\n audio?.play().catch(() => {})\r\n break\r\n case 'single':\r\n isPlaying.value = false\r\n break\r\n case 'shuffle':\r\n playTrack(Math.floor(Math.random() * props.tracks.length))\r\n break\r\n default: // list\r\n if (activeIndex.value < props.tracks.length - 1) next()\r\n else {\r\n activeIndex.value = 0\r\n initAudio()\r\n audio?.play().catch(() => {})\r\n }\r\n }\r\n }\r\n\r\n /** 切换播放/暂停 */\r\n function togglePlay() {\r\n if (!audio) initAudio()\r\n if (isPlaying.value) {\r\n audio?.pause()\r\n isPlaying.value = false\r\n emit('pause')\r\n } else {\r\n audio?.play().catch(() => {})\r\n isPlaying.value = true\r\n emit('play', activeIndex.value)\r\n }\r\n }\r\n\r\n /** 播放指定索引的曲目 */\r\n function playTrack(idx: number) {\r\n activeIndex.value = idx\r\n initAudio()\r\n audio?.play().catch(() => {})\r\n isPlaying.value = true\r\n emit('play', idx)\r\n }\r\n\r\n /** 上一曲 */\r\n function prev() {\r\n const idx =\r\n activeIndex.value <= 0 ? props.tracks.length - 1 : activeIndex.value - 1\r\n playTrack(idx)\r\n }\r\n\r\n /** 下一曲 */\r\n function next() {\r\n const idx =\r\n activeIndex.value >= props.tracks.length - 1 ? 0 : activeIndex.value + 1\r\n playTrack(idx)\r\n }\r\n\r\n /** 点击进度条跳转播放位置 */\r\n function seekByClick(e: MouseEvent) {\r\n if (!audio || !totalDuration.value) return\r\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect()\r\n const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width))\r\n audio.currentTime = ratio * totalDuration.value\r\n currentTime.value = audio.currentTime\r\n }\r\n\r\n /** 处理音量变更 */\r\n function handleVolumeChange(val: number) {\r\n volume.value = val\r\n if (audio) audio.volume = val / 100\r\n }\r\n\r\n /** 切换静音状态 */\r\n function toggleMute() {\r\n if (volume.value > 0) {\r\n prevVolume.value = volume.value\r\n volume.value = 0\r\n } else {\r\n volume.value = prevVolume.value || 70\r\n }\r\n if (audio) audio.volume = volume.value / 100\r\n }\r\n\r\n const MODES = ['list', 'loop', 'single', 'shuffle'] as const\r\n /** 循环切换播放模式 */\r\n function cycleMode() {\r\n const idx = MODES.indexOf(playMode.value as (typeof MODES)[number])\r\n playMode.value = MODES[(idx + 1) % MODES.length]\r\n emit('modeChange', playMode.value)\r\n }\r\n\r\n // ==================== Lifecycle ====================\r\n\r\n watch(\r\n () => props.tracks,\r\n () => {\r\n activeIndex.value = 0\r\n initAudio()\r\n }\r\n )\r\n\r\n watch(\r\n () => props.initialIndex,\r\n val => {\r\n if (val !== undefined && val !== activeIndex.value) {\r\n activeIndex.value = val\r\n initAudio()\r\n }\r\n }\r\n )\r\n\r\n onBeforeUnmount(() => {\r\n if (audio) {\r\n audio.pause()\r\n audio.removeEventListener('timeupdate', onTimeUpdate)\r\n audio.removeEventListener('loadedmetadata', onMetaLoaded)\r\n audio.removeEventListener('ended', onEnded)\r\n audio = null\r\n }\r\n })\r\n\r\n // 自动播放\r\n if (props.autoplay && props.tracks.length > 0) {\r\n playTrack(activeIndex.value)\r\n }\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 音频播放器组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-audio-player\"\r\n :class=\"{ 'is-minimal': theme === 'minimal' }\"\r\n >\r\n <!-- ================ Now Playing ================ -->\r\n <div class=\"c-audio-player__now-playing\">\r\n <div\r\n v-if=\"showCover\"\r\n class=\"c-audio-player__cover\"\r\n >\r\n <img\r\n v-if=\"currentTrack?.cover\"\r\n :src=\"currentTrack.cover\"\r\n :alt=\"currentTrack.title\"\r\n />\r\n <C_Icon\r\n v-else\r\n name=\"mdi:music-note\"\r\n class=\"c-audio-player__cover-placeholder\"\r\n />\r\n </div>\r\n <div class=\"c-audio-player__info\">\r\n <div class=\"c-audio-player__title\">{{\r\n currentTrack?.title ?? '未选择曲目'\r\n }}</div>\r\n <div\r\n v-if=\"currentTrack?.artist\"\r\n class=\"c-audio-player__artist\"\r\n >\r\n {{ currentTrack.artist }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ================ Progress ================ -->\r\n <div\r\n v-if=\"theme !== 'minimal'\"\r\n class=\"c-audio-player__progress\"\r\n >\r\n <div\r\n class=\"c-audio-player__progress-bar\"\r\n @click=\"seekByClick\"\r\n >\r\n <div\r\n class=\"c-audio-player__progress-fill\"\r\n :style=\"{ width: `${progressPercent}%` }\"\r\n />\r\n </div>\r\n <div class=\"c-audio-player__time\">\r\n <span>{{ formatTime(currentTime) }}</span>\r\n <span>{{ formatTime(totalDuration) }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- ================ Controls ================ -->\r\n <div class=\"c-audio-player__controls\">\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-mode\"\r\n :title=\"currentModeLabel\"\r\n @click=\"cycleMode\"\r\n >\r\n <C_Icon :name=\"currentModeIcon\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-skip\"\r\n title=\"上一曲\"\r\n @click=\"prev\"\r\n >\r\n <C_Icon name=\"mdi:skip-previous\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-play\"\r\n :title=\"isPlaying ? '暂停' : '播放'\"\r\n @click=\"togglePlay\"\r\n >\r\n <C_Icon :name=\"isPlaying ? 'mdi:pause' : 'mdi:play'\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-skip\"\r\n title=\"下一曲\"\r\n @click=\"next\"\r\n >\r\n <C_Icon name=\"mdi:skip-next\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-mode\"\r\n title=\"播放列表\"\r\n @click=\"playlistVisible = !playlistVisible\"\r\n >\r\n <C_Icon name=\"mdi:playlist-music\" />\r\n </button>\r\n </div>\r\n\r\n <!-- ================ Volume ================ -->\r\n <div\r\n v-if=\"theme !== 'minimal'\"\r\n class=\"c-audio-player__volume\"\r\n >\r\n <C_Icon\r\n :name=\"volumeIcon\"\r\n class=\"c-audio-player__volume-icon\"\r\n @click=\"toggleMute\"\r\n />\r\n <NSlider\r\n v-model:value=\"volume\"\r\n :min=\"0\"\r\n :max=\"100\"\r\n :step=\"1\"\r\n class=\"c-audio-player__volume-slider\"\r\n @update:value=\"handleVolumeChange\"\r\n />\r\n </div>\r\n\r\n <!-- ================ Playlist ================ -->\r\n <div\r\n v-if=\"showPlaylist && playlistVisible && theme !== 'minimal'\"\r\n class=\"c-audio-player__playlist\"\r\n >\r\n <div class=\"c-audio-player__playlist-header\">\r\n <span>播放列表</span>\r\n <span>{{ tracks.length }} 首</span>\r\n </div>\r\n <div\r\n v-for=\"(track, idx) in tracks\"\r\n :key=\"track.id\"\r\n class=\"c-audio-player__track\"\r\n :class=\"{ 'is-active': idx === activeIndex }\"\r\n @click=\"playTrack(idx)\"\r\n >\r\n <span class=\"c-audio-player__track-index\">\r\n <C_Icon\r\n v-if=\"idx === activeIndex && isPlaying\"\r\n name=\"mdi:volume-high\"\r\n />\r\n <template v-else>{{ idx + 1 }}</template>\r\n </span>\r\n <div class=\"c-audio-player__track-info\">\r\n <div class=\"c-audio-player__track-title\">{{ track.title }}</div>\r\n <div\r\n v-if=\"track.artist\"\r\n class=\"c-audio-player__track-artist\"\r\n >\r\n {{ track.artist }}\r\n </div>\r\n </div>\r\n <span\r\n v-if=\"track.duration\"\r\n class=\"c-audio-player__track-duration\"\r\n >\r\n {{ formatTime(track.duration) }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed, onBeforeUnmount, ref, watch } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import {\r\n DEFAULT_AUDIO_PLAYER_PROPS,\r\n formatTime,\r\n MODE_ICON_MAP,\r\n type AudioPlayerProps,\r\n } from './types'\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n tracks: AudioPlayerProps['tracks']\r\n initialIndex?: number\r\n showPlaylist?: boolean\r\n showCover?: boolean\r\n autoplay?: boolean\r\n mode?: AudioPlayerProps['mode']\r\n theme?: AudioPlayerProps['theme']\r\n }>(),\r\n {\r\n initialIndex: DEFAULT_AUDIO_PLAYER_PROPS.initialIndex,\r\n showPlaylist: DEFAULT_AUDIO_PLAYER_PROPS.showPlaylist,\r\n showCover: true,\r\n autoplay: DEFAULT_AUDIO_PLAYER_PROPS.autoplay,\r\n mode: DEFAULT_AUDIO_PLAYER_PROPS.mode,\r\n theme: DEFAULT_AUDIO_PLAYER_PROPS.theme,\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n play: [index: number]\r\n pause: []\r\n ended: [index: number]\r\n modeChange: [mode: string]\r\n }>()\r\n\r\n // ==================== Audio Core ====================\r\n\r\n let audio: HTMLAudioElement | null = null\r\n\r\n const activeIndex = ref(props.initialIndex ?? 0)\r\n const isPlaying = ref(false)\r\n const currentTime = ref(0)\r\n const totalDuration = ref(0)\r\n const volume = ref(70)\r\n const prevVolume = ref(70)\r\n const playlistVisible = ref(props.showPlaylist)\r\n const playMode = ref(props.mode ?? 'list')\r\n\r\n const currentTrack = computed(() => props.tracks[activeIndex.value])\r\n\r\n const progressPercent = computed(() => {\r\n if (totalDuration.value === 0) return 0\r\n return (currentTime.value / totalDuration.value) * 100\r\n })\r\n\r\n const volumeIcon = computed(() => {\r\n if (volume.value === 0) return 'mdi:volume-off'\r\n if (volume.value < 40) return 'mdi:volume-low'\r\n if (volume.value < 70) return 'mdi:volume-medium'\r\n return 'mdi:volume-high'\r\n })\r\n\r\n const currentModeIcon = computed(\r\n () => MODE_ICON_MAP[playMode.value]?.icon ?? 'mdi:repeat'\r\n )\r\n const currentModeLabel = computed(\r\n () => MODE_ICON_MAP[playMode.value]?.label ?? '循环'\r\n )\r\n\r\n /** 初始化音频实例 */\r\n function initAudio() {\r\n if (audio) {\r\n audio.pause()\r\n audio.removeEventListener('timeupdate', onTimeUpdate)\r\n audio.removeEventListener('loadedmetadata', onMetaLoaded)\r\n audio.removeEventListener('ended', onEnded)\r\n }\r\n const track = currentTrack.value\r\n if (!track) return\r\n\r\n audio = new Audio(track.src)\r\n audio.volume = volume.value / 100\r\n audio.addEventListener('timeupdate', onTimeUpdate)\r\n audio.addEventListener('loadedmetadata', onMetaLoaded)\r\n audio.addEventListener('ended', onEnded)\r\n }\r\n\r\n /** 播放进度更新回调 */\r\n function onTimeUpdate() {\r\n if (audio) currentTime.value = audio.currentTime\r\n }\r\n\r\n /** 音频元数据加载完成回调 */\r\n function onMetaLoaded() {\r\n if (audio) totalDuration.value = audio.duration\r\n }\r\n\r\n /** 播放结束回调,根据模式决定下一步 */\r\n function onEnded() {\r\n emit('ended', activeIndex.value)\r\n switch (playMode.value) {\r\n case 'loop':\r\n audio?.play().catch(() => {})\r\n break\r\n case 'single':\r\n isPlaying.value = false\r\n break\r\n case 'shuffle':\r\n playTrack(Math.floor(Math.random() * props.tracks.length))\r\n break\r\n default: // list\r\n if (activeIndex.value < props.tracks.length - 1) next()\r\n else {\r\n activeIndex.value = 0\r\n initAudio()\r\n audio?.play().catch(() => {})\r\n }\r\n }\r\n }\r\n\r\n /** 切换播放/暂停 */\r\n function togglePlay() {\r\n if (!audio) initAudio()\r\n if (isPlaying.value) {\r\n audio?.pause()\r\n isPlaying.value = false\r\n emit('pause')\r\n } else {\r\n audio?.play().catch(() => {})\r\n isPlaying.value = true\r\n emit('play', activeIndex.value)\r\n }\r\n }\r\n\r\n /** 播放指定索引的曲目 */\r\n function playTrack(idx: number) {\r\n activeIndex.value = idx\r\n initAudio()\r\n audio?.play().catch(() => {})\r\n isPlaying.value = true\r\n emit('play', idx)\r\n }\r\n\r\n /** 上一曲 */\r\n function prev() {\r\n const idx =\r\n activeIndex.value <= 0 ? props.tracks.length - 1 : activeIndex.value - 1\r\n playTrack(idx)\r\n }\r\n\r\n /** 下一曲 */\r\n function next() {\r\n const idx =\r\n activeIndex.value >= props.tracks.length - 1 ? 0 : activeIndex.value + 1\r\n playTrack(idx)\r\n }\r\n\r\n /** 点击进度条跳转播放位置 */\r\n function seekByClick(e: MouseEvent) {\r\n if (!audio || !totalDuration.value) return\r\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect()\r\n const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width))\r\n audio.currentTime = ratio * totalDuration.value\r\n currentTime.value = audio.currentTime\r\n }\r\n\r\n /** 处理音量变更 */\r\n function handleVolumeChange(val: number) {\r\n volume.value = val\r\n if (audio) audio.volume = val / 100\r\n }\r\n\r\n /** 切换静音状态 */\r\n function toggleMute() {\r\n if (volume.value > 0) {\r\n prevVolume.value = volume.value\r\n volume.value = 0\r\n } else {\r\n volume.value = prevVolume.value || 70\r\n }\r\n if (audio) audio.volume = volume.value / 100\r\n }\r\n\r\n const MODES = ['list', 'loop', 'single', 'shuffle'] as const\r\n /** 循环切换播放模式 */\r\n function cycleMode() {\r\n const idx = MODES.indexOf(playMode.value as (typeof MODES)[number])\r\n playMode.value = MODES[(idx + 1) % MODES.length]\r\n emit('modeChange', playMode.value)\r\n }\r\n\r\n // ==================== Lifecycle ====================\r\n\r\n watch(\r\n () => props.tracks,\r\n () => {\r\n activeIndex.value = 0\r\n initAudio()\r\n }\r\n )\r\n\r\n watch(\r\n () => props.initialIndex,\r\n val => {\r\n if (val !== undefined && val !== activeIndex.value) {\r\n activeIndex.value = val\r\n initAudio()\r\n }\r\n }\r\n )\r\n\r\n onBeforeUnmount(() => {\r\n if (audio) {\r\n audio.pause()\r\n audio.removeEventListener('timeupdate', onTimeUpdate)\r\n audio.removeEventListener('loadedmetadata', onMetaLoaded)\r\n audio.removeEventListener('ended', onEnded)\r\n audio = null\r\n }\r\n })\r\n\r\n // 自动播放\r\n if (props.autoplay && props.tracks.length > 0) {\r\n playTrack(activeIndex.value)\r\n }\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Description: 音频播放器组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-audio-player\"\r\n :class=\"{ 'is-minimal': theme === 'minimal' }\"\r\n >\r\n <!-- ================ Now Playing ================ -->\r\n <div class=\"c-audio-player__now-playing\">\r\n <div\r\n v-if=\"showCover\"\r\n class=\"c-audio-player__cover\"\r\n >\r\n <img\r\n v-if=\"currentTrack?.cover\"\r\n :src=\"currentTrack.cover\"\r\n :alt=\"currentTrack.title\"\r\n />\r\n <C_Icon\r\n v-else\r\n name=\"mdi:music-note\"\r\n class=\"c-audio-player__cover-placeholder\"\r\n />\r\n </div>\r\n <div class=\"c-audio-player__info\">\r\n <div class=\"c-audio-player__title\">{{\r\n currentTrack?.title ?? '未选择曲目'\r\n }}</div>\r\n <div\r\n v-if=\"currentTrack?.artist\"\r\n class=\"c-audio-player__artist\"\r\n >\r\n {{ currentTrack.artist }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- ================ Progress ================ -->\r\n <div\r\n v-if=\"theme !== 'minimal'\"\r\n class=\"c-audio-player__progress\"\r\n >\r\n <div\r\n class=\"c-audio-player__progress-bar\"\r\n @click=\"seekByClick\"\r\n >\r\n <div\r\n class=\"c-audio-player__progress-fill\"\r\n :style=\"{ width: `${progressPercent}%` }\"\r\n />\r\n </div>\r\n <div class=\"c-audio-player__time\">\r\n <span>{{ formatTime(currentTime) }}</span>\r\n <span>{{ formatTime(totalDuration) }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- ================ Controls ================ -->\r\n <div class=\"c-audio-player__controls\">\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-mode\"\r\n :title=\"currentModeLabel\"\r\n @click=\"cycleMode\"\r\n >\r\n <C_Icon :name=\"currentModeIcon\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-skip\"\r\n title=\"上一曲\"\r\n @click=\"prev\"\r\n >\r\n <C_Icon name=\"mdi:skip-previous\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-play\"\r\n :title=\"isPlaying ? '暂停' : '播放'\"\r\n @click=\"togglePlay\"\r\n >\r\n <C_Icon :name=\"isPlaying ? 'mdi:pause' : 'mdi:play'\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-skip\"\r\n title=\"下一曲\"\r\n @click=\"next\"\r\n >\r\n <C_Icon name=\"mdi:skip-next\" />\r\n </button>\r\n <button\r\n class=\"c-audio-player__ctrl-btn is-mode\"\r\n title=\"播放列表\"\r\n @click=\"playlistVisible = !playlistVisible\"\r\n >\r\n <C_Icon name=\"mdi:playlist-music\" />\r\n </button>\r\n </div>\r\n\r\n <!-- ================ Volume ================ -->\r\n <div\r\n v-if=\"theme !== 'minimal'\"\r\n class=\"c-audio-player__volume\"\r\n >\r\n <C_Icon\r\n :name=\"volumeIcon\"\r\n class=\"c-audio-player__volume-icon\"\r\n @click=\"toggleMute\"\r\n />\r\n <NSlider\r\n v-model:value=\"volume\"\r\n :min=\"0\"\r\n :max=\"100\"\r\n :step=\"1\"\r\n class=\"c-audio-player__volume-slider\"\r\n @update:value=\"handleVolumeChange\"\r\n />\r\n </div>\r\n\r\n <!-- ================ Playlist ================ -->\r\n <div\r\n v-if=\"showPlaylist && playlistVisible && theme !== 'minimal'\"\r\n class=\"c-audio-player__playlist\"\r\n >\r\n <div class=\"c-audio-player__playlist-header\">\r\n <span>播放列表</span>\r\n <span>{{ tracks.length }} 首</span>\r\n </div>\r\n <div\r\n v-for=\"(track, idx) in tracks\"\r\n :key=\"track.id\"\r\n class=\"c-audio-player__track\"\r\n :class=\"{ 'is-active': idx === activeIndex }\"\r\n @click=\"playTrack(idx)\"\r\n >\r\n <span class=\"c-audio-player__track-index\">\r\n <C_Icon\r\n v-if=\"idx === activeIndex && isPlaying\"\r\n name=\"mdi:volume-high\"\r\n />\r\n <template v-else>{{ idx + 1 }}</template>\r\n </span>\r\n <div class=\"c-audio-player__track-info\">\r\n <div class=\"c-audio-player__track-title\">{{ track.title }}</div>\r\n <div\r\n v-if=\"track.artist\"\r\n class=\"c-audio-player__track-artist\"\r\n >\r\n {{ track.artist }}\r\n </div>\r\n </div>\r\n <span\r\n v-if=\"track.duration\"\r\n class=\"c-audio-player__track-duration\"\r\n >\r\n {{ formatTime(track.duration) }}\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed, onBeforeUnmount, ref, watch } from 'vue'\r\n import C_Icon from '../C_Icon/index.vue'\r\n import {\r\n DEFAULT_AUDIO_PLAYER_PROPS,\r\n formatTime,\r\n MODE_ICON_MAP,\r\n type AudioPlayerProps,\r\n } from './types'\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n tracks: AudioPlayerProps['tracks']\r\n initialIndex?: number\r\n showPlaylist?: boolean\r\n showCover?: boolean\r\n autoplay?: boolean\r\n mode?: AudioPlayerProps['mode']\r\n theme?: AudioPlayerProps['theme']\r\n }>(),\r\n {\r\n initialIndex: DEFAULT_AUDIO_PLAYER_PROPS.initialIndex,\r\n showPlaylist: DEFAULT_AUDIO_PLAYER_PROPS.showPlaylist,\r\n showCover: true,\r\n autoplay: DEFAULT_AUDIO_PLAYER_PROPS.autoplay,\r\n mode: DEFAULT_AUDIO_PLAYER_PROPS.mode,\r\n theme: DEFAULT_AUDIO_PLAYER_PROPS.theme,\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n play: [index: number]\r\n pause: []\r\n ended: [index: number]\r\n modeChange: [mode: string]\r\n }>()\r\n\r\n // ==================== Audio Core ====================\r\n\r\n let audio: HTMLAudioElement | null = null\r\n\r\n const activeIndex = ref(props.initialIndex ?? 0)\r\n const isPlaying = ref(false)\r\n const currentTime = ref(0)\r\n const totalDuration = ref(0)\r\n const volume = ref(70)\r\n const prevVolume = ref(70)\r\n const playlistVisible = ref(props.showPlaylist)\r\n const playMode = ref(props.mode ?? 'list')\r\n\r\n const currentTrack = computed(() => props.tracks[activeIndex.value])\r\n\r\n const progressPercent = computed(() => {\r\n if (totalDuration.value === 0) return 0\r\n return (currentTime.value / totalDuration.value) * 100\r\n })\r\n\r\n const volumeIcon = computed(() => {\r\n if (volume.value === 0) return 'mdi:volume-off'\r\n if (volume.value < 40) return 'mdi:volume-low'\r\n if (volume.value < 70) return 'mdi:volume-medium'\r\n return 'mdi:volume-high'\r\n })\r\n\r\n const currentModeIcon = computed(\r\n () => MODE_ICON_MAP[playMode.value]?.icon ?? 'mdi:repeat'\r\n )\r\n const currentModeLabel = computed(\r\n () => MODE_ICON_MAP[playMode.value]?.label ?? '循环'\r\n )\r\n\r\n /** 初始化音频实例 */\r\n function initAudio() {\r\n if (audio) {\r\n audio.pause()\r\n audio.removeEventListener('timeupdate', onTimeUpdate)\r\n audio.removeEventListener('loadedmetadata', onMetaLoaded)\r\n audio.removeEventListener('ended', onEnded)\r\n }\r\n const track = currentTrack.value\r\n if (!track) return\r\n\r\n audio = new Audio(track.src)\r\n audio.volume = volume.value / 100\r\n audio.addEventListener('timeupdate', onTimeUpdate)\r\n audio.addEventListener('loadedmetadata', onMetaLoaded)\r\n audio.addEventListener('ended', onEnded)\r\n }\r\n\r\n /** 播放进度更新回调 */\r\n function onTimeUpdate() {\r\n if (audio) currentTime.value = audio.currentTime\r\n }\r\n\r\n /** 音频元数据加载完成回调 */\r\n function onMetaLoaded() {\r\n if (audio) totalDuration.value = audio.duration\r\n }\r\n\r\n /** 播放结束回调,根据模式决定下一步 */\r\n function onEnded() {\r\n emit('ended', activeIndex.value)\r\n switch (playMode.value) {\r\n case 'loop':\r\n audio?.play().catch(() => {})\r\n break\r\n case 'single':\r\n isPlaying.value = false\r\n break\r\n case 'shuffle':\r\n playTrack(Math.floor(Math.random() * props.tracks.length))\r\n break\r\n default: // list\r\n if (activeIndex.value < props.tracks.length - 1) next()\r\n else {\r\n activeIndex.value = 0\r\n initAudio()\r\n audio?.play().catch(() => {})\r\n }\r\n }\r\n }\r\n\r\n /** 切换播放/暂停 */\r\n function togglePlay() {\r\n if (!audio) initAudio()\r\n if (isPlaying.value) {\r\n audio?.pause()\r\n isPlaying.value = false\r\n emit('pause')\r\n } else {\r\n audio?.play().catch(() => {})\r\n isPlaying.value = true\r\n emit('play', activeIndex.value)\r\n }\r\n }\r\n\r\n /** 播放指定索引的曲目 */\r\n function playTrack(idx: number) {\r\n activeIndex.value = idx\r\n initAudio()\r\n audio?.play().catch(() => {})\r\n isPlaying.value = true\r\n emit('play', idx)\r\n }\r\n\r\n /** 上一曲 */\r\n function prev() {\r\n const idx =\r\n activeIndex.value <= 0 ? props.tracks.length - 1 : activeIndex.value - 1\r\n playTrack(idx)\r\n }\r\n\r\n /** 下一曲 */\r\n function next() {\r\n const idx =\r\n activeIndex.value >= props.tracks.length - 1 ? 0 : activeIndex.value + 1\r\n playTrack(idx)\r\n }\r\n\r\n /** 点击进度条跳转播放位置 */\r\n function seekByClick(e: MouseEvent) {\r\n if (!audio || !totalDuration.value) return\r\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect()\r\n const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width))\r\n audio.currentTime = ratio * totalDuration.value\r\n currentTime.value = audio.currentTime\r\n }\r\n\r\n /** 处理音量变更 */\r\n function handleVolumeChange(val: number) {\r\n volume.value = val\r\n if (audio) audio.volume = val / 100\r\n }\r\n\r\n /** 切换静音状态 */\r\n function toggleMute() {\r\n if (volume.value > 0) {\r\n prevVolume.value = volume.value\r\n volume.value = 0\r\n } else {\r\n volume.value = prevVolume.value || 70\r\n }\r\n if (audio) audio.volume = volume.value / 100\r\n }\r\n\r\n const MODES = ['list', 'loop', 'single', 'shuffle'] as const\r\n /** 循环切换播放模式 */\r\n function cycleMode() {\r\n const idx = MODES.indexOf(playMode.value as (typeof MODES)[number])\r\n playMode.value = MODES[(idx + 1) % MODES.length]\r\n emit('modeChange', playMode.value)\r\n }\r\n\r\n // ==================== Lifecycle ====================\r\n\r\n watch(\r\n () => props.tracks,\r\n () => {\r\n activeIndex.value = 0\r\n initAudio()\r\n }\r\n )\r\n\r\n watch(\r\n () => props.initialIndex,\r\n val => {\r\n if (val !== undefined && val !== activeIndex.value) {\r\n activeIndex.value = val\r\n initAudio()\r\n }\r\n }\r\n )\r\n\r\n onBeforeUnmount(() => {\r\n if (audio) {\r\n audio.pause()\r\n audio.removeEventListener('timeupdate', onTimeUpdate)\r\n audio.removeEventListener('loadedmetadata', onMetaLoaded)\r\n audio.removeEventListener('ended', onEnded)\r\n audio = null\r\n }\r\n })\r\n\r\n // 自动播放\r\n if (props.autoplay && props.tracks.length > 0) {\r\n playTrack(activeIndex.value)\r\n }\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_AudioPlayer2.js","names":[],"sources":["../src/components/C_AudioPlayer/types.ts","../src/components/C_AudioPlayer/index.vue"],"sourcesContent":["/**\n * @Description: Audio player component type definitions\n * Copyright (c) 2026 by CHENY, All Rights Reserved.\n */\n\n/** Single audio track */\nexport interface AudioTrack {\n /** Unique identifier */\n id: string | number\n /** Track title */\n title: string\n /** Artist / author */\n artist?: string\n /** Audio source URL */\n src: string\n /** Cover image URL */\n cover?: string\n /** Duration in seconds (optional, for static display) */\n duration?: number\n /** Extra data */\n extra?: Record<string, unknown>\n}\n\n/** Component props */\nexport interface AudioPlayerProps {\n /** Playlist */\n tracks: AudioTrack[]\n /** Initial active index */\n initialIndex?: number\n /** Whether to show the playlist panel */\n showPlaylist?: boolean\n /** Whether to show the cover art */\n showCover?: boolean\n /** Whether to auto-play on mount */\n autoplay?: boolean\n /** Playback mode */\n mode?: 'list' | 'loop' | 'single' | 'shuffle'\n /** Theme appearance */\n theme?: 'default' | 'minimal'\n}\n\n/** Default props */\nexport const DEFAULT_AUDIO_PLAYER_PROPS: Partial<AudioPlayerProps> = {\n initialIndex: 0,\n showPlaylist: true,\n showCover: true,\n autoplay: false,\n mode: 'list',\n theme: 'default',\n}\n\n/** Playback mode icon map */\nexport const MODE_ICON_MAP: Record<string, { icon: string; label: string }> = {\n list: { icon: 'mdi:repeat', label: 'List Loop' },\n loop: { icon: 'mdi:repeat-once', label: 'Single Loop' },\n single: { icon: 'mdi:numeric-1-box', label: 'Play Once' },\n shuffle: { icon: 'mdi:shuffle-variant', label: 'Shuffle' },\n}\n\n/** Format seconds to mm:ss */\nexport function formatTime(seconds: number): string {\n if (!Number.isFinite(seconds) || seconds < 0) return '00:00'\n const m = Math.floor(seconds / 60)\n const s = Math.floor(seconds % 60)\n return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`\n}\n","<!--\n * @Description: 音频播放器组件\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n class=\"c-audio-player\"\n :class=\"{ 'is-minimal': theme === 'minimal' }\"\n >\n <!-- ================ Now Playing ================ -->\n <div class=\"c-audio-player__now-playing\">\n <div\n v-if=\"showCover\"\n class=\"c-audio-player__cover\"\n >\n <img\n v-if=\"currentTrack?.cover\"\n :src=\"currentTrack.cover\"\n :alt=\"currentTrack.title\"\n />\n <C_Icon\n v-else\n name=\"mdi:music-note\"\n class=\"c-audio-player__cover-placeholder\"\n />\n </div>\n <div class=\"c-audio-player__info\">\n <div class=\"c-audio-player__title\">{{\n currentTrack?.title ?? '未选择曲目'\n }}</div>\n <div\n v-if=\"currentTrack?.artist\"\n class=\"c-audio-player__artist\"\n >\n {{ currentTrack.artist }}\n </div>\n </div>\n </div>\n\n <!-- ================ Progress ================ -->\n <div\n v-if=\"theme !== 'minimal'\"\n class=\"c-audio-player__progress\"\n >\n <div\n class=\"c-audio-player__progress-bar\"\n @click=\"seekByClick\"\n >\n <div\n class=\"c-audio-player__progress-fill\"\n :style=\"{ width: `${progressPercent}%` }\"\n />\n </div>\n <div class=\"c-audio-player__time\">\n <span>{{ formatTime(currentTime) }}</span>\n <span>{{ formatTime(totalDuration) }}</span>\n </div>\n </div>\n\n <!-- ================ Controls ================ -->\n <div class=\"c-audio-player__controls\">\n <button\n class=\"c-audio-player__ctrl-btn is-mode\"\n :title=\"currentModeLabel\"\n @click=\"cycleMode\"\n >\n <C_Icon :name=\"currentModeIcon\" />\n </button>\n <button\n class=\"c-audio-player__ctrl-btn is-skip\"\n title=\"上一曲\"\n @click=\"prev\"\n >\n <C_Icon name=\"mdi:skip-previous\" />\n </button>\n <button\n class=\"c-audio-player__ctrl-btn is-play\"\n :title=\"isPlaying ? '暂停' : '播放'\"\n @click=\"togglePlay\"\n >\n <C_Icon :name=\"isPlaying ? 'mdi:pause' : 'mdi:play'\" />\n </button>\n <button\n class=\"c-audio-player__ctrl-btn is-skip\"\n title=\"下一曲\"\n @click=\"next\"\n >\n <C_Icon name=\"mdi:skip-next\" />\n </button>\n <button\n class=\"c-audio-player__ctrl-btn is-mode\"\n title=\"播放列表\"\n @click=\"playlistVisible = !playlistVisible\"\n >\n <C_Icon name=\"mdi:playlist-music\" />\n </button>\n </div>\n\n <!-- ================ Volume ================ -->\n <div\n v-if=\"theme !== 'minimal'\"\n class=\"c-audio-player__volume\"\n >\n <C_Icon\n :name=\"volumeIcon\"\n class=\"c-audio-player__volume-icon\"\n @click=\"toggleMute\"\n />\n <NSlider\n v-model:value=\"volume\"\n :min=\"0\"\n :max=\"100\"\n :step=\"1\"\n class=\"c-audio-player__volume-slider\"\n @update:value=\"handleVolumeChange\"\n />\n </div>\n\n <!-- ================ Playlist ================ -->\n <div\n v-if=\"showPlaylist && playlistVisible && theme !== 'minimal'\"\n class=\"c-audio-player__playlist\"\n >\n <div class=\"c-audio-player__playlist-header\">\n <span>播放列表</span>\n <span>{{ tracks.length }} 首</span>\n </div>\n <div\n v-for=\"(track, idx) in tracks\"\n :key=\"track.id\"\n class=\"c-audio-player__track\"\n :class=\"{ 'is-active': idx === activeIndex }\"\n @click=\"playTrack(idx)\"\n >\n <span class=\"c-audio-player__track-index\">\n <C_Icon\n v-if=\"idx === activeIndex && isPlaying\"\n name=\"mdi:volume-high\"\n />\n <template v-else>{{ idx + 1 }}</template>\n </span>\n <div class=\"c-audio-player__track-info\">\n <div class=\"c-audio-player__track-title\">{{ track.title }}</div>\n <div\n v-if=\"track.artist\"\n class=\"c-audio-player__track-artist\"\n >\n {{ track.artist }}\n </div>\n </div>\n <span\n v-if=\"track.duration\"\n class=\"c-audio-player__track-duration\"\n >\n {{ formatTime(track.duration) }}\n </span>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { computed, onBeforeUnmount, ref, watch } from 'vue'\n import C_Icon from '../C_Icon/index.vue'\n import {\n DEFAULT_AUDIO_PLAYER_PROPS,\n formatTime,\n MODE_ICON_MAP,\n type AudioPlayerProps,\n } from './types'\n\n const props = withDefaults(\n defineProps<{\n tracks: AudioPlayerProps['tracks']\n initialIndex?: number\n showPlaylist?: boolean\n showCover?: boolean\n autoplay?: boolean\n mode?: AudioPlayerProps['mode']\n theme?: AudioPlayerProps['theme']\n }>(),\n {\n initialIndex: DEFAULT_AUDIO_PLAYER_PROPS.initialIndex,\n showPlaylist: DEFAULT_AUDIO_PLAYER_PROPS.showPlaylist,\n showCover: true,\n autoplay: DEFAULT_AUDIO_PLAYER_PROPS.autoplay,\n mode: DEFAULT_AUDIO_PLAYER_PROPS.mode,\n theme: DEFAULT_AUDIO_PLAYER_PROPS.theme,\n }\n )\n\n const emit = defineEmits<{\n play: [index: number]\n pause: []\n ended: [index: number]\n modeChange: [mode: string]\n }>()\n\n // ==================== Audio Core ====================\n\n let audio: HTMLAudioElement | null = null\n\n const activeIndex = ref(props.initialIndex ?? 0)\n const isPlaying = ref(false)\n const currentTime = ref(0)\n const totalDuration = ref(0)\n const volume = ref(70)\n const prevVolume = ref(70)\n const playlistVisible = ref(props.showPlaylist)\n const playMode = ref(props.mode ?? 'list')\n\n const currentTrack = computed(() => props.tracks[activeIndex.value])\n\n const progressPercent = computed(() => {\n if (totalDuration.value === 0) return 0\n return (currentTime.value / totalDuration.value) * 100\n })\n\n const volumeIcon = computed(() => {\n if (volume.value === 0) return 'mdi:volume-off'\n if (volume.value < 40) return 'mdi:volume-low'\n if (volume.value < 70) return 'mdi:volume-medium'\n return 'mdi:volume-high'\n })\n\n const currentModeIcon = computed(\n () => MODE_ICON_MAP[playMode.value]?.icon ?? 'mdi:repeat'\n )\n const currentModeLabel = computed(\n () => MODE_ICON_MAP[playMode.value]?.label ?? '循环'\n )\n\n /** 初始化音频实例 */\n function initAudio() {\n if (audio) {\n audio.pause()\n audio.removeEventListener('timeupdate', onTimeUpdate)\n audio.removeEventListener('loadedmetadata', onMetaLoaded)\n audio.removeEventListener('ended', onEnded)\n }\n const track = currentTrack.value\n if (!track) return\n\n audio = new Audio(track.src)\n audio.volume = volume.value / 100\n audio.addEventListener('timeupdate', onTimeUpdate)\n audio.addEventListener('loadedmetadata', onMetaLoaded)\n audio.addEventListener('ended', onEnded)\n }\n\n /** 播放进度更新回调 */\n function onTimeUpdate() {\n if (audio) currentTime.value = audio.currentTime\n }\n\n /** 音频元数据加载完成回调 */\n function onMetaLoaded() {\n if (audio) totalDuration.value = audio.duration\n }\n\n /** 播放结束回调,根据模式决定下一步 */\n function onEnded() {\n emit('ended', activeIndex.value)\n switch (playMode.value) {\n case 'loop':\n audio?.play().catch(() => {})\n break\n case 'single':\n isPlaying.value = false\n break\n case 'shuffle':\n playTrack(Math.floor(Math.random() * props.tracks.length))\n break\n default: // list\n if (activeIndex.value < props.tracks.length - 1) next()\n else {\n activeIndex.value = 0\n initAudio()\n audio?.play().catch(() => {})\n }\n }\n }\n\n /** 切换播放/暂停 */\n function togglePlay() {\n if (!audio) initAudio()\n if (isPlaying.value) {\n audio?.pause()\n isPlaying.value = false\n emit('pause')\n } else {\n audio?.play().catch(() => {})\n isPlaying.value = true\n emit('play', activeIndex.value)\n }\n }\n\n /** 播放指定索引的曲目 */\n function playTrack(idx: number) {\n activeIndex.value = idx\n initAudio()\n audio?.play().catch(() => {})\n isPlaying.value = true\n emit('play', idx)\n }\n\n /** 上一曲 */\n function prev() {\n const idx =\n activeIndex.value <= 0 ? props.tracks.length - 1 : activeIndex.value - 1\n playTrack(idx)\n }\n\n /** 下一曲 */\n function next() {\n const idx =\n activeIndex.value >= props.tracks.length - 1 ? 0 : activeIndex.value + 1\n playTrack(idx)\n }\n\n /** 点击进度条跳转播放位置 */\n function seekByClick(e: MouseEvent) {\n if (!audio || !totalDuration.value) return\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect()\n const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width))\n audio.currentTime = ratio * totalDuration.value\n currentTime.value = audio.currentTime\n }\n\n /** 处理音量变更 */\n function handleVolumeChange(val: number) {\n volume.value = val\n if (audio) audio.volume = val / 100\n }\n\n /** 切换静音状态 */\n function toggleMute() {\n if (volume.value > 0) {\n prevVolume.value = volume.value\n volume.value = 0\n } else {\n volume.value = prevVolume.value || 70\n }\n if (audio) audio.volume = volume.value / 100\n }\n\n const MODES = ['list', 'loop', 'single', 'shuffle'] as const\n /** 循环切换播放模式 */\n function cycleMode() {\n const idx = MODES.indexOf(playMode.value as (typeof MODES)[number])\n playMode.value = MODES[(idx + 1) % MODES.length]\n emit('modeChange', playMode.value)\n }\n\n // ==================== Lifecycle ====================\n\n watch(\n () => props.tracks,\n () => {\n activeIndex.value = 0\n initAudio()\n }\n )\n\n watch(\n () => props.initialIndex,\n val => {\n if (val !== undefined && val !== activeIndex.value) {\n activeIndex.value = val\n initAudio()\n }\n }\n )\n\n onBeforeUnmount(() => {\n if (audio) {\n audio.pause()\n audio.removeEventListener('timeupdate', onTimeUpdate)\n audio.removeEventListener('loadedmetadata', onMetaLoaded)\n audio.removeEventListener('ended', onEnded)\n audio = null\n }\n })\n\n // 自动播放\n if (props.autoplay && props.tracks.length > 0) {\n playTrack(activeIndex.value)\n }\n</script>\n\n<style scoped lang=\"scss\">\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_AvatarGroup-
|
|
1
|
+
{"version":3,"file":"C_AvatarGroup-D02zci-i.css","names":[],"sources":["../src/components/C_AvatarGroup/index.vue?vue&type=style&index=0&scoped=8be58d5b&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//**\n * C_AvatarGroup — 头像组组件样式\n */\n.c-avatar-group[data-v-8be58d5b] {\n display: inline-flex;\n align-items: center;\n /* ======================== 单个头像 ======================== */\n /* ---- 头像图片 ---- */\n /* ---- 首字母 fallback ---- */\n /* ---- 状态指示点 ---- */\n /* ======================== 溢出 +N ======================== */\n}\n.c-avatar-group.is-rtl[data-v-8be58d5b] {\n flex-direction: row-reverse;\n}\n.c-avatar-group__item[data-v-8be58d5b] {\n position: relative;\n flex-shrink: 0;\n border: 2px solid var(--card-color);\n background: var(--card-color);\n transition: transform 0.2s, z-index 0.2s, box-shadow 0.2s;\n cursor: default;\n z-index: 1;\n}\n.c-avatar-group__item.is-circle[data-v-8be58d5b] {\n border-radius: 50%;\n}\n.c-avatar-group__item.is-square[data-v-8be58d5b] {\n border-radius: 6px;\n}\n.c-avatar-group__item.is-clickable[data-v-8be58d5b] {\n cursor: pointer;\n}\n.c-avatar-group__item.is-clickable[data-v-8be58d5b]:hover {\n transform: translateY(-3px) scale(1.08);\n z-index: 10;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n.c-avatar-group__item[data-v-8be58d5b]:hover {\n z-index: 10;\n}\n.c-avatar-group__img[data-v-8be58d5b] {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.is-circle .c-avatar-group__img[data-v-8be58d5b] {\n border-radius: 50%;\n}\n.is-square .c-avatar-group__img[data-v-8be58d5b] {\n border-radius: 4px;\n}\n.c-avatar-group__initials[data-v-8be58d5b] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n color: #fff;\n font-weight: 600;\n user-select: none;\n}\n.is-circle .c-avatar-group__initials[data-v-8be58d5b] {\n border-radius: 50%;\n}\n.is-square .c-avatar-group__initials[data-v-8be58d5b] {\n border-radius: 4px;\n}\n.c-avatar-group__status[data-v-8be58d5b] {\n position: absolute;\n bottom: 0;\n right: 0;\n border-radius: 50%;\n border: 2px solid var(--card-color);\n z-index: 2;\n}\n.c-avatar-group__overflow[data-v-8be58d5b] {\n position: relative;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid var(--card-color);\n background: color-mix(in srgb, var(--primary-color) 12%, var(--card-color));\n color: var(--primary-color);\n font-weight: 700;\n z-index: 0;\n transition: transform 0.2s, box-shadow 0.2s;\n}\n.c-avatar-group__overflow.is-circle[data-v-8be58d5b] {\n border-radius: 50%;\n}\n.c-avatar-group__overflow.is-square[data-v-8be58d5b] {\n border-radius: 6px;\n}\n.c-avatar-group__overflow.is-clickable[data-v-8be58d5b] {\n cursor: pointer;\n}\n.c-avatar-group__overflow.is-clickable[data-v-8be58d5b]:hover {\n transform: translateY(-3px) scale(1.08);\n z-index: 10;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n background: color-mix(in srgb, var(--primary-color) 20%, var(--card-color));\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_AvatarGroup-
|
|
1
|
+
{"version":3,"file":"C_AvatarGroup-DatHaUlY.css","names":[],"sources":["../src/components/C_AvatarGroup/index.vue?vue&type=style&index=0&scoped=8be58d5b&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled *//**\n * C_AvatarGroup — 头像组组件样式\n */\n.c-avatar-group[data-v-8be58d5b] {\n display: inline-flex;\n align-items: center;\n /* ======================== 单个头像 ======================== */\n /* ---- 头像图片 ---- */\n /* ---- 首字母 fallback ---- */\n /* ---- 状态指示点 ---- */\n /* ======================== 溢出 +N ======================== */\n}\n.c-avatar-group.is-rtl[data-v-8be58d5b] {\n flex-direction: row-reverse;\n}\n.c-avatar-group__item[data-v-8be58d5b] {\n position: relative;\n flex-shrink: 0;\n border: 2px solid var(--card-color);\n background: var(--card-color);\n transition: transform 0.2s, z-index 0.2s, box-shadow 0.2s;\n cursor: default;\n z-index: 1;\n}\n.c-avatar-group__item.is-circle[data-v-8be58d5b] {\n border-radius: 50%;\n}\n.c-avatar-group__item.is-square[data-v-8be58d5b] {\n border-radius: 6px;\n}\n.c-avatar-group__item.is-clickable[data-v-8be58d5b] {\n cursor: pointer;\n}\n.c-avatar-group__item.is-clickable[data-v-8be58d5b]:hover {\n transform: translateY(-3px) scale(1.08);\n z-index: 10;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n.c-avatar-group__item[data-v-8be58d5b]:hover {\n z-index: 10;\n}\n.c-avatar-group__img[data-v-8be58d5b] {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n.is-circle .c-avatar-group__img[data-v-8be58d5b] {\n border-radius: 50%;\n}\n.is-square .c-avatar-group__img[data-v-8be58d5b] {\n border-radius: 4px;\n}\n.c-avatar-group__initials[data-v-8be58d5b] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n color: #fff;\n font-weight: 600;\n user-select: none;\n}\n.is-circle .c-avatar-group__initials[data-v-8be58d5b] {\n border-radius: 50%;\n}\n.is-square .c-avatar-group__initials[data-v-8be58d5b] {\n border-radius: 4px;\n}\n.c-avatar-group__status[data-v-8be58d5b] {\n position: absolute;\n bottom: 0;\n right: 0;\n border-radius: 50%;\n border: 2px solid var(--card-color);\n z-index: 2;\n}\n.c-avatar-group__overflow[data-v-8be58d5b] {\n position: relative;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border: 2px solid var(--card-color);\n background: color-mix(in srgb, var(--primary-color) 12%, var(--card-color));\n color: var(--primary-color);\n font-weight: 700;\n z-index: 0;\n transition: transform 0.2s, box-shadow 0.2s;\n}\n.c-avatar-group__overflow.is-circle[data-v-8be58d5b] {\n border-radius: 50%;\n}\n.c-avatar-group__overflow.is-square[data-v-8be58d5b] {\n border-radius: 6px;\n}\n.c-avatar-group__overflow.is-clickable[data-v-8be58d5b] {\n cursor: pointer;\n}\n.c-avatar-group__overflow.is-clickable[data-v-8be58d5b]:hover {\n transform: translateY(-3px) scale(1.08);\n z-index: 10;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n background: color-mix(in srgb, var(--primary-color) 20%, var(--card-color));\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
package/dist/C_AvatarGroup.css
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* unplugin-vue-components disabled *//**
|
|
2
2
|
* C_AvatarGroup — 头像组组件样式
|
|
3
3
|
*/
|
|
4
|
-
.c-avatar-group[data-v-
|
|
4
|
+
.c-avatar-group[data-v-8be58d5b] {
|
|
5
5
|
display: inline-flex;
|
|
6
6
|
align-items: center;
|
|
7
7
|
/* ======================== 单个头像 ======================== */
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
/* ---- 状态指示点 ---- */
|
|
11
11
|
/* ======================== 溢出 +N ======================== */
|
|
12
12
|
}
|
|
13
|
-
.c-avatar-group.is-rtl[data-v-
|
|
13
|
+
.c-avatar-group.is-rtl[data-v-8be58d5b] {
|
|
14
14
|
flex-direction: row-reverse;
|
|
15
15
|
}
|
|
16
|
-
.c-avatar-group__item[data-v-
|
|
16
|
+
.c-avatar-group__item[data-v-8be58d5b] {
|
|
17
17
|
position: relative;
|
|
18
18
|
flex-shrink: 0;
|
|
19
19
|
border: 2px solid var(--card-color);
|
|
@@ -22,36 +22,36 @@
|
|
|
22
22
|
cursor: default;
|
|
23
23
|
z-index: 1;
|
|
24
24
|
}
|
|
25
|
-
.c-avatar-group__item.is-circle[data-v-
|
|
25
|
+
.c-avatar-group__item.is-circle[data-v-8be58d5b] {
|
|
26
26
|
border-radius: 50%;
|
|
27
27
|
}
|
|
28
|
-
.c-avatar-group__item.is-square[data-v-
|
|
28
|
+
.c-avatar-group__item.is-square[data-v-8be58d5b] {
|
|
29
29
|
border-radius: 6px;
|
|
30
30
|
}
|
|
31
|
-
.c-avatar-group__item.is-clickable[data-v-
|
|
31
|
+
.c-avatar-group__item.is-clickable[data-v-8be58d5b] {
|
|
32
32
|
cursor: pointer;
|
|
33
33
|
}
|
|
34
|
-
.c-avatar-group__item.is-clickable[data-v-
|
|
34
|
+
.c-avatar-group__item.is-clickable[data-v-8be58d5b]:hover {
|
|
35
35
|
transform: translateY(-3px) scale(1.08);
|
|
36
36
|
z-index: 10;
|
|
37
37
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
38
38
|
}
|
|
39
|
-
.c-avatar-group__item[data-v-
|
|
39
|
+
.c-avatar-group__item[data-v-8be58d5b]:hover {
|
|
40
40
|
z-index: 10;
|
|
41
41
|
}
|
|
42
|
-
.c-avatar-group__img[data-v-
|
|
42
|
+
.c-avatar-group__img[data-v-8be58d5b] {
|
|
43
43
|
display: block;
|
|
44
44
|
width: 100%;
|
|
45
45
|
height: 100%;
|
|
46
46
|
object-fit: cover;
|
|
47
47
|
}
|
|
48
|
-
.is-circle .c-avatar-group__img[data-v-
|
|
48
|
+
.is-circle .c-avatar-group__img[data-v-8be58d5b] {
|
|
49
49
|
border-radius: 50%;
|
|
50
50
|
}
|
|
51
|
-
.is-square .c-avatar-group__img[data-v-
|
|
51
|
+
.is-square .c-avatar-group__img[data-v-8be58d5b] {
|
|
52
52
|
border-radius: 4px;
|
|
53
53
|
}
|
|
54
|
-
.c-avatar-group__initials[data-v-
|
|
54
|
+
.c-avatar-group__initials[data-v-8be58d5b] {
|
|
55
55
|
display: flex;
|
|
56
56
|
align-items: center;
|
|
57
57
|
justify-content: center;
|
|
@@ -61,13 +61,13 @@
|
|
|
61
61
|
font-weight: 600;
|
|
62
62
|
user-select: none;
|
|
63
63
|
}
|
|
64
|
-
.is-circle .c-avatar-group__initials[data-v-
|
|
64
|
+
.is-circle .c-avatar-group__initials[data-v-8be58d5b] {
|
|
65
65
|
border-radius: 50%;
|
|
66
66
|
}
|
|
67
|
-
.is-square .c-avatar-group__initials[data-v-
|
|
67
|
+
.is-square .c-avatar-group__initials[data-v-8be58d5b] {
|
|
68
68
|
border-radius: 4px;
|
|
69
69
|
}
|
|
70
|
-
.c-avatar-group__status[data-v-
|
|
70
|
+
.c-avatar-group__status[data-v-8be58d5b] {
|
|
71
71
|
position: absolute;
|
|
72
72
|
bottom: 0;
|
|
73
73
|
right: 0;
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
border: 2px solid var(--card-color);
|
|
76
76
|
z-index: 2;
|
|
77
77
|
}
|
|
78
|
-
.c-avatar-group__overflow[data-v-
|
|
78
|
+
.c-avatar-group__overflow[data-v-8be58d5b] {
|
|
79
79
|
position: relative;
|
|
80
80
|
flex-shrink: 0;
|
|
81
81
|
display: flex;
|
|
@@ -88,20 +88,20 @@
|
|
|
88
88
|
z-index: 0;
|
|
89
89
|
transition: transform 0.2s, box-shadow 0.2s;
|
|
90
90
|
}
|
|
91
|
-
.c-avatar-group__overflow.is-circle[data-v-
|
|
91
|
+
.c-avatar-group__overflow.is-circle[data-v-8be58d5b] {
|
|
92
92
|
border-radius: 50%;
|
|
93
93
|
}
|
|
94
|
-
.c-avatar-group__overflow.is-square[data-v-
|
|
94
|
+
.c-avatar-group__overflow.is-square[data-v-8be58d5b] {
|
|
95
95
|
border-radius: 6px;
|
|
96
96
|
}
|
|
97
|
-
.c-avatar-group__overflow.is-clickable[data-v-
|
|
97
|
+
.c-avatar-group__overflow.is-clickable[data-v-8be58d5b] {
|
|
98
98
|
cursor: pointer;
|
|
99
99
|
}
|
|
100
|
-
.c-avatar-group__overflow.is-clickable[data-v-
|
|
100
|
+
.c-avatar-group__overflow.is-clickable[data-v-8be58d5b]:hover {
|
|
101
101
|
transform: translateY(-3px) scale(1.08);
|
|
102
102
|
z-index: 10;
|
|
103
103
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
104
104
|
background: color-mix(in srgb, var(--primary-color) 20%, var(--card-color));
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
/*# sourceMappingURL=C_AvatarGroup-
|
|
107
|
+
/*# sourceMappingURL=C_AvatarGroup-D02zci-i.css.map*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_AvatarGroup.js","names":[],"sources":["../src/components/C_AvatarGroup/types.ts","../src/components/C_AvatarGroup/index.vue","../src/components/C_AvatarGroup/index.vue","../src/components/C_AvatarGroup/index.vue"],"sourcesContent":["/**\r\n * @Description: 头像组组件类型定义\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n */\r\n\r\n/** 单个头像数据 */\r\nexport interface AvatarItem {\r\n /** 唯一标识 */\r\n id: string | number\r\n /** 头像图片 URL */\r\n src?: string\r\n /** 姓名(用于首字母 fallback 和 tooltip) */\r\n name: string\r\n /** 悬浮提示(默认取 name) */\r\n tooltip?: string\r\n /** 在线状态 */\r\n status?: 'online' | 'offline' | 'busy' | 'away'\r\n /** 额外数据 */\r\n extra?: Record<string, unknown>\r\n}\r\n\r\n/** 组件 Props */\r\nexport interface AvatarGroupProps {\r\n /** 头像数据列表 */\r\n items: AvatarItem[]\r\n /** 最多显示数量(超出 +N) */\r\n max?: number\r\n /** 头像尺寸 (px) */\r\n size?: number\r\n /** 头像间重叠偏移量 (px),负值表示堆叠 */\r\n overlap?: number\r\n /** 形状 */\r\n shape?: 'circle' | 'square'\r\n /** 是否显示状态指示点 */\r\n showStatus?: boolean\r\n /** 是否显示悬浮提示 */\r\n showTooltip?: boolean\r\n /** 是否可点击 */\r\n clickable?: boolean\r\n /** +N 溢出按钮是否可点击 */\r\n overflowClickable?: boolean\r\n /** 堆叠方向 */\r\n direction?: 'ltr' | 'rtl'\r\n}\r\n\r\n/** 默认 Props */\r\nexport const DEFAULT_AVATAR_GROUP_PROPS: Partial<AvatarGroupProps> = {\r\n max: 5,\r\n size: 40,\r\n overlap: -10,\r\n shape: 'circle',\r\n showStatus: true,\r\n showTooltip: true,\r\n clickable: false,\r\n overflowClickable: true,\r\n direction: 'ltr',\r\n}\r\n\r\n/** 状态颜色映射 */\r\nexport const STATUS_COLOR_MAP: Record<string, string> = {\r\n online: '#18a058',\r\n offline: '#909399',\r\n busy: '#e53e3e',\r\n away: '#f0a020',\r\n}\r\n\r\n/** 从名字中提取首字母 */\r\nexport function getInitials(name: string): string {\r\n if (!name) return '?'\r\n const parts = name.trim().split(/\\s+/)\r\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase()\r\n // 中文直接取最后一个字\r\n if (/[\\u4E00-\\u9FFF]/.test(name)) return name.slice(-1)\r\n return name.slice(0, 2).toUpperCase()\r\n}\r\n\r\n/** 根据名字生成稳定的背景色 */\r\nexport function nameToColor(name: string): string {\r\n const palette = [\r\n '#6366f1',\r\n '#8b5cf6',\r\n '#a855f7',\r\n '#d946ef',\r\n '#ec4899',\r\n '#f43f5e',\r\n '#ef4444',\r\n '#f97316',\r\n '#eab308',\r\n '#84cc16',\r\n '#22c55e',\r\n '#14b8a6',\r\n '#06b6d4',\r\n '#0ea5e9',\r\n '#3b82f6',\r\n '#6d28d9',\r\n ]\r\n let hash = 0\r\n for (let i = 0; i < name.length; i++) {\r\n hash = name.charCodeAt(i) + ((hash * 31) | 0)\r\n }\r\n return palette[Math.abs(hash) % palette.length]\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 头像组组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-avatar-group\"\r\n :class=\"{ 'is-rtl': mergedProps.direction === 'rtl' }\"\r\n >\r\n <NTooltip\r\n v-for=\"(item, idx) in visibleItems\"\r\n :key=\"item.id\"\r\n :disabled=\"!mergedProps.showTooltip\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__item\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.clickable },\r\n ]\"\r\n :style=\"itemStyle(idx)\"\r\n @click=\"mergedProps.clickable && emit('itemClick', item)\"\r\n >\r\n <img\r\n v-if=\"item.src\"\r\n :src=\"item.src\"\r\n :alt=\"item.name\"\r\n class=\"c-avatar-group__img\"\r\n />\r\n <div\r\n v-else\r\n class=\"c-avatar-group__initials\"\r\n :style=\"{\r\n background: nameToColor(item.name),\r\n fontSize: initialsFontSize,\r\n }\"\r\n >\r\n {{ getInitials(item.name) }}\r\n </div>\r\n\r\n <span\r\n v-if=\"mergedProps.showStatus && item.status\"\r\n class=\"c-avatar-group__status\"\r\n :style=\"statusStyle(item.status)\"\r\n />\r\n </div>\r\n </template>\r\n {{ item.tooltip ?? item.name }}\r\n </NTooltip>\r\n\r\n <!-- 溢出 +N -->\r\n <NTooltip\r\n v-if=\"overflowCount > 0\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__overflow\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.overflowClickable },\r\n ]\"\r\n :style=\"overflowStyle\"\r\n @click=\"\r\n mergedProps.overflowClickable && emit('overflowClick', hiddenItems)\r\n \"\r\n >\r\n +{{ overflowCount }}\r\n </div>\r\n </template>\r\n <div style=\"max-width: 200px\">\r\n <div\r\n v-for=\"h in hiddenItems\"\r\n :key=\"h.id\"\r\n style=\"line-height: 1.6\"\r\n >\r\n {{ h.name }}\r\n </div>\r\n </div>\r\n </NTooltip>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed } from 'vue'\r\n import {\r\n DEFAULT_AVATAR_GROUP_PROPS,\r\n getInitials,\r\n nameToColor,\r\n STATUS_COLOR_MAP,\r\n type AvatarGroupProps,\r\n type AvatarItem,\r\n } from './types'\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n items: AvatarGroupProps['items']\r\n max?: number\r\n size?: number\r\n overlap?: number\r\n shape?: AvatarGroupProps['shape']\r\n showStatus?: boolean\r\n showTooltip?: boolean\r\n clickable?: boolean\r\n overflowClickable?: boolean\r\n direction?: AvatarGroupProps['direction']\r\n }>(),\r\n {\r\n max: DEFAULT_AVATAR_GROUP_PROPS.max,\r\n size: DEFAULT_AVATAR_GROUP_PROPS.size,\r\n overlap: DEFAULT_AVATAR_GROUP_PROPS.overlap,\r\n shape: DEFAULT_AVATAR_GROUP_PROPS.shape,\r\n showStatus: DEFAULT_AVATAR_GROUP_PROPS.showStatus,\r\n showTooltip: DEFAULT_AVATAR_GROUP_PROPS.showTooltip,\r\n clickable: DEFAULT_AVATAR_GROUP_PROPS.clickable,\r\n overflowClickable: DEFAULT_AVATAR_GROUP_PROPS.overflowClickable,\r\n direction: DEFAULT_AVATAR_GROUP_PROPS.direction,\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n itemClick: [item: AvatarItem]\r\n overflowClick: [hiddenItems: AvatarItem[]]\r\n }>()\r\n\r\n const mergedProps = computed(() => ({\r\n ...DEFAULT_AVATAR_GROUP_PROPS,\r\n ...props,\r\n }))\r\n\r\n const visibleItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(0, max) : props.items\r\n })\r\n\r\n const hiddenItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(max) : []\r\n })\r\n\r\n const overflowCount = computed(() => hiddenItems.value.length)\r\n\r\n const initialsFontSize = computed(\r\n () => `${Math.round(mergedProps.value.size! * 0.38)}px`\r\n )\r\n\r\n /** 计算头像项定位样式 */\r\n function itemStyle(idx: number) {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: idx === 0 ? '0' : `${overlap}px`,\r\n }\r\n }\r\n\r\n const overflowStyle = computed(() => {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: `${overlap}px`,\r\n fontSize: `${Math.round(s * 0.32)}px`,\r\n }\r\n })\r\n\r\n /** 计算状态指示点样式 */\r\n function statusStyle(status: string) {\r\n const dotSize = Math.max(8, Math.round(mergedProps.value.size! * 0.24))\r\n return {\r\n width: `${dotSize}px`,\r\n height: `${dotSize}px`,\r\n backgroundColor: STATUS_COLOR_MAP[status] ?? STATUS_COLOR_MAP.offline,\r\n }\r\n }\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 头像组组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-avatar-group\"\r\n :class=\"{ 'is-rtl': mergedProps.direction === 'rtl' }\"\r\n >\r\n <NTooltip\r\n v-for=\"(item, idx) in visibleItems\"\r\n :key=\"item.id\"\r\n :disabled=\"!mergedProps.showTooltip\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__item\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.clickable },\r\n ]\"\r\n :style=\"itemStyle(idx)\"\r\n @click=\"mergedProps.clickable && emit('itemClick', item)\"\r\n >\r\n <img\r\n v-if=\"item.src\"\r\n :src=\"item.src\"\r\n :alt=\"item.name\"\r\n class=\"c-avatar-group__img\"\r\n />\r\n <div\r\n v-else\r\n class=\"c-avatar-group__initials\"\r\n :style=\"{\r\n background: nameToColor(item.name),\r\n fontSize: initialsFontSize,\r\n }\"\r\n >\r\n {{ getInitials(item.name) }}\r\n </div>\r\n\r\n <span\r\n v-if=\"mergedProps.showStatus && item.status\"\r\n class=\"c-avatar-group__status\"\r\n :style=\"statusStyle(item.status)\"\r\n />\r\n </div>\r\n </template>\r\n {{ item.tooltip ?? item.name }}\r\n </NTooltip>\r\n\r\n <!-- 溢出 +N -->\r\n <NTooltip\r\n v-if=\"overflowCount > 0\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__overflow\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.overflowClickable },\r\n ]\"\r\n :style=\"overflowStyle\"\r\n @click=\"\r\n mergedProps.overflowClickable && emit('overflowClick', hiddenItems)\r\n \"\r\n >\r\n +{{ overflowCount }}\r\n </div>\r\n </template>\r\n <div style=\"max-width: 200px\">\r\n <div\r\n v-for=\"h in hiddenItems\"\r\n :key=\"h.id\"\r\n style=\"line-height: 1.6\"\r\n >\r\n {{ h.name }}\r\n </div>\r\n </div>\r\n </NTooltip>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed } from 'vue'\r\n import {\r\n DEFAULT_AVATAR_GROUP_PROPS,\r\n getInitials,\r\n nameToColor,\r\n STATUS_COLOR_MAP,\r\n type AvatarGroupProps,\r\n type AvatarItem,\r\n } from './types'\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n items: AvatarGroupProps['items']\r\n max?: number\r\n size?: number\r\n overlap?: number\r\n shape?: AvatarGroupProps['shape']\r\n showStatus?: boolean\r\n showTooltip?: boolean\r\n clickable?: boolean\r\n overflowClickable?: boolean\r\n direction?: AvatarGroupProps['direction']\r\n }>(),\r\n {\r\n max: DEFAULT_AVATAR_GROUP_PROPS.max,\r\n size: DEFAULT_AVATAR_GROUP_PROPS.size,\r\n overlap: DEFAULT_AVATAR_GROUP_PROPS.overlap,\r\n shape: DEFAULT_AVATAR_GROUP_PROPS.shape,\r\n showStatus: DEFAULT_AVATAR_GROUP_PROPS.showStatus,\r\n showTooltip: DEFAULT_AVATAR_GROUP_PROPS.showTooltip,\r\n clickable: DEFAULT_AVATAR_GROUP_PROPS.clickable,\r\n overflowClickable: DEFAULT_AVATAR_GROUP_PROPS.overflowClickable,\r\n direction: DEFAULT_AVATAR_GROUP_PROPS.direction,\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n itemClick: [item: AvatarItem]\r\n overflowClick: [hiddenItems: AvatarItem[]]\r\n }>()\r\n\r\n const mergedProps = computed(() => ({\r\n ...DEFAULT_AVATAR_GROUP_PROPS,\r\n ...props,\r\n }))\r\n\r\n const visibleItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(0, max) : props.items\r\n })\r\n\r\n const hiddenItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(max) : []\r\n })\r\n\r\n const overflowCount = computed(() => hiddenItems.value.length)\r\n\r\n const initialsFontSize = computed(\r\n () => `${Math.round(mergedProps.value.size! * 0.38)}px`\r\n )\r\n\r\n /** 计算头像项定位样式 */\r\n function itemStyle(idx: number) {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: idx === 0 ? '0' : `${overlap}px`,\r\n }\r\n }\r\n\r\n const overflowStyle = computed(() => {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: `${overlap}px`,\r\n fontSize: `${Math.round(s * 0.32)}px`,\r\n }\r\n })\r\n\r\n /** 计算状态指示点样式 */\r\n function statusStyle(status: string) {\r\n const dotSize = Math.max(8, Math.round(mergedProps.value.size! * 0.24))\r\n return {\r\n width: `${dotSize}px`,\r\n height: `${dotSize}px`,\r\n backgroundColor: STATUS_COLOR_MAP[status] ?? STATUS_COLOR_MAP.offline,\r\n }\r\n }\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Description: 头像组组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-avatar-group\"\r\n :class=\"{ 'is-rtl': mergedProps.direction === 'rtl' }\"\r\n >\r\n <NTooltip\r\n v-for=\"(item, idx) in visibleItems\"\r\n :key=\"item.id\"\r\n :disabled=\"!mergedProps.showTooltip\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__item\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.clickable },\r\n ]\"\r\n :style=\"itemStyle(idx)\"\r\n @click=\"mergedProps.clickable && emit('itemClick', item)\"\r\n >\r\n <img\r\n v-if=\"item.src\"\r\n :src=\"item.src\"\r\n :alt=\"item.name\"\r\n class=\"c-avatar-group__img\"\r\n />\r\n <div\r\n v-else\r\n class=\"c-avatar-group__initials\"\r\n :style=\"{\r\n background: nameToColor(item.name),\r\n fontSize: initialsFontSize,\r\n }\"\r\n >\r\n {{ getInitials(item.name) }}\r\n </div>\r\n\r\n <span\r\n v-if=\"mergedProps.showStatus && item.status\"\r\n class=\"c-avatar-group__status\"\r\n :style=\"statusStyle(item.status)\"\r\n />\r\n </div>\r\n </template>\r\n {{ item.tooltip ?? item.name }}\r\n </NTooltip>\r\n\r\n <!-- 溢出 +N -->\r\n <NTooltip\r\n v-if=\"overflowCount > 0\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__overflow\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.overflowClickable },\r\n ]\"\r\n :style=\"overflowStyle\"\r\n @click=\"\r\n mergedProps.overflowClickable && emit('overflowClick', hiddenItems)\r\n \"\r\n >\r\n +{{ overflowCount }}\r\n </div>\r\n </template>\r\n <div style=\"max-width: 200px\">\r\n <div\r\n v-for=\"h in hiddenItems\"\r\n :key=\"h.id\"\r\n style=\"line-height: 1.6\"\r\n >\r\n {{ h.name }}\r\n </div>\r\n </div>\r\n </NTooltip>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed } from 'vue'\r\n import {\r\n DEFAULT_AVATAR_GROUP_PROPS,\r\n getInitials,\r\n nameToColor,\r\n STATUS_COLOR_MAP,\r\n type AvatarGroupProps,\r\n type AvatarItem,\r\n } from './types'\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n items: AvatarGroupProps['items']\r\n max?: number\r\n size?: number\r\n overlap?: number\r\n shape?: AvatarGroupProps['shape']\r\n showStatus?: boolean\r\n showTooltip?: boolean\r\n clickable?: boolean\r\n overflowClickable?: boolean\r\n direction?: AvatarGroupProps['direction']\r\n }>(),\r\n {\r\n max: DEFAULT_AVATAR_GROUP_PROPS.max,\r\n size: DEFAULT_AVATAR_GROUP_PROPS.size,\r\n overlap: DEFAULT_AVATAR_GROUP_PROPS.overlap,\r\n shape: DEFAULT_AVATAR_GROUP_PROPS.shape,\r\n showStatus: DEFAULT_AVATAR_GROUP_PROPS.showStatus,\r\n showTooltip: DEFAULT_AVATAR_GROUP_PROPS.showTooltip,\r\n clickable: DEFAULT_AVATAR_GROUP_PROPS.clickable,\r\n overflowClickable: DEFAULT_AVATAR_GROUP_PROPS.overflowClickable,\r\n direction: DEFAULT_AVATAR_GROUP_PROPS.direction,\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n itemClick: [item: AvatarItem]\r\n overflowClick: [hiddenItems: AvatarItem[]]\r\n }>()\r\n\r\n const mergedProps = computed(() => ({\r\n ...DEFAULT_AVATAR_GROUP_PROPS,\r\n ...props,\r\n }))\r\n\r\n const visibleItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(0, max) : props.items\r\n })\r\n\r\n const hiddenItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(max) : []\r\n })\r\n\r\n const overflowCount = computed(() => hiddenItems.value.length)\r\n\r\n const initialsFontSize = computed(\r\n () => `${Math.round(mergedProps.value.size! * 0.38)}px`\r\n )\r\n\r\n /** 计算头像项定位样式 */\r\n function itemStyle(idx: number) {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: idx === 0 ? '0' : `${overlap}px`,\r\n }\r\n }\r\n\r\n const overflowStyle = computed(() => {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: `${overlap}px`,\r\n fontSize: `${Math.round(s * 0.32)}px`,\r\n }\r\n })\r\n\r\n /** 计算状态指示点样式 */\r\n function statusStyle(status: string) {\r\n const dotSize = Math.max(8, Math.round(mergedProps.value.size! * 0.24))\r\n return {\r\n width: `${dotSize}px`,\r\n height: `${dotSize}px`,\r\n backgroundColor: STATUS_COLOR_MAP[status] ?? STATUS_COLOR_MAP.offline,\r\n }\r\n }\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_AvatarGroup.js","names":[],"sources":["../src/components/C_AvatarGroup/types.ts","../src/components/C_AvatarGroup/index.vue"],"sourcesContent":["/**\n * @Description: 头像组组件类型定义\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n */\n\n/** 单个头像数据 */\nexport interface AvatarItem {\n /** 唯一标识 */\n id: string | number\n /** 头像图片 URL */\n src?: string\n /** 姓名(用于首字母 fallback 和 tooltip) */\n name: string\n /** 悬浮提示(默认取 name) */\n tooltip?: string\n /** 在线状态 */\n status?: 'online' | 'offline' | 'busy' | 'away'\n /** 额外数据 */\n extra?: Record<string, unknown>\n}\n\n/** 组件 Props */\nexport interface AvatarGroupProps {\n /** 头像数据列表 */\n items: AvatarItem[]\n /** 最多显示数量(超出 +N) */\n max?: number\n /** 头像尺寸 (px) */\n size?: number\n /** 头像间重叠偏移量 (px),负值表示堆叠 */\n overlap?: number\n /** 形状 */\n shape?: 'circle' | 'square'\n /** 是否显示状态指示点 */\n showStatus?: boolean\n /** 是否显示悬浮提示 */\n showTooltip?: boolean\n /** 是否可点击 */\n clickable?: boolean\n /** +N 溢出按钮是否可点击 */\n overflowClickable?: boolean\n /** 堆叠方向 */\n direction?: 'ltr' | 'rtl'\n}\n\n/** 默认 Props */\nexport const DEFAULT_AVATAR_GROUP_PROPS: Partial<AvatarGroupProps> = {\n max: 5,\n size: 40,\n overlap: -10,\n shape: 'circle',\n showStatus: true,\n showTooltip: true,\n clickable: false,\n overflowClickable: true,\n direction: 'ltr',\n}\n\n/** 状态颜色映射 */\nexport const STATUS_COLOR_MAP: Record<string, string> = {\n online: '#18a058',\n offline: '#909399',\n busy: '#e53e3e',\n away: '#f0a020',\n}\n\n/** 从名字中提取首字母 */\nexport function getInitials(name: string): string {\n if (!name) return '?'\n const parts = name.trim().split(/\\s+/)\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase()\n // 中文直接取最后一个字\n if (/[\\u4E00-\\u9FFF]/.test(name)) return name.slice(-1)\n return name.slice(0, 2).toUpperCase()\n}\n\n/** 根据名字生成稳定的背景色 */\nexport function nameToColor(name: string): string {\n const palette = [\n '#6366f1',\n '#8b5cf6',\n '#a855f7',\n '#d946ef',\n '#ec4899',\n '#f43f5e',\n '#ef4444',\n '#f97316',\n '#eab308',\n '#84cc16',\n '#22c55e',\n '#14b8a6',\n '#06b6d4',\n '#0ea5e9',\n '#3b82f6',\n '#6d28d9',\n ]\n let hash = 0\n for (let i = 0; i < name.length; i++) {\n hash = name.charCodeAt(i) + ((hash * 31) | 0)\n }\n return palette[Math.abs(hash) % palette.length]\n}\n","<!--\n * @Description: 头像组组件\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n class=\"c-avatar-group\"\n :class=\"{ 'is-rtl': mergedProps.direction === 'rtl' }\"\n >\n <NTooltip\n v-for=\"(item, idx) in visibleItems\"\n :key=\"item.id\"\n :disabled=\"!mergedProps.showTooltip\"\n placement=\"top\"\n >\n <template #trigger>\n <div\n class=\"c-avatar-group__item\"\n :class=\"[\n `is-${mergedProps.shape}`,\n { 'is-clickable': mergedProps.clickable },\n ]\"\n :style=\"itemStyle(idx)\"\n @click=\"mergedProps.clickable && emit('itemClick', item)\"\n >\n <img\n v-if=\"item.src\"\n :src=\"item.src\"\n :alt=\"item.name\"\n class=\"c-avatar-group__img\"\n />\n <div\n v-else\n class=\"c-avatar-group__initials\"\n :style=\"{\n background: nameToColor(item.name),\n fontSize: initialsFontSize,\n }\"\n >\n {{ getInitials(item.name) }}\n </div>\n\n <span\n v-if=\"mergedProps.showStatus && item.status\"\n class=\"c-avatar-group__status\"\n :style=\"statusStyle(item.status)\"\n />\n </div>\n </template>\n {{ item.tooltip ?? item.name }}\n </NTooltip>\n\n <!-- 溢出 +N -->\n <NTooltip\n v-if=\"overflowCount > 0\"\n placement=\"top\"\n >\n <template #trigger>\n <div\n class=\"c-avatar-group__overflow\"\n :class=\"[\n `is-${mergedProps.shape}`,\n { 'is-clickable': mergedProps.overflowClickable },\n ]\"\n :style=\"overflowStyle\"\n @click=\"\n mergedProps.overflowClickable && emit('overflowClick', hiddenItems)\n \"\n >\n +{{ overflowCount }}\n </div>\n </template>\n <div style=\"max-width: 200px\">\n <div\n v-for=\"h in hiddenItems\"\n :key=\"h.id\"\n style=\"line-height: 1.6\"\n >\n {{ h.name }}\n </div>\n </div>\n </NTooltip>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import {\n DEFAULT_AVATAR_GROUP_PROPS,\n getInitials,\n nameToColor,\n STATUS_COLOR_MAP,\n type AvatarGroupProps,\n type AvatarItem,\n } from './types'\n\n const props = withDefaults(\n defineProps<{\n items: AvatarGroupProps['items']\n max?: number\n size?: number\n overlap?: number\n shape?: AvatarGroupProps['shape']\n showStatus?: boolean\n showTooltip?: boolean\n clickable?: boolean\n overflowClickable?: boolean\n direction?: AvatarGroupProps['direction']\n }>(),\n {\n max: DEFAULT_AVATAR_GROUP_PROPS.max,\n size: DEFAULT_AVATAR_GROUP_PROPS.size,\n overlap: DEFAULT_AVATAR_GROUP_PROPS.overlap,\n shape: DEFAULT_AVATAR_GROUP_PROPS.shape,\n showStatus: DEFAULT_AVATAR_GROUP_PROPS.showStatus,\n showTooltip: DEFAULT_AVATAR_GROUP_PROPS.showTooltip,\n clickable: DEFAULT_AVATAR_GROUP_PROPS.clickable,\n overflowClickable: DEFAULT_AVATAR_GROUP_PROPS.overflowClickable,\n direction: DEFAULT_AVATAR_GROUP_PROPS.direction,\n }\n )\n\n const emit = defineEmits<{\n itemClick: [item: AvatarItem]\n overflowClick: [hiddenItems: AvatarItem[]]\n }>()\n\n const mergedProps = computed(() => ({\n ...DEFAULT_AVATAR_GROUP_PROPS,\n ...props,\n }))\n\n const visibleItems = computed(() => {\n const max = mergedProps.value.max!\n return props.items.length > max ? props.items.slice(0, max) : props.items\n })\n\n const hiddenItems = computed(() => {\n const max = mergedProps.value.max!\n return props.items.length > max ? props.items.slice(max) : []\n })\n\n const overflowCount = computed(() => hiddenItems.value.length)\n\n const initialsFontSize = computed(\n () => `${Math.round(mergedProps.value.size! * 0.38)}px`\n )\n\n /** 计算头像项定位样式 */\n function itemStyle(idx: number) {\n const s = mergedProps.value.size!\n const overlap = mergedProps.value.overlap!\n return {\n width: `${s}px`,\n height: `${s}px`,\n marginLeft: idx === 0 ? '0' : `${overlap}px`,\n }\n }\n\n const overflowStyle = computed(() => {\n const s = mergedProps.value.size!\n const overlap = mergedProps.value.overlap!\n return {\n width: `${s}px`,\n height: `${s}px`,\n marginLeft: `${overlap}px`,\n fontSize: `${Math.round(s * 0.32)}px`,\n }\n })\n\n /** 计算状态指示点样式 */\n function statusStyle(status: string) {\n const dotSize = Math.max(8, Math.round(mergedProps.value.size! * 0.24))\n return {\n width: `${dotSize}px`,\n height: `${dotSize}px`,\n backgroundColor: STATUS_COLOR_MAP[status] ?? STATUS_COLOR_MAP.offline,\n }\n }\n</script>\n\n<style scoped lang=\"scss\">\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|
package/dist/C_AvatarGroup2.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"./export-helper.js";import{
|
|
1
|
+
import{t as e}from"./export-helper.js";import{Fragment as t,computed as n,createBlock as r,createCommentVNode as i,createElementBlock as a,createElementVNode as o,createTextVNode as s,defineComponent as c,normalizeClass as l,normalizeStyle as u,openBlock as d,renderList as f,resolveComponent as p,toDisplayString as m,unref as h,withCtx as g}from"vue";const _={max:5,size:40,overlap:-10,shape:`circle`,showStatus:!0,showTooltip:!0,clickable:!1,overflowClickable:!0,direction:`ltr`},v={online:`#18a058`,offline:`#909399`,busy:`#e53e3e`,away:`#f0a020`};function y(e){if(!e)return`?`;let t=e.trim().split(/\s+/);return t.length>=2?(t[0][0]+t[1][0]).toUpperCase():/[\u4E00-\u9FFF]/.test(e)?e.slice(-1):e.slice(0,2).toUpperCase()}function b(e){let t=[`#6366f1`,`#8b5cf6`,`#a855f7`,`#d946ef`,`#ec4899`,`#f43f5e`,`#ef4444`,`#f97316`,`#eab308`,`#84cc16`,`#22c55e`,`#14b8a6`,`#06b6d4`,`#0ea5e9`,`#3b82f6`,`#6d28d9`],n=0;for(let t=0;t<e.length;t++)n=e.charCodeAt(t)+(n*31|0);return t[Math.abs(n)%t.length]}const x=[`onClick`],S=[`src`,`alt`],C={style:{"max-width":`200px`}};var w=e(c({__name:`index`,props:{items:{},max:{default:_.max},size:{default:_.size},overlap:{default:_.overlap},shape:{default:_.shape},showStatus:{type:Boolean,default:_.showStatus},showTooltip:{type:Boolean,default:_.showTooltip},clickable:{type:Boolean,default:_.clickable},overflowClickable:{type:Boolean,default:_.overflowClickable},direction:{default:_.direction}},emits:[`itemClick`,`overflowClick`],setup(e,{emit:c}){let w=e,T=c,E=n(()=>({..._,...w})),D=n(()=>{let e=E.value.max;return w.items.length>e?w.items.slice(0,e):w.items}),O=n(()=>{let e=E.value.max;return w.items.length>e?w.items.slice(e):[]}),k=n(()=>O.value.length),A=n(()=>`${Math.round(E.value.size*.38)}px`);function j(e){let t=E.value.size,n=E.value.overlap;return{width:`${t}px`,height:`${t}px`,marginLeft:e===0?`0`:`${n}px`}}let M=n(()=>{let e=E.value.size,t=E.value.overlap;return{width:`${e}px`,height:`${e}px`,marginLeft:`${t}px`,fontSize:`${Math.round(e*.32)}px`}});function N(e){let t=Math.max(8,Math.round(E.value.size*.24));return{width:`${t}px`,height:`${t}px`,backgroundColor:v[e]??v.offline}}return(e,n)=>{let c=p(`NTooltip`);return d(),a(`div`,{class:l([`c-avatar-group`,{"is-rtl":E.value.direction===`rtl`}])},[(d(!0),a(t,null,f(D.value,(e,t)=>(d(),r(c,{key:e.id,disabled:!E.value.showTooltip,placement:`top`},{trigger:g(()=>[o(`div`,{class:l([`c-avatar-group__item`,[`is-${E.value.shape}`,{"is-clickable":E.value.clickable}]]),style:u(j(t)),onClick:t=>E.value.clickable&&T(`itemClick`,e)},[e.src?(d(),a(`img`,{key:0,src:e.src,alt:e.name,class:`c-avatar-group__img`},null,8,S)):(d(),a(`div`,{key:1,class:`c-avatar-group__initials`,style:u({background:h(b)(e.name),fontSize:A.value})},m(h(y)(e.name)),5)),E.value.showStatus&&e.status?(d(),a(`span`,{key:2,class:`c-avatar-group__status`,style:u(N(e.status))},null,4)):i(`v-if`,!0)],14,x)]),default:g(()=>[s(` `+m(e.tooltip??e.name),1)]),_:2},1032,[`disabled`]))),128)),i(` 溢出 +N `),k.value>0?(d(),r(c,{key:0,placement:`top`},{trigger:g(()=>[o(`div`,{class:l([`c-avatar-group__overflow`,[`is-${E.value.shape}`,{"is-clickable":E.value.overflowClickable}]]),style:u(M.value),onClick:n[0]||=e=>E.value.overflowClickable&&T(`overflowClick`,O.value)},` +`+m(k.value),7)]),default:g(()=>[o(`div`,C,[(d(!0),a(t,null,f(O.value,e=>(d(),a(`div`,{key:e.id,style:{"line-height":`1.6`}},m(e.name),1))),128))])]),_:1})):i(`v-if`,!0)],2)}}}),[[`__scopeId`,`data-v-8be58d5b`]]);export{b as a,y as i,_ as n,v as r,w as t};
|
|
2
2
|
//# sourceMappingURL=C_AvatarGroup2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_AvatarGroup2.js","names":[],"sources":["../src/components/C_AvatarGroup/types.ts","../src/components/C_AvatarGroup/index.vue","../src/components/C_AvatarGroup/index.vue","../src/components/C_AvatarGroup/index.vue"],"sourcesContent":["/**\r\n * @Description: 头像组组件类型定义\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n */\r\n\r\n/** 单个头像数据 */\r\nexport interface AvatarItem {\r\n /** 唯一标识 */\r\n id: string | number\r\n /** 头像图片 URL */\r\n src?: string\r\n /** 姓名(用于首字母 fallback 和 tooltip) */\r\n name: string\r\n /** 悬浮提示(默认取 name) */\r\n tooltip?: string\r\n /** 在线状态 */\r\n status?: 'online' | 'offline' | 'busy' | 'away'\r\n /** 额外数据 */\r\n extra?: Record<string, unknown>\r\n}\r\n\r\n/** 组件 Props */\r\nexport interface AvatarGroupProps {\r\n /** 头像数据列表 */\r\n items: AvatarItem[]\r\n /** 最多显示数量(超出 +N) */\r\n max?: number\r\n /** 头像尺寸 (px) */\r\n size?: number\r\n /** 头像间重叠偏移量 (px),负值表示堆叠 */\r\n overlap?: number\r\n /** 形状 */\r\n shape?: 'circle' | 'square'\r\n /** 是否显示状态指示点 */\r\n showStatus?: boolean\r\n /** 是否显示悬浮提示 */\r\n showTooltip?: boolean\r\n /** 是否可点击 */\r\n clickable?: boolean\r\n /** +N 溢出按钮是否可点击 */\r\n overflowClickable?: boolean\r\n /** 堆叠方向 */\r\n direction?: 'ltr' | 'rtl'\r\n}\r\n\r\n/** 默认 Props */\r\nexport const DEFAULT_AVATAR_GROUP_PROPS: Partial<AvatarGroupProps> = {\r\n max: 5,\r\n size: 40,\r\n overlap: -10,\r\n shape: 'circle',\r\n showStatus: true,\r\n showTooltip: true,\r\n clickable: false,\r\n overflowClickable: true,\r\n direction: 'ltr',\r\n}\r\n\r\n/** 状态颜色映射 */\r\nexport const STATUS_COLOR_MAP: Record<string, string> = {\r\n online: '#18a058',\r\n offline: '#909399',\r\n busy: '#e53e3e',\r\n away: '#f0a020',\r\n}\r\n\r\n/** 从名字中提取首字母 */\r\nexport function getInitials(name: string): string {\r\n if (!name) return '?'\r\n const parts = name.trim().split(/\\s+/)\r\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase()\r\n // 中文直接取最后一个字\r\n if (/[\\u4E00-\\u9FFF]/.test(name)) return name.slice(-1)\r\n return name.slice(0, 2).toUpperCase()\r\n}\r\n\r\n/** 根据名字生成稳定的背景色 */\r\nexport function nameToColor(name: string): string {\r\n const palette = [\r\n '#6366f1',\r\n '#8b5cf6',\r\n '#a855f7',\r\n '#d946ef',\r\n '#ec4899',\r\n '#f43f5e',\r\n '#ef4444',\r\n '#f97316',\r\n '#eab308',\r\n '#84cc16',\r\n '#22c55e',\r\n '#14b8a6',\r\n '#06b6d4',\r\n '#0ea5e9',\r\n '#3b82f6',\r\n '#6d28d9',\r\n ]\r\n let hash = 0\r\n for (let i = 0; i < name.length; i++) {\r\n hash = name.charCodeAt(i) + ((hash * 31) | 0)\r\n }\r\n return palette[Math.abs(hash) % palette.length]\r\n}\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 头像组组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-avatar-group\"\r\n :class=\"{ 'is-rtl': mergedProps.direction === 'rtl' }\"\r\n >\r\n <NTooltip\r\n v-for=\"(item, idx) in visibleItems\"\r\n :key=\"item.id\"\r\n :disabled=\"!mergedProps.showTooltip\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__item\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.clickable },\r\n ]\"\r\n :style=\"itemStyle(idx)\"\r\n @click=\"mergedProps.clickable && emit('itemClick', item)\"\r\n >\r\n <img\r\n v-if=\"item.src\"\r\n :src=\"item.src\"\r\n :alt=\"item.name\"\r\n class=\"c-avatar-group__img\"\r\n />\r\n <div\r\n v-else\r\n class=\"c-avatar-group__initials\"\r\n :style=\"{\r\n background: nameToColor(item.name),\r\n fontSize: initialsFontSize,\r\n }\"\r\n >\r\n {{ getInitials(item.name) }}\r\n </div>\r\n\r\n <span\r\n v-if=\"mergedProps.showStatus && item.status\"\r\n class=\"c-avatar-group__status\"\r\n :style=\"statusStyle(item.status)\"\r\n />\r\n </div>\r\n </template>\r\n {{ item.tooltip ?? item.name }}\r\n </NTooltip>\r\n\r\n <!-- 溢出 +N -->\r\n <NTooltip\r\n v-if=\"overflowCount > 0\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__overflow\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.overflowClickable },\r\n ]\"\r\n :style=\"overflowStyle\"\r\n @click=\"\r\n mergedProps.overflowClickable && emit('overflowClick', hiddenItems)\r\n \"\r\n >\r\n +{{ overflowCount }}\r\n </div>\r\n </template>\r\n <div style=\"max-width: 200px\">\r\n <div\r\n v-for=\"h in hiddenItems\"\r\n :key=\"h.id\"\r\n style=\"line-height: 1.6\"\r\n >\r\n {{ h.name }}\r\n </div>\r\n </div>\r\n </NTooltip>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed } from 'vue'\r\n import {\r\n DEFAULT_AVATAR_GROUP_PROPS,\r\n getInitials,\r\n nameToColor,\r\n STATUS_COLOR_MAP,\r\n type AvatarGroupProps,\r\n type AvatarItem,\r\n } from './types'\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n items: AvatarGroupProps['items']\r\n max?: number\r\n size?: number\r\n overlap?: number\r\n shape?: AvatarGroupProps['shape']\r\n showStatus?: boolean\r\n showTooltip?: boolean\r\n clickable?: boolean\r\n overflowClickable?: boolean\r\n direction?: AvatarGroupProps['direction']\r\n }>(),\r\n {\r\n max: DEFAULT_AVATAR_GROUP_PROPS.max,\r\n size: DEFAULT_AVATAR_GROUP_PROPS.size,\r\n overlap: DEFAULT_AVATAR_GROUP_PROPS.overlap,\r\n shape: DEFAULT_AVATAR_GROUP_PROPS.shape,\r\n showStatus: DEFAULT_AVATAR_GROUP_PROPS.showStatus,\r\n showTooltip: DEFAULT_AVATAR_GROUP_PROPS.showTooltip,\r\n clickable: DEFAULT_AVATAR_GROUP_PROPS.clickable,\r\n overflowClickable: DEFAULT_AVATAR_GROUP_PROPS.overflowClickable,\r\n direction: DEFAULT_AVATAR_GROUP_PROPS.direction,\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n itemClick: [item: AvatarItem]\r\n overflowClick: [hiddenItems: AvatarItem[]]\r\n }>()\r\n\r\n const mergedProps = computed(() => ({\r\n ...DEFAULT_AVATAR_GROUP_PROPS,\r\n ...props,\r\n }))\r\n\r\n const visibleItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(0, max) : props.items\r\n })\r\n\r\n const hiddenItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(max) : []\r\n })\r\n\r\n const overflowCount = computed(() => hiddenItems.value.length)\r\n\r\n const initialsFontSize = computed(\r\n () => `${Math.round(mergedProps.value.size! * 0.38)}px`\r\n )\r\n\r\n /** 计算头像项定位样式 */\r\n function itemStyle(idx: number) {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: idx === 0 ? '0' : `${overlap}px`,\r\n }\r\n }\r\n\r\n const overflowStyle = computed(() => {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: `${overlap}px`,\r\n fontSize: `${Math.round(s * 0.32)}px`,\r\n }\r\n })\r\n\r\n /** 计算状态指示点样式 */\r\n function statusStyle(status: string) {\r\n const dotSize = Math.max(8, Math.round(mergedProps.value.size! * 0.24))\r\n return {\r\n width: `${dotSize}px`,\r\n height: `${dotSize}px`,\r\n backgroundColor: STATUS_COLOR_MAP[status] ?? STATUS_COLOR_MAP.offline,\r\n }\r\n }\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","/* unplugin-vue-components disabled */<!--\r\n * @Description: 头像组组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-avatar-group\"\r\n :class=\"{ 'is-rtl': mergedProps.direction === 'rtl' }\"\r\n >\r\n <NTooltip\r\n v-for=\"(item, idx) in visibleItems\"\r\n :key=\"item.id\"\r\n :disabled=\"!mergedProps.showTooltip\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__item\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.clickable },\r\n ]\"\r\n :style=\"itemStyle(idx)\"\r\n @click=\"mergedProps.clickable && emit('itemClick', item)\"\r\n >\r\n <img\r\n v-if=\"item.src\"\r\n :src=\"item.src\"\r\n :alt=\"item.name\"\r\n class=\"c-avatar-group__img\"\r\n />\r\n <div\r\n v-else\r\n class=\"c-avatar-group__initials\"\r\n :style=\"{\r\n background: nameToColor(item.name),\r\n fontSize: initialsFontSize,\r\n }\"\r\n >\r\n {{ getInitials(item.name) }}\r\n </div>\r\n\r\n <span\r\n v-if=\"mergedProps.showStatus && item.status\"\r\n class=\"c-avatar-group__status\"\r\n :style=\"statusStyle(item.status)\"\r\n />\r\n </div>\r\n </template>\r\n {{ item.tooltip ?? item.name }}\r\n </NTooltip>\r\n\r\n <!-- 溢出 +N -->\r\n <NTooltip\r\n v-if=\"overflowCount > 0\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__overflow\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.overflowClickable },\r\n ]\"\r\n :style=\"overflowStyle\"\r\n @click=\"\r\n mergedProps.overflowClickable && emit('overflowClick', hiddenItems)\r\n \"\r\n >\r\n +{{ overflowCount }}\r\n </div>\r\n </template>\r\n <div style=\"max-width: 200px\">\r\n <div\r\n v-for=\"h in hiddenItems\"\r\n :key=\"h.id\"\r\n style=\"line-height: 1.6\"\r\n >\r\n {{ h.name }}\r\n </div>\r\n </div>\r\n </NTooltip>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed } from 'vue'\r\n import {\r\n DEFAULT_AVATAR_GROUP_PROPS,\r\n getInitials,\r\n nameToColor,\r\n STATUS_COLOR_MAP,\r\n type AvatarGroupProps,\r\n type AvatarItem,\r\n } from './types'\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n items: AvatarGroupProps['items']\r\n max?: number\r\n size?: number\r\n overlap?: number\r\n shape?: AvatarGroupProps['shape']\r\n showStatus?: boolean\r\n showTooltip?: boolean\r\n clickable?: boolean\r\n overflowClickable?: boolean\r\n direction?: AvatarGroupProps['direction']\r\n }>(),\r\n {\r\n max: DEFAULT_AVATAR_GROUP_PROPS.max,\r\n size: DEFAULT_AVATAR_GROUP_PROPS.size,\r\n overlap: DEFAULT_AVATAR_GROUP_PROPS.overlap,\r\n shape: DEFAULT_AVATAR_GROUP_PROPS.shape,\r\n showStatus: DEFAULT_AVATAR_GROUP_PROPS.showStatus,\r\n showTooltip: DEFAULT_AVATAR_GROUP_PROPS.showTooltip,\r\n clickable: DEFAULT_AVATAR_GROUP_PROPS.clickable,\r\n overflowClickable: DEFAULT_AVATAR_GROUP_PROPS.overflowClickable,\r\n direction: DEFAULT_AVATAR_GROUP_PROPS.direction,\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n itemClick: [item: AvatarItem]\r\n overflowClick: [hiddenItems: AvatarItem[]]\r\n }>()\r\n\r\n const mergedProps = computed(() => ({\r\n ...DEFAULT_AVATAR_GROUP_PROPS,\r\n ...props,\r\n }))\r\n\r\n const visibleItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(0, max) : props.items\r\n })\r\n\r\n const hiddenItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(max) : []\r\n })\r\n\r\n const overflowCount = computed(() => hiddenItems.value.length)\r\n\r\n const initialsFontSize = computed(\r\n () => `${Math.round(mergedProps.value.size! * 0.38)}px`\r\n )\r\n\r\n /** 计算头像项定位样式 */\r\n function itemStyle(idx: number) {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: idx === 0 ? '0' : `${overlap}px`,\r\n }\r\n }\r\n\r\n const overflowStyle = computed(() => {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: `${overlap}px`,\r\n fontSize: `${Math.round(s * 0.32)}px`,\r\n }\r\n })\r\n\r\n /** 计算状态指示点样式 */\r\n function statusStyle(status: string) {\r\n const dotSize = Math.max(8, Math.round(mergedProps.value.size! * 0.24))\r\n return {\r\n width: `${dotSize}px`,\r\n height: `${dotSize}px`,\r\n backgroundColor: STATUS_COLOR_MAP[status] ?? STATUS_COLOR_MAP.offline,\r\n }\r\n }\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Description: 头像组组件\r\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\r\n-->\r\n<template>\r\n <div\r\n class=\"c-avatar-group\"\r\n :class=\"{ 'is-rtl': mergedProps.direction === 'rtl' }\"\r\n >\r\n <NTooltip\r\n v-for=\"(item, idx) in visibleItems\"\r\n :key=\"item.id\"\r\n :disabled=\"!mergedProps.showTooltip\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__item\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.clickable },\r\n ]\"\r\n :style=\"itemStyle(idx)\"\r\n @click=\"mergedProps.clickable && emit('itemClick', item)\"\r\n >\r\n <img\r\n v-if=\"item.src\"\r\n :src=\"item.src\"\r\n :alt=\"item.name\"\r\n class=\"c-avatar-group__img\"\r\n />\r\n <div\r\n v-else\r\n class=\"c-avatar-group__initials\"\r\n :style=\"{\r\n background: nameToColor(item.name),\r\n fontSize: initialsFontSize,\r\n }\"\r\n >\r\n {{ getInitials(item.name) }}\r\n </div>\r\n\r\n <span\r\n v-if=\"mergedProps.showStatus && item.status\"\r\n class=\"c-avatar-group__status\"\r\n :style=\"statusStyle(item.status)\"\r\n />\r\n </div>\r\n </template>\r\n {{ item.tooltip ?? item.name }}\r\n </NTooltip>\r\n\r\n <!-- 溢出 +N -->\r\n <NTooltip\r\n v-if=\"overflowCount > 0\"\r\n placement=\"top\"\r\n >\r\n <template #trigger>\r\n <div\r\n class=\"c-avatar-group__overflow\"\r\n :class=\"[\r\n `is-${mergedProps.shape}`,\r\n { 'is-clickable': mergedProps.overflowClickable },\r\n ]\"\r\n :style=\"overflowStyle\"\r\n @click=\"\r\n mergedProps.overflowClickable && emit('overflowClick', hiddenItems)\r\n \"\r\n >\r\n +{{ overflowCount }}\r\n </div>\r\n </template>\r\n <div style=\"max-width: 200px\">\r\n <div\r\n v-for=\"h in hiddenItems\"\r\n :key=\"h.id\"\r\n style=\"line-height: 1.6\"\r\n >\r\n {{ h.name }}\r\n </div>\r\n </div>\r\n </NTooltip>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed } from 'vue'\r\n import {\r\n DEFAULT_AVATAR_GROUP_PROPS,\r\n getInitials,\r\n nameToColor,\r\n STATUS_COLOR_MAP,\r\n type AvatarGroupProps,\r\n type AvatarItem,\r\n } from './types'\r\n\r\n const props = withDefaults(\r\n defineProps<{\r\n items: AvatarGroupProps['items']\r\n max?: number\r\n size?: number\r\n overlap?: number\r\n shape?: AvatarGroupProps['shape']\r\n showStatus?: boolean\r\n showTooltip?: boolean\r\n clickable?: boolean\r\n overflowClickable?: boolean\r\n direction?: AvatarGroupProps['direction']\r\n }>(),\r\n {\r\n max: DEFAULT_AVATAR_GROUP_PROPS.max,\r\n size: DEFAULT_AVATAR_GROUP_PROPS.size,\r\n overlap: DEFAULT_AVATAR_GROUP_PROPS.overlap,\r\n shape: DEFAULT_AVATAR_GROUP_PROPS.shape,\r\n showStatus: DEFAULT_AVATAR_GROUP_PROPS.showStatus,\r\n showTooltip: DEFAULT_AVATAR_GROUP_PROPS.showTooltip,\r\n clickable: DEFAULT_AVATAR_GROUP_PROPS.clickable,\r\n overflowClickable: DEFAULT_AVATAR_GROUP_PROPS.overflowClickable,\r\n direction: DEFAULT_AVATAR_GROUP_PROPS.direction,\r\n }\r\n )\r\n\r\n const emit = defineEmits<{\r\n itemClick: [item: AvatarItem]\r\n overflowClick: [hiddenItems: AvatarItem[]]\r\n }>()\r\n\r\n const mergedProps = computed(() => ({\r\n ...DEFAULT_AVATAR_GROUP_PROPS,\r\n ...props,\r\n }))\r\n\r\n const visibleItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(0, max) : props.items\r\n })\r\n\r\n const hiddenItems = computed(() => {\r\n const max = mergedProps.value.max!\r\n return props.items.length > max ? props.items.slice(max) : []\r\n })\r\n\r\n const overflowCount = computed(() => hiddenItems.value.length)\r\n\r\n const initialsFontSize = computed(\r\n () => `${Math.round(mergedProps.value.size! * 0.38)}px`\r\n )\r\n\r\n /** 计算头像项定位样式 */\r\n function itemStyle(idx: number) {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: idx === 0 ? '0' : `${overlap}px`,\r\n }\r\n }\r\n\r\n const overflowStyle = computed(() => {\r\n const s = mergedProps.value.size!\r\n const overlap = mergedProps.value.overlap!\r\n return {\r\n width: `${s}px`,\r\n height: `${s}px`,\r\n marginLeft: `${overlap}px`,\r\n fontSize: `${Math.round(s * 0.32)}px`,\r\n }\r\n })\r\n\r\n /** 计算状态指示点样式 */\r\n function statusStyle(status: string) {\r\n const dotSize = Math.max(8, Math.round(mergedProps.value.size! * 0.24))\r\n return {\r\n width: `${dotSize}px`,\r\n height: `${dotSize}px`,\r\n backgroundColor: STATUS_COLOR_MAP[status] ?? STATUS_COLOR_MAP.offline,\r\n }\r\n }\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"C_AvatarGroup2.js","names":[],"sources":["../src/components/C_AvatarGroup/types.ts","../src/components/C_AvatarGroup/index.vue"],"sourcesContent":["/**\n * @Description: 头像组组件类型定义\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n */\n\n/** 单个头像数据 */\nexport interface AvatarItem {\n /** 唯一标识 */\n id: string | number\n /** 头像图片 URL */\n src?: string\n /** 姓名(用于首字母 fallback 和 tooltip) */\n name: string\n /** 悬浮提示(默认取 name) */\n tooltip?: string\n /** 在线状态 */\n status?: 'online' | 'offline' | 'busy' | 'away'\n /** 额外数据 */\n extra?: Record<string, unknown>\n}\n\n/** 组件 Props */\nexport interface AvatarGroupProps {\n /** 头像数据列表 */\n items: AvatarItem[]\n /** 最多显示数量(超出 +N) */\n max?: number\n /** 头像尺寸 (px) */\n size?: number\n /** 头像间重叠偏移量 (px),负值表示堆叠 */\n overlap?: number\n /** 形状 */\n shape?: 'circle' | 'square'\n /** 是否显示状态指示点 */\n showStatus?: boolean\n /** 是否显示悬浮提示 */\n showTooltip?: boolean\n /** 是否可点击 */\n clickable?: boolean\n /** +N 溢出按钮是否可点击 */\n overflowClickable?: boolean\n /** 堆叠方向 */\n direction?: 'ltr' | 'rtl'\n}\n\n/** 默认 Props */\nexport const DEFAULT_AVATAR_GROUP_PROPS: Partial<AvatarGroupProps> = {\n max: 5,\n size: 40,\n overlap: -10,\n shape: 'circle',\n showStatus: true,\n showTooltip: true,\n clickable: false,\n overflowClickable: true,\n direction: 'ltr',\n}\n\n/** 状态颜色映射 */\nexport const STATUS_COLOR_MAP: Record<string, string> = {\n online: '#18a058',\n offline: '#909399',\n busy: '#e53e3e',\n away: '#f0a020',\n}\n\n/** 从名字中提取首字母 */\nexport function getInitials(name: string): string {\n if (!name) return '?'\n const parts = name.trim().split(/\\s+/)\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase()\n // 中文直接取最后一个字\n if (/[\\u4E00-\\u9FFF]/.test(name)) return name.slice(-1)\n return name.slice(0, 2).toUpperCase()\n}\n\n/** 根据名字生成稳定的背景色 */\nexport function nameToColor(name: string): string {\n const palette = [\n '#6366f1',\n '#8b5cf6',\n '#a855f7',\n '#d946ef',\n '#ec4899',\n '#f43f5e',\n '#ef4444',\n '#f97316',\n '#eab308',\n '#84cc16',\n '#22c55e',\n '#14b8a6',\n '#06b6d4',\n '#0ea5e9',\n '#3b82f6',\n '#6d28d9',\n ]\n let hash = 0\n for (let i = 0; i < name.length; i++) {\n hash = name.charCodeAt(i) + ((hash * 31) | 0)\n }\n return palette[Math.abs(hash) % palette.length]\n}\n","<!--\n * @Description: 头像组组件\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n-->\n<template>\n <div\n class=\"c-avatar-group\"\n :class=\"{ 'is-rtl': mergedProps.direction === 'rtl' }\"\n >\n <NTooltip\n v-for=\"(item, idx) in visibleItems\"\n :key=\"item.id\"\n :disabled=\"!mergedProps.showTooltip\"\n placement=\"top\"\n >\n <template #trigger>\n <div\n class=\"c-avatar-group__item\"\n :class=\"[\n `is-${mergedProps.shape}`,\n { 'is-clickable': mergedProps.clickable },\n ]\"\n :style=\"itemStyle(idx)\"\n @click=\"mergedProps.clickable && emit('itemClick', item)\"\n >\n <img\n v-if=\"item.src\"\n :src=\"item.src\"\n :alt=\"item.name\"\n class=\"c-avatar-group__img\"\n />\n <div\n v-else\n class=\"c-avatar-group__initials\"\n :style=\"{\n background: nameToColor(item.name),\n fontSize: initialsFontSize,\n }\"\n >\n {{ getInitials(item.name) }}\n </div>\n\n <span\n v-if=\"mergedProps.showStatus && item.status\"\n class=\"c-avatar-group__status\"\n :style=\"statusStyle(item.status)\"\n />\n </div>\n </template>\n {{ item.tooltip ?? item.name }}\n </NTooltip>\n\n <!-- 溢出 +N -->\n <NTooltip\n v-if=\"overflowCount > 0\"\n placement=\"top\"\n >\n <template #trigger>\n <div\n class=\"c-avatar-group__overflow\"\n :class=\"[\n `is-${mergedProps.shape}`,\n { 'is-clickable': mergedProps.overflowClickable },\n ]\"\n :style=\"overflowStyle\"\n @click=\"\n mergedProps.overflowClickable && emit('overflowClick', hiddenItems)\n \"\n >\n +{{ overflowCount }}\n </div>\n </template>\n <div style=\"max-width: 200px\">\n <div\n v-for=\"h in hiddenItems\"\n :key=\"h.id\"\n style=\"line-height: 1.6\"\n >\n {{ h.name }}\n </div>\n </div>\n </NTooltip>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue'\n import {\n DEFAULT_AVATAR_GROUP_PROPS,\n getInitials,\n nameToColor,\n STATUS_COLOR_MAP,\n type AvatarGroupProps,\n type AvatarItem,\n } from './types'\n\n const props = withDefaults(\n defineProps<{\n items: AvatarGroupProps['items']\n max?: number\n size?: number\n overlap?: number\n shape?: AvatarGroupProps['shape']\n showStatus?: boolean\n showTooltip?: boolean\n clickable?: boolean\n overflowClickable?: boolean\n direction?: AvatarGroupProps['direction']\n }>(),\n {\n max: DEFAULT_AVATAR_GROUP_PROPS.max,\n size: DEFAULT_AVATAR_GROUP_PROPS.size,\n overlap: DEFAULT_AVATAR_GROUP_PROPS.overlap,\n shape: DEFAULT_AVATAR_GROUP_PROPS.shape,\n showStatus: DEFAULT_AVATAR_GROUP_PROPS.showStatus,\n showTooltip: DEFAULT_AVATAR_GROUP_PROPS.showTooltip,\n clickable: DEFAULT_AVATAR_GROUP_PROPS.clickable,\n overflowClickable: DEFAULT_AVATAR_GROUP_PROPS.overflowClickable,\n direction: DEFAULT_AVATAR_GROUP_PROPS.direction,\n }\n )\n\n const emit = defineEmits<{\n itemClick: [item: AvatarItem]\n overflowClick: [hiddenItems: AvatarItem[]]\n }>()\n\n const mergedProps = computed(() => ({\n ...DEFAULT_AVATAR_GROUP_PROPS,\n ...props,\n }))\n\n const visibleItems = computed(() => {\n const max = mergedProps.value.max!\n return props.items.length > max ? props.items.slice(0, max) : props.items\n })\n\n const hiddenItems = computed(() => {\n const max = mergedProps.value.max!\n return props.items.length > max ? props.items.slice(max) : []\n })\n\n const overflowCount = computed(() => hiddenItems.value.length)\n\n const initialsFontSize = computed(\n () => `${Math.round(mergedProps.value.size! * 0.38)}px`\n )\n\n /** 计算头像项定位样式 */\n function itemStyle(idx: number) {\n const s = mergedProps.value.size!\n const overlap = mergedProps.value.overlap!\n return {\n width: `${s}px`,\n height: `${s}px`,\n marginLeft: idx === 0 ? '0' : `${overlap}px`,\n }\n }\n\n const overflowStyle = computed(() => {\n const s = mergedProps.value.size!\n const overlap = mergedProps.value.overlap!\n return {\n width: `${s}px`,\n height: `${s}px`,\n marginLeft: `${overlap}px`,\n fontSize: `${Math.round(s * 0.32)}px`,\n }\n })\n\n /** 计算状态指示点样式 */\n function statusStyle(status: string) {\n const dotSize = Math.max(8, Math.round(mergedProps.value.size! * 0.24))\n return {\n width: `${dotSize}px`,\n height: `${dotSize}px`,\n backgroundColor: STATUS_COLOR_MAP[status] ?? STATUS_COLOR_MAP.offline,\n }\n }\n</script>\n\n<style scoped lang=\"scss\">\n @use './index.scss';\n</style>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Barcode-
|
|
1
|
+
{"version":3,"file":"C_Barcode-DYDRDe2O.css","names":[],"sources":["../src/components/C_Barcode/index.vue?vue&type=style&index=0&scoped=03c1988e&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled */.c-barcode[data-v-03c1988e] {\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n max-width: 100%;\n}\n.c-barcode .barcode-wrapper[data-v-03c1988e] {\n display: inline-block;\n padding: 8px;\n background: #ffffff;\n border-radius: 4px;\n transition: all 0.3s ease;\n overflow: hidden;\n max-width: 100%;\n}\n.c-barcode .barcode-wrapper.with-border[data-v-03c1988e] {\n border: 1px dashed #e0e0e0;\n}\n.c-barcode .barcode-wrapper[data-v-03c1988e]:hover {\n border-color: var(--c-primary, #409eff);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n.c-barcode .barcode-wrapper[data-v-03c1988e] svg {\n max-width: 100%;\n height: auto;\n display: block;\n overflow: visible;\n}\n.c-barcode .barcode-label[data-v-03c1988e] {\n font-size: 14px;\n color: #666;\n text-align: center;\n font-weight: 500;\n word-break: break-all;\n max-width: 100%;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"C_Barcode-
|
|
1
|
+
{"version":3,"file":"C_Barcode-muJdc_O4.css","names":[],"sources":["../src/components/C_Barcode/index.vue?vue&type=style&index=0&scoped=03c1988e&lang.scss"],"sourcesContent":["/* unplugin-vue-components disabled */.c-barcode[data-v-03c1988e] {\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n max-width: 100%;\n}\n.c-barcode .barcode-wrapper[data-v-03c1988e] {\n display: inline-block;\n padding: 8px;\n background: #ffffff;\n border-radius: 4px;\n transition: all 0.3s ease;\n overflow: hidden;\n max-width: 100%;\n}\n.c-barcode .barcode-wrapper.with-border[data-v-03c1988e] {\n border: 1px dashed #e0e0e0;\n}\n.c-barcode .barcode-wrapper[data-v-03c1988e]:hover {\n border-color: var(--c-primary, #409eff);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n}\n.c-barcode .barcode-wrapper[data-v-03c1988e] svg {\n max-width: 100%;\n height: auto;\n display: block;\n overflow: visible;\n}\n.c-barcode .barcode-label[data-v-03c1988e] {\n font-size: 14px;\n color: #666;\n text-align: center;\n font-weight: 500;\n word-break: break-all;\n max-width: 100%;\n}"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
|
package/dist/C_Barcode.css
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
/* unplugin-vue-components disabled */.c-barcode[data-v-
|
|
1
|
+
/* unplugin-vue-components disabled */.c-barcode[data-v-03c1988e] {
|
|
2
2
|
display: inline-flex;
|
|
3
3
|
flex-direction: column;
|
|
4
4
|
align-items: center;
|
|
5
5
|
gap: 8px;
|
|
6
6
|
max-width: 100%;
|
|
7
7
|
}
|
|
8
|
-
.c-barcode .barcode-wrapper[data-v-
|
|
8
|
+
.c-barcode .barcode-wrapper[data-v-03c1988e] {
|
|
9
9
|
display: inline-block;
|
|
10
10
|
padding: 8px;
|
|
11
11
|
background: #ffffff;
|
|
@@ -14,20 +14,20 @@
|
|
|
14
14
|
overflow: hidden;
|
|
15
15
|
max-width: 100%;
|
|
16
16
|
}
|
|
17
|
-
.c-barcode .barcode-wrapper.with-border[data-v-
|
|
17
|
+
.c-barcode .barcode-wrapper.with-border[data-v-03c1988e] {
|
|
18
18
|
border: 1px dashed #e0e0e0;
|
|
19
19
|
}
|
|
20
|
-
.c-barcode .barcode-wrapper[data-v-
|
|
20
|
+
.c-barcode .barcode-wrapper[data-v-03c1988e]:hover {
|
|
21
21
|
border-color: var(--c-primary, #409eff);
|
|
22
22
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
23
23
|
}
|
|
24
|
-
.c-barcode .barcode-wrapper[data-v-
|
|
24
|
+
.c-barcode .barcode-wrapper[data-v-03c1988e] svg {
|
|
25
25
|
max-width: 100%;
|
|
26
26
|
height: auto;
|
|
27
27
|
display: block;
|
|
28
28
|
overflow: visible;
|
|
29
29
|
}
|
|
30
|
-
.c-barcode .barcode-label[data-v-
|
|
30
|
+
.c-barcode .barcode-label[data-v-03c1988e] {
|
|
31
31
|
font-size: 14px;
|
|
32
32
|
color: #666;
|
|
33
33
|
text-align: center;
|
|
@@ -36,4 +36,4 @@
|
|
|
36
36
|
max-width: 100%;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
/*# sourceMappingURL=C_Barcode-
|
|
39
|
+
/*# sourceMappingURL=C_Barcode-DYDRDe2O.css.map*/
|