@lee576/vue3-gantt 1.0.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/LICENSE +21 -0
- package/README.en-US.md +647 -0
- package/README.md +730 -0
- package/dist/index.d.ts +1 -0
- package/dist/vue3-gantt.css +1 -0
- package/dist/vue3-gantt.es.js +7275 -0
- package/dist/vue3-gantt.es.js.map +1 -0
- package/dist/vue3-gantt.umd.js +123 -0
- package/dist/vue3-gantt.umd.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vue3-gantt.es.js","sources":["../node_modules/dayjs/plugin/customParseFormat.js","../node_modules/dayjs/locale/zh-cn.js","../node_modules/dayjs/locale/en.js","../node_modules/dayjs/locale/ja.js","../node_modules/dayjs/locale/ko.js","../node_modules/dayjs/locale/fr.js","../node_modules/dayjs/locale/de.js","../node_modules/dayjs/locale/es.js","../node_modules/dayjs/locale/ru.js","../src/components/gantt/Symbols.ts","../src/components/gantt/Types.ts","../src/components/gantt/LinkConfig.ts","../src/components/gantt/i18n/locales/zh-CN.ts","../src/components/gantt/i18n/locales/en-US.ts","../src/components/gantt/i18n/locales/ja-JP.ts","../src/components/gantt/i18n/locales/ko-KR.ts","../src/components/gantt/i18n/locales/fr-FR.ts","../src/components/gantt/i18n/locales/de-DE.ts","../src/components/gantt/i18n/locales/es-ES.ts","../src/components/gantt/i18n/locales/ru-RU.ts","../src/components/gantt/i18n/index.ts","../src/components/gantt/DatePicker.vue","../src/components/gantt/DatePicker.vue","../src/components/gantt/SplitPane.vue","../src/components/gantt/SplitPane.vue","../src/components/gantt/task/TaskHeader.vue","../src/components/gantt/task/TaskHeader.vue","../src/components/gantt/Store.ts","../src/components/gantt/ShareState.ts","../src/components/gantt/task/TaskRow.vue","../src/components/gantt/task/TaskRow.vue","../src/components/gantt/task/TaskRecursionRow.vue","../src/components/gantt/task/TaskRecursionRow.vue","../src/components/gantt/task/TaskContent.vue","../src/components/gantt/task/TaskContent.vue","../node_modules/dayjs/plugin/isBetween.js","../src/components/gantt/task/TaskTable.vue","../src/components/gantt/task/TaskTable.vue","../src/components/gantt/TimelineHeader.vue","../src/components/gantt/TimelineHeader.vue","../node_modules/dayjs/plugin/isoWeek.js","../src/components/gantt/Bar.vue","../src/components/gantt/Bar.vue","../src/components/gantt/BarRecursionRow.vue","../src/components/gantt/BarRecursionRow.vue","../src/components/gantt/TaskLinks.vue","../src/components/gantt/TaskLinks.vue","../src/components/gantt/TableContent.vue","../src/components/gantt/TableContent.vue","../src/components/gantt/RightTable.vue","../src/components/gantt/RightTable.vue","../src/components/gantt/themes/GanttThemes.ts","../src/components/gantt/GanttConfigPanel.vue","../src/components/gantt/GanttConfigPanel.vue","../src/components/gantt/ZodSchema.ts","../src/components/gantt/Gantt.vue","../src/components/gantt/Gantt.vue","../src/components/gantt/GanttThemeSelector.vue","../src/components/gantt/GanttThemeSelector.vue","../src/components/gantt/LanguageSelector.vue","../src/components/gantt/LanguageSelector.vue","../src/components/gantt/LinkConfigPanel.vue","../src/components/gantt/LinkConfigPanel.vue","../src/index.ts"],"sourcesContent":["!function(e,t){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define(t):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_plugin_customParseFormat=t()}(this,(function(){\"use strict\";var e={LTS:\"h:mm:ss A\",LT:\"h:mm A\",L:\"MM/DD/YYYY\",LL:\"MMMM D, YYYY\",LLL:\"MMMM D, YYYY h:mm A\",LLLL:\"dddd, MMMM D, YYYY h:mm A\"},t=/(\\[[^[]*\\])|([-_:/.,()\\s]+)|(A|a|Q|YYYY|YY?|ww?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,n=/\\d/,r=/\\d\\d/,i=/\\d\\d?/,o=/\\d*[^-_:/,()\\s\\d]+/,s={},a=function(e){return(e=+e)+(e>68?1900:2e3)};var f=function(e){return function(t){this[e]=+t}},h=[/[+-]\\d\\d:?(\\d\\d)?|Z/,function(e){(this.zone||(this.zone={})).offset=function(e){if(!e)return 0;if(\"Z\"===e)return 0;var t=e.match(/([+-]|\\d\\d)/g),n=60*t[1]+(+t[2]||0);return 0===n?0:\"+\"===t[0]?-n:n}(e)}],u=function(e){var t=s[e];return t&&(t.indexOf?t:t.s.concat(t.f))},d=function(e,t){var n,r=s.meridiem;if(r){for(var i=1;i<=24;i+=1)if(e.indexOf(r(i,0,t))>-1){n=i>12;break}}else n=e===(t?\"pm\":\"PM\");return n},c={A:[o,function(e){this.afternoon=d(e,!1)}],a:[o,function(e){this.afternoon=d(e,!0)}],Q:[n,function(e){this.month=3*(e-1)+1}],S:[n,function(e){this.milliseconds=100*+e}],SS:[r,function(e){this.milliseconds=10*+e}],SSS:[/\\d{3}/,function(e){this.milliseconds=+e}],s:[i,f(\"seconds\")],ss:[i,f(\"seconds\")],m:[i,f(\"minutes\")],mm:[i,f(\"minutes\")],H:[i,f(\"hours\")],h:[i,f(\"hours\")],HH:[i,f(\"hours\")],hh:[i,f(\"hours\")],D:[i,f(\"day\")],DD:[r,f(\"day\")],Do:[o,function(e){var t=s.ordinal,n=e.match(/\\d+/);if(this.day=n[0],t)for(var r=1;r<=31;r+=1)t(r).replace(/\\[|\\]/g,\"\")===e&&(this.day=r)}],w:[i,f(\"week\")],ww:[r,f(\"week\")],M:[i,f(\"month\")],MM:[r,f(\"month\")],MMM:[o,function(e){var t=u(\"months\"),n=(u(\"monthsShort\")||t.map((function(e){return e.slice(0,3)}))).indexOf(e)+1;if(n<1)throw new Error;this.month=n%12||n}],MMMM:[o,function(e){var t=u(\"months\").indexOf(e)+1;if(t<1)throw new Error;this.month=t%12||t}],Y:[/[+-]?\\d+/,f(\"year\")],YY:[r,function(e){this.year=a(e)}],YYYY:[/\\d{4}/,f(\"year\")],Z:h,ZZ:h};function l(n){var r,i;r=n,i=s&&s.formats;for(var o=(n=r.replace(/(\\[[^\\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,n,r){var o=r&&r.toUpperCase();return n||i[r]||e[r]||i[o].replace(/(\\[[^\\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}))).match(t),a=o.length,f=0;f<a;f+=1){var h=o[f],u=c[h],d=u&&u[0],l=u&&u[1];o[f]=l?{regex:d,parser:l}:h.replace(/^\\[|\\]$/g,\"\")}return function(e){for(var t={},n=0,r=0;n<a;n+=1){var i=o[n];if(\"string\"==typeof i)r+=i.length;else{var s=i.regex,f=i.parser,h=e.slice(r),u=s.exec(h)[0];f.call(t,u),e=e.replace(u,\"\")}}return function(e){var t=e.afternoon;if(void 0!==t){var n=e.hours;t?n<12&&(e.hours+=12):12===n&&(e.hours=0),delete e.afternoon}}(t),t}}return function(e,t,n){n.p.customParseFormat=!0,e&&e.parseTwoDigitYear&&(a=e.parseTwoDigitYear);var r=t.prototype,i=r.parse;r.parse=function(e){var t=e.date,r=e.utc,o=e.args;this.$u=r;var a=o[1];if(\"string\"==typeof a){var f=!0===o[2],h=!0===o[3],u=f||h,d=o[2];h&&(d=o[2]),s=this.$locale(),!f&&d&&(s=n.Ls[d]),this.$d=function(e,t,n,r){try{if([\"x\",\"X\"].indexOf(t)>-1)return new Date((\"X\"===t?1e3:1)*e);var i=l(t)(e),o=i.year,s=i.month,a=i.day,f=i.hours,h=i.minutes,u=i.seconds,d=i.milliseconds,c=i.zone,m=i.week,M=new Date,Y=a||(o||s?1:M.getDate()),p=o||M.getFullYear(),v=0;o&&!s||(v=s>0?s-1:M.getMonth());var D,w=f||0,g=h||0,y=u||0,L=d||0;return c?new Date(Date.UTC(p,v,Y,w,g,y,L+60*c.offset*1e3)):n?new Date(Date.UTC(p,v,Y,w,g,y,L)):(D=new Date(p,v,Y,w,g,y,L),m&&(D=r(D).week(m).toDate()),D)}catch(e){return new Date(\"\")}}(t,a,r,n),this.init(),d&&!0!==d&&(this.$L=this.locale(d).$L),u&&t!=this.format(a)&&(this.$d=new Date(\"\")),s={}}else if(a instanceof Array)for(var c=a.length,m=1;m<=c;m+=1){o[1]=a[m-1];var M=n.apply(this,o);if(M.isValid()){this.$d=M.$d,this.$L=M.$L,this.init();break}m===c&&(this.$d=new Date(\"\"))}else i.call(this,e)}}}));","!function(e,_){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=_(require(\"dayjs\")):\"function\"==typeof define&&define.amd?define([\"dayjs\"],_):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_locale_zh_cn=_(e.dayjs)}(this,(function(e){\"use strict\";function _(e){return e&&\"object\"==typeof e&&\"default\"in e?e:{default:e}}var t=_(e),d={name:\"zh-cn\",weekdays:\"星期日_星期一_星期二_星期三_星期四_星期五_星期六\".split(\"_\"),weekdaysShort:\"周日_周一_周二_周三_周四_周五_周六\".split(\"_\"),weekdaysMin:\"日_一_二_三_四_五_六\".split(\"_\"),months:\"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月\".split(\"_\"),monthsShort:\"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月\".split(\"_\"),ordinal:function(e,_){return\"W\"===_?e+\"周\":e+\"日\"},weekStart:1,yearStart:4,formats:{LT:\"HH:mm\",LTS:\"HH:mm:ss\",L:\"YYYY/MM/DD\",LL:\"YYYY年M月D日\",LLL:\"YYYY年M月D日Ah点mm分\",LLLL:\"YYYY年M月D日ddddAh点mm分\",l:\"YYYY/M/D\",ll:\"YYYY年M月D日\",lll:\"YYYY年M月D日 HH:mm\",llll:\"YYYY年M月D日dddd HH:mm\"},relativeTime:{future:\"%s内\",past:\"%s前\",s:\"几秒\",m:\"1 分钟\",mm:\"%d 分钟\",h:\"1 小时\",hh:\"%d 小时\",d:\"1 天\",dd:\"%d 天\",M:\"1 个月\",MM:\"%d 个月\",y:\"1 年\",yy:\"%d 年\"},meridiem:function(e,_){var t=100*e+_;return t<600?\"凌晨\":t<900?\"早上\":t<1100?\"上午\":t<1300?\"中午\":t<1800?\"下午\":\"晚上\"}};return t.default.locale(d,null,!0),d}));","!function(e,n){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=n():\"function\"==typeof define&&define.amd?define(n):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_locale_en=n()}(this,(function(){\"use strict\";return{name:\"en\",weekdays:\"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday\".split(\"_\"),months:\"January_February_March_April_May_June_July_August_September_October_November_December\".split(\"_\"),ordinal:function(e){var n=[\"th\",\"st\",\"nd\",\"rd\"],t=e%100;return\"[\"+e+(n[(t-20)%10]||n[t]||n[0])+\"]\"}}}));","!function(e,_){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=_(require(\"dayjs\")):\"function\"==typeof define&&define.amd?define([\"dayjs\"],_):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_locale_ja=_(e.dayjs)}(this,(function(e){\"use strict\";function _(e){return e&&\"object\"==typeof e&&\"default\"in e?e:{default:e}}var t=_(e),d={name:\"ja\",weekdays:\"日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日\".split(\"_\"),weekdaysShort:\"日_月_火_水_木_金_土\".split(\"_\"),weekdaysMin:\"日_月_火_水_木_金_土\".split(\"_\"),months:\"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月\".split(\"_\"),monthsShort:\"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月\".split(\"_\"),ordinal:function(e){return e+\"日\"},formats:{LT:\"HH:mm\",LTS:\"HH:mm:ss\",L:\"YYYY/MM/DD\",LL:\"YYYY年M月D日\",LLL:\"YYYY年M月D日 HH:mm\",LLLL:\"YYYY年M月D日 dddd HH:mm\",l:\"YYYY/MM/DD\",ll:\"YYYY年M月D日\",lll:\"YYYY年M月D日 HH:mm\",llll:\"YYYY年M月D日(ddd) HH:mm\"},meridiem:function(e){return e<12?\"午前\":\"午後\"},relativeTime:{future:\"%s後\",past:\"%s前\",s:\"数秒\",m:\"1分\",mm:\"%d分\",h:\"1時間\",hh:\"%d時間\",d:\"1日\",dd:\"%d日\",M:\"1ヶ月\",MM:\"%dヶ月\",y:\"1年\",yy:\"%d年\"}};return t.default.locale(d,null,!0),d}));","!function(e,_){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=_(require(\"dayjs\")):\"function\"==typeof define&&define.amd?define([\"dayjs\"],_):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_locale_ko=_(e.dayjs)}(this,(function(e){\"use strict\";function _(e){return e&&\"object\"==typeof e&&\"default\"in e?e:{default:e}}var d=_(e),t={name:\"ko\",weekdays:\"일요일_월요일_화요일_수요일_목요일_금요일_토요일\".split(\"_\"),weekdaysShort:\"일_월_화_수_목_금_토\".split(\"_\"),weekdaysMin:\"일_월_화_수_목_금_토\".split(\"_\"),months:\"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월\".split(\"_\"),monthsShort:\"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월\".split(\"_\"),ordinal:function(e){return e+\"일\"},formats:{LT:\"A h:mm\",LTS:\"A h:mm:ss\",L:\"YYYY.MM.DD.\",LL:\"YYYY년 MMMM D일\",LLL:\"YYYY년 MMMM D일 A h:mm\",LLLL:\"YYYY년 MMMM D일 dddd A h:mm\",l:\"YYYY.MM.DD.\",ll:\"YYYY년 MMMM D일\",lll:\"YYYY년 MMMM D일 A h:mm\",llll:\"YYYY년 MMMM D일 dddd A h:mm\"},meridiem:function(e){return e<12?\"오전\":\"오후\"},relativeTime:{future:\"%s 후\",past:\"%s 전\",s:\"몇 초\",m:\"1분\",mm:\"%d분\",h:\"한 시간\",hh:\"%d시간\",d:\"하루\",dd:\"%d일\",M:\"한 달\",MM:\"%d달\",y:\"일 년\",yy:\"%d년\"}};return d.default.locale(t,null,!0),t}));","!function(e,n){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=n(require(\"dayjs\")):\"function\"==typeof define&&define.amd?define([\"dayjs\"],n):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_locale_fr=n(e.dayjs)}(this,(function(e){\"use strict\";function n(e){return e&&\"object\"==typeof e&&\"default\"in e?e:{default:e}}var t=n(e),i={name:\"fr\",weekdays:\"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi\".split(\"_\"),weekdaysShort:\"dim._lun._mar._mer._jeu._ven._sam.\".split(\"_\"),weekdaysMin:\"di_lu_ma_me_je_ve_sa\".split(\"_\"),months:\"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre\".split(\"_\"),monthsShort:\"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.\".split(\"_\"),weekStart:1,yearStart:4,formats:{LT:\"HH:mm\",LTS:\"HH:mm:ss\",L:\"DD/MM/YYYY\",LL:\"D MMMM YYYY\",LLL:\"D MMMM YYYY HH:mm\",LLLL:\"dddd D MMMM YYYY HH:mm\"},relativeTime:{future:\"dans %s\",past:\"il y a %s\",s:\"quelques secondes\",m:\"une minute\",mm:\"%d minutes\",h:\"une heure\",hh:\"%d heures\",d:\"un jour\",dd:\"%d jours\",M:\"un mois\",MM:\"%d mois\",y:\"un an\",yy:\"%d ans\"},ordinal:function(e){return\"\"+e+(1===e?\"er\":\"\")}};return t.default.locale(i,null,!0),i}));","!function(e,n){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=n(require(\"dayjs\")):\"function\"==typeof define&&define.amd?define([\"dayjs\"],n):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_locale_de=n(e.dayjs)}(this,(function(e){\"use strict\";function n(e){return e&&\"object\"==typeof e&&\"default\"in e?e:{default:e}}var t=n(e),a={s:\"ein paar Sekunden\",m:[\"eine Minute\",\"einer Minute\"],mm:\"%d Minuten\",h:[\"eine Stunde\",\"einer Stunde\"],hh:\"%d Stunden\",d:[\"ein Tag\",\"einem Tag\"],dd:[\"%d Tage\",\"%d Tagen\"],M:[\"ein Monat\",\"einem Monat\"],MM:[\"%d Monate\",\"%d Monaten\"],y:[\"ein Jahr\",\"einem Jahr\"],yy:[\"%d Jahre\",\"%d Jahren\"]};function i(e,n,t){var i=a[t];return Array.isArray(i)&&(i=i[n?0:1]),i.replace(\"%d\",e)}var r={name:\"de\",weekdays:\"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag\".split(\"_\"),weekdaysShort:\"So._Mo._Di._Mi._Do._Fr._Sa.\".split(\"_\"),weekdaysMin:\"So_Mo_Di_Mi_Do_Fr_Sa\".split(\"_\"),months:\"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember\".split(\"_\"),monthsShort:\"Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sept._Okt._Nov._Dez.\".split(\"_\"),ordinal:function(e){return e+\".\"},weekStart:1,yearStart:4,formats:{LTS:\"HH:mm:ss\",LT:\"HH:mm\",L:\"DD.MM.YYYY\",LL:\"D. MMMM YYYY\",LLL:\"D. MMMM YYYY HH:mm\",LLLL:\"dddd, D. MMMM YYYY HH:mm\"},relativeTime:{future:\"in %s\",past:\"vor %s\",s:i,m:i,mm:i,h:i,hh:i,d:i,dd:i,M:i,MM:i,y:i,yy:i}};return t.default.locale(r,null,!0),r}));","!function(e,o){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=o(require(\"dayjs\")):\"function\"==typeof define&&define.amd?define([\"dayjs\"],o):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_locale_es=o(e.dayjs)}(this,(function(e){\"use strict\";function o(e){return e&&\"object\"==typeof e&&\"default\"in e?e:{default:e}}var s=o(e),d={name:\"es\",monthsShort:\"ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic\".split(\"_\"),weekdays:\"domingo_lunes_martes_miércoles_jueves_viernes_sábado\".split(\"_\"),weekdaysShort:\"dom._lun._mar._mié._jue._vie._sáb.\".split(\"_\"),weekdaysMin:\"do_lu_ma_mi_ju_vi_sá\".split(\"_\"),months:\"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre\".split(\"_\"),weekStart:1,formats:{LT:\"H:mm\",LTS:\"H:mm:ss\",L:\"DD/MM/YYYY\",LL:\"D [de] MMMM [de] YYYY\",LLL:\"D [de] MMMM [de] YYYY H:mm\",LLLL:\"dddd, D [de] MMMM [de] YYYY H:mm\"},relativeTime:{future:\"en %s\",past:\"hace %s\",s:\"unos segundos\",m:\"un minuto\",mm:\"%d minutos\",h:\"una hora\",hh:\"%d horas\",d:\"un día\",dd:\"%d días\",M:\"un mes\",MM:\"%d meses\",y:\"un año\",yy:\"%d años\"},ordinal:function(e){return e+\"º\"}};return s.default.locale(d,null,!0),d}));","!function(_,t){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=t(require(\"dayjs\")):\"function\"==typeof define&&define.amd?define([\"dayjs\"],t):(_=\"undefined\"!=typeof globalThis?globalThis:_||self).dayjs_locale_ru=t(_.dayjs)}(this,(function(_){\"use strict\";function t(_){return _&&\"object\"==typeof _&&\"default\"in _?_:{default:_}}var e=t(_),n=\"января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря\".split(\"_\"),s=\"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь\".split(\"_\"),r=\"янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.\".split(\"_\"),o=\"янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.\".split(\"_\"),i=/D[oD]?(\\[[^[\\]]*\\]|\\s)+MMMM?/;function d(_,t,e){var n,s;return\"m\"===e?t?\"минута\":\"минуту\":_+\" \"+(n=+_,s={mm:t?\"минута_минуты_минут\":\"минуту_минуты_минут\",hh:\"час_часа_часов\",dd:\"день_дня_дней\",MM:\"месяц_месяца_месяцев\",yy:\"год_года_лет\"}[e].split(\"_\"),n%10==1&&n%100!=11?s[0]:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?s[1]:s[2])}var u=function(_,t){return i.test(t)?n[_.month()]:s[_.month()]};u.s=s,u.f=n;var a=function(_,t){return i.test(t)?r[_.month()]:o[_.month()]};a.s=o,a.f=r;var m={name:\"ru\",weekdays:\"воскресенье_понедельник_вторник_среда_четверг_пятница_суббота\".split(\"_\"),weekdaysShort:\"вск_пнд_втр_срд_чтв_птн_сбт\".split(\"_\"),weekdaysMin:\"вс_пн_вт_ср_чт_пт_сб\".split(\"_\"),months:u,monthsShort:a,weekStart:1,yearStart:4,formats:{LT:\"H:mm\",LTS:\"H:mm:ss\",L:\"DD.MM.YYYY\",LL:\"D MMMM YYYY г.\",LLL:\"D MMMM YYYY г., H:mm\",LLLL:\"dddd, D MMMM YYYY г., H:mm\"},relativeTime:{future:\"через %s\",past:\"%s назад\",s:\"несколько секунд\",m:d,mm:d,h:\"час\",hh:d,d:\"день\",dd:d,M:\"месяц\",MM:d,y:\"год\",yy:d},ordinal:function(_){return _},meridiem:function(_){return _<4?\"ночи\":_<12?\"утра\":_<17?\"дня\":\"вечера\"}};return e.default.locale(m,null,!0),m}));","// 定义多个 Symbol\r\nconst SetBarColorSymbol = Symbol('SetBarColor');\r\nconst AddRootTaskSymbol = Symbol('AddRootTask');\r\nconst SharedStateSymbol = Symbol('SharedState');\r\n\r\n// 以对象形式导出\r\nexport const Symbols = {\r\n SetBarColorSymbol,\r\n AddRootTaskSymbol,\r\n SharedStateSymbol\r\n};","// 连线类型枚举\r\nexport enum LinkType {\r\n FINISH_TO_START = 'finish-to-start', // 完成-开始(最常用)\r\n START_TO_START = 'start-to-start', // 开始-开始\r\n FINISH_TO_FINISH = 'finish-to-finish', // 完成-完成\r\n START_TO_FINISH = 'start-to-finish', // 开始-完成\r\n PARENT_CHILD = 'parent-child' // 父子关系\r\n}\r\n\r\n// 连线路径类型枚举\r\nexport enum LinkPathType {\r\n STRAIGHT = 'straight', // 直线\r\n BEZIER = 'bezier', // 贝塞尔曲线\r\n RIGHT_ANGLE = 'right-angle' // 直角连线\r\n}\r\n\r\n// 连线类型颜色配置\r\nexport interface LinkTypeColors {\r\n finishToStart: string; // FS - 完成-开始\r\n startToStart: string; // SS - 开始-开始\r\n finishToFinish: string; // FF - 完成-完成\r\n startToFinish: string; // SF - 开始-完成\r\n}\r\n\r\n// 连线类型显示控制\r\nexport interface LinkTypeVisibility {\r\n finishToStart: boolean; // FS - 完成-开始\r\n startToStart: boolean; // SS - 开始-开始\r\n finishToFinish: boolean; // FF - 完成-完成\r\n startToFinish: boolean; // SF - 开始-完成\r\n parentChild: boolean; // 父子关系\r\n}\r\n\r\n// 基础连线配置接口\r\nexport interface LinkConfig {\r\n color: string;\r\n width: number;\r\n dashArray?: string;\r\n showArrow: boolean;\r\n arrowColor?: string;\r\n arrowSize: number;\r\n showLabels: boolean;\r\n labelColor: string;\r\n labelFontSize: number;\r\n cornerRadius: number;\r\n pathType: LinkPathType;\r\n bezierCurvature: number;\r\n rightAngleOffset: number;\r\n smoothCorners: boolean;\r\n enableDashAnimation: boolean;\r\n dashAnimationSpeed: number;\r\n parentChildStyle: {\r\n color: string;\r\n width: number;\r\n dashArray?: string;\r\n };\r\n linkTypeColors?: LinkTypeColors;\r\n linkTypeVisibility?: LinkTypeVisibility;\r\n}\r\n\r\n// 连线数据接口\r\nexport interface TaskLink {\r\n id: string;\r\n sourceId: string;\r\n targetId: string;\r\n type: LinkType;\r\n label?: string;\r\n path: string;\r\n arrowPoints: string;\r\n labelX: number;\r\n labelY: number;\r\n}\r\n\r\n// 任务依赖关系接口\r\nexport interface TaskDependency {\r\n id: string;\r\n sourceTaskId: string;\r\n targetTaskId: string;\r\n type: LinkType;\r\n lag?: number; // 延迟天数\r\n label?: string;\r\n}\r\n\r\n// 样式配置接口\r\nexport interface StyleConfig {\r\n headersHeight: number;\r\n rowHeight: number;\r\n setBarColor: (row: Record<string, any>) => string;\r\n}\r\n\r\n// 数据配置接口\r\nexport interface DataConfig {\r\n dataSource: any[];\r\n taskHeaders: any[];\r\n mapFields: Record<string, any>;\r\n queryStartDate: string;\r\n queryEndDate: string;\r\n dependencies?: Omit<TaskDependency, 'id'>[];\r\n}\r\n\r\n// 进度更新事件详情接口\r\nexport interface ProgressUpdateDetail {\r\n taskId: any;\r\n oldProgress: number;\r\n newProgress: number;\r\n task: Record<string, any>;\r\n}\r\n\r\n// 事件配置接口\r\nexport interface EventConfig {\r\n addRootTask: (row: Record<string, any> | null) => void;\r\n addSubTask: (task: any) => void;\r\n removeTask: (task: any) => void;\r\n editTask: (task: any) => void;\r\n queryTask: (startDate: string, endDate: string, mode: string) => void;\r\n barDate: (id: any, startDate: string, endDate: string) => void;\r\n allowChangeTaskDate: (allow: boolean) => void;\r\n updateProgress?: (detail: ProgressUpdateDetail) => void;\r\n}\r\n\r\n// 任务表头接口\r\nexport interface TaskHeader {\r\n title: string;\r\n key: string;\r\n width?: number;\r\n align?: 'left' | 'center' | 'right';\r\n}","import { reactive } from 'vue';\r\nimport { LinkType, LinkPathType, type LinkConfig, type TaskDependency } from './Types';\r\n\r\n// 重新导出类型,方便其他组件使用\r\nexport { LinkType, LinkPathType } from './Types';\r\n\r\n// 预定义的连线样式主题\r\nexport const LinkThemes = {\r\n // 默认主题\r\n default: {\r\n color: '#3498db',\r\n width: 2,\r\n dashArray: undefined,\r\n showArrow: true,\r\n arrowColor: undefined,\r\n arrowSize: 8,\r\n showLabels: false,\r\n labelColor: '#666',\r\n labelFontSize: 12,\r\n cornerRadius: 5,\r\n pathType: LinkPathType.BEZIER,\r\n bezierCurvature: 0.4,\r\n rightAngleOffset: 30,\r\n smoothCorners: true,\r\n enableDashAnimation: true,\r\n dashAnimationSpeed: 0.8,\r\n parentChildStyle: {\r\n color: '#95a5a6',\r\n width: 1,\r\n dashArray: '3,3'\r\n },\r\n // 各类型连线颜色\r\n linkTypeColors: {\r\n finishToStart: '#3498db', // 蓝色 - FS\r\n startToStart: '#2ecc71', // 绿色 - SS\r\n finishToFinish: '#e74c3c', // 红色 - FF\r\n startToFinish: '#f39c12' // 橙色 - SF\r\n },\r\n // 各类型连线显示控制\r\n linkTypeVisibility: {\r\n finishToStart: true,\r\n startToStart: true,\r\n finishToFinish: true,\r\n startToFinish: true,\r\n parentChild: true\r\n }\r\n },\r\n \r\n // 商务主题\r\n business: {\r\n color: '#2c3e50',\r\n width: 2,\r\n dashArray: undefined,\r\n showArrow: true,\r\n arrowColor: '#e74c3c',\r\n arrowSize: 10,\r\n showLabels: true,\r\n labelColor: '#34495e',\r\n labelFontSize: 11,\r\n cornerRadius: 8,\r\n pathType: LinkPathType.RIGHT_ANGLE,\r\n bezierCurvature: 0.3,\r\n rightAngleOffset: 40,\r\n smoothCorners: true,\r\n enableDashAnimation: true,\r\n dashAnimationSpeed: 0.6,\r\n parentChildStyle: {\r\n color: '#7f8c8d',\r\n width: 2,\r\n dashArray: '5,2'\r\n },\r\n linkTypeColors: {\r\n finishToStart: '#2c3e50',\r\n startToStart: '#27ae60',\r\n finishToFinish: '#c0392b',\r\n startToFinish: '#d35400'\r\n },\r\n linkTypeVisibility: {\r\n finishToStart: true,\r\n startToStart: true,\r\n finishToFinish: true,\r\n startToFinish: true,\r\n parentChild: true\r\n }\r\n },\r\n \r\n // 现代主题\r\n modern: {\r\n color: '#00bcd4',\r\n width: 3,\r\n dashArray: undefined,\r\n showArrow: true,\r\n arrowColor: '#ff5722',\r\n arrowSize: 12,\r\n showLabels: false,\r\n labelColor: '#607d8b',\r\n labelFontSize: 12,\r\n cornerRadius: 10,\r\n pathType: LinkPathType.BEZIER,\r\n bezierCurvature: 0.6,\r\n rightAngleOffset: 50,\r\n smoothCorners: true,\r\n enableDashAnimation: true,\r\n dashAnimationSpeed: 1,\r\n parentChildStyle: {\r\n color: '#90a4ae',\r\n width: 2,\r\n dashArray: '8,4'\r\n },\r\n linkTypeColors: {\r\n finishToStart: '#00bcd4',\r\n startToStart: '#4caf50',\r\n finishToFinish: '#f44336',\r\n startToFinish: '#ff9800'\r\n },\r\n linkTypeVisibility: {\r\n finishToStart: true,\r\n startToStart: true,\r\n finishToFinish: true,\r\n startToFinish: true,\r\n parentChild: true\r\n }\r\n },\r\n \r\n // 简约主题\r\n minimal: {\r\n color: '#666',\r\n width: 1,\r\n dashArray: undefined,\r\n showArrow: false,\r\n arrowColor: undefined,\r\n arrowSize: 6,\r\n showLabels: false,\r\n labelColor: '#999',\r\n labelFontSize: 10,\r\n cornerRadius: 3,\r\n pathType: LinkPathType.STRAIGHT,\r\n bezierCurvature: 0.2,\r\n rightAngleOffset: 20,\r\n smoothCorners: false,\r\n enableDashAnimation: false,\r\n dashAnimationSpeed: 0.8,\r\n parentChildStyle: {\r\n color: '#ccc',\r\n width: 1,\r\n dashArray: '2,2'\r\n },\r\n linkTypeColors: {\r\n finishToStart: '#666',\r\n startToStart: '#888',\r\n finishToFinish: '#555',\r\n startToFinish: '#777'\r\n },\r\n linkTypeVisibility: {\r\n finishToStart: true,\r\n startToStart: true,\r\n finishToFinish: true,\r\n startToFinish: true,\r\n parentChild: true\r\n }\r\n },\r\n \r\n // 彩色主题\r\n colorful: {\r\n color: '#9c27b0',\r\n width: 2,\r\n dashArray: undefined,\r\n showArrow: true,\r\n arrowColor: '#ff9800',\r\n arrowSize: 9,\r\n showLabels: true,\r\n labelColor: '#673ab7',\r\n labelFontSize: 11,\r\n cornerRadius: 6,\r\n pathType: LinkPathType.RIGHT_ANGLE,\r\n bezierCurvature: 0.5,\r\n rightAngleOffset: 35,\r\n smoothCorners: true,\r\n enableDashAnimation: true,\r\n dashAnimationSpeed: 1,\r\n parentChildStyle: {\r\n color: '#4caf50',\r\n width: 2,\r\n dashArray: '4,3'\r\n },\r\n linkTypeColors: {\r\n finishToStart: '#9c27b0',\r\n startToStart: '#4caf50',\r\n finishToFinish: '#e91e63',\r\n startToFinish: '#ff9800'\r\n },\r\n linkTypeVisibility: {\r\n finishToStart: true,\r\n startToStart: true,\r\n finishToFinish: true,\r\n startToFinish: true,\r\n parentChild: true\r\n }\r\n }\r\n} as const;\r\n\r\n// 连线类型配置\r\nexport const LinkTypeConfig = {\r\n [LinkType.FINISH_TO_START]: {\r\n name: '完成-开始',\r\n description: '前置任务完成后,后续任务才能开始',\r\n color: '#3498db',\r\n priority: 1\r\n },\r\n [LinkType.START_TO_START]: {\r\n name: '开始-开始',\r\n description: '两个任务同时开始',\r\n color: '#2ecc71',\r\n priority: 2\r\n },\r\n [LinkType.FINISH_TO_FINISH]: {\r\n name: '完成-完成',\r\n description: '两个任务同时完成',\r\n color: '#e74c3c',\r\n priority: 3\r\n },\r\n [LinkType.START_TO_FINISH]: {\r\n name: '开始-完成',\r\n description: '前置任务开始后,后续任务才能完成',\r\n color: '#f39c12',\r\n priority: 4\r\n },\r\n [LinkType.PARENT_CHILD]: {\r\n name: '父子关系',\r\n description: '显示任务的层级关系',\r\n color: '#95a5a6',\r\n priority: 0\r\n }\r\n} as const;\r\n\r\n// 全局连线配置管理器\r\nexport class LinkConfigManager {\r\n private config = reactive<LinkConfig>({ ...LinkThemes.default });\r\n private readonly STORAGE_KEY = 'gantt-link-config';\r\n \r\n constructor() {\r\n this.loadFromStorage();\r\n }\r\n \r\n // 从 localStorage 加载配置\r\n private loadFromStorage(): void {\r\n try {\r\n const stored = localStorage.getItem(this.STORAGE_KEY);\r\n if (stored) {\r\n const parsedConfig = JSON.parse(stored);\r\n Object.assign(this.config, parsedConfig);\r\n }\r\n } catch (error) {\r\n console.warn('加载连线配置失败,使用默认配置:', error);\r\n }\r\n }\r\n \r\n // 保存配置到 localStorage\r\n private saveToStorage(): void {\r\n try {\r\n localStorage.setItem(this.STORAGE_KEY, JSON.stringify(this.config));\r\n } catch (error) {\r\n console.warn('保存连线配置失败:', error);\r\n }\r\n }\r\n \r\n // 获取当前配置\r\n getConfig(): LinkConfig {\r\n return this.config;\r\n }\r\n \r\n // 设置主题\r\n setTheme(themeName: keyof typeof LinkThemes): void {\r\n Object.assign(this.config, LinkThemes[themeName]);\r\n this.saveToStorage();\r\n }\r\n \r\n // 更新配置\r\n updateConfig(newConfig: Partial<LinkConfig>): void {\r\n Object.assign(this.config, newConfig);\r\n this.saveToStorage();\r\n }\r\n \r\n // 重置为默认配置\r\n reset(): void {\r\n Object.assign(this.config, LinkThemes.default);\r\n this.saveToStorage();\r\n }\r\n \r\n // 获取特定类型连线的样式\r\n getLinkStyle(linkType: LinkType): Partial<LinkConfig> {\r\n const typeConfig = LinkTypeConfig[linkType];\r\n \r\n if (linkType === LinkType.PARENT_CHILD) {\r\n return {\r\n color: this.config.parentChildStyle.color,\r\n width: this.config.parentChildStyle.width,\r\n dashArray: this.config.parentChildStyle.dashArray\r\n };\r\n }\r\n \r\n return {\r\n color: typeConfig.color,\r\n width: this.config.width,\r\n dashArray: this.config.dashArray\r\n };\r\n }\r\n \r\n // 导出配置\r\n exportConfig(): string {\r\n return JSON.stringify(this.config, null, 2);\r\n }\r\n \r\n // 导入配置\r\n importConfig(configJson: string): boolean {\r\n try {\r\n const importedConfig = JSON.parse(configJson);\r\n this.updateConfig(importedConfig);\r\n return true;\r\n } catch (error) {\r\n console.error('导入配置失败:', error);\r\n return false;\r\n }\r\n }\r\n \r\n // 清除存储的配置\r\n clearStorage(): void {\r\n try {\r\n localStorage.removeItem(this.STORAGE_KEY);\r\n this.reset();\r\n } catch (error) {\r\n console.warn('清除配置失败:', error);\r\n }\r\n }\r\n}\r\n\r\n// 创建全局实例\r\nexport const linkConfigManager = new LinkConfigManager();\r\n\r\n// 连线配置组合式函数\r\nexport function useLinkConfig() {\r\n return {\r\n config: linkConfigManager.getConfig(),\r\n setTheme: linkConfigManager.setTheme.bind(linkConfigManager),\r\n updateConfig: linkConfigManager.updateConfig.bind(linkConfigManager),\r\n reset: linkConfigManager.reset.bind(linkConfigManager),\r\n getLinkStyle: linkConfigManager.getLinkStyle.bind(linkConfigManager),\r\n exportConfig: linkConfigManager.exportConfig.bind(linkConfigManager),\r\n importConfig: linkConfigManager.importConfig.bind(linkConfigManager),\r\n clearStorage: linkConfigManager.clearStorage.bind(linkConfigManager),\r\n themes: LinkThemes,\r\n linkTypes: LinkTypeConfig\r\n };\r\n}\r\n\r\n// 连线数据管理\r\nexport class LinkDataManager {\r\n private dependencies = reactive<TaskDependency[]>([]);\r\n private readonly STORAGE_KEY = 'gantt-link-dependencies';\r\n \r\n constructor() {\r\n this.loadFromStorage();\r\n }\r\n \r\n // 从 localStorage 加载依赖关系\r\n private loadFromStorage(): void {\r\n try {\r\n const stored = localStorage.getItem(this.STORAGE_KEY);\r\n if (stored) {\r\n const parsedDependencies = JSON.parse(stored);\r\n this.dependencies.splice(0, this.dependencies.length, ...parsedDependencies);\r\n }\r\n } catch (error) {\r\n console.warn('加载连线依赖关系失败:', error);\r\n }\r\n }\r\n \r\n // 保存依赖关系到 localStorage\r\n private saveToStorage(): void {\r\n try {\r\n localStorage.setItem(this.STORAGE_KEY, JSON.stringify(this.dependencies));\r\n } catch (error) {\r\n console.warn('保存连线依赖关系失败:', error);\r\n }\r\n }\r\n \r\n // 添加依赖关系\r\n addDependency(dependency: Omit<TaskDependency, 'id'>): string {\r\n const id = `link-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;\r\n this.dependencies.push({ ...dependency, id });\r\n this.saveToStorage();\r\n return id;\r\n }\r\n \r\n // 删除依赖关系\r\n removeDependency(id: string): boolean {\r\n const index = this.dependencies.findIndex(dep => dep.id === id);\r\n if (index > -1) {\r\n this.dependencies.splice(index, 1);\r\n this.saveToStorage();\r\n return true;\r\n }\r\n return false;\r\n }\r\n \r\n // 获取所有依赖关系\r\n getDependencies(): TaskDependency[] {\r\n return this.dependencies;\r\n }\r\n \r\n // 获取任务的依赖关系\r\n getTaskDependencies(taskId: string): TaskDependency[] {\r\n return this.dependencies.filter(dep => \r\n dep.sourceTaskId === taskId || dep.targetTaskId === taskId\r\n );\r\n }\r\n \r\n // 清空所有依赖关系\r\n clear(): void {\r\n this.dependencies.splice(0);\r\n this.saveToStorage();\r\n }\r\n \r\n // 清除存储的依赖关系\r\n clearStorage(): void {\r\n try {\r\n localStorage.removeItem(this.STORAGE_KEY);\r\n this.clear();\r\n } catch (error) {\r\n console.warn('清除依赖关系失败:', error);\r\n }\r\n }\r\n \r\n // 检查是否会形成循环依赖\r\n wouldCreateCycle(sourceId: string, targetId: string): boolean {\r\n const visited = new Set<string>();\r\n const recursionStack = new Set<string>();\r\n \r\n const hasCycle = (nodeId: string): boolean => {\r\n if (recursionStack.has(nodeId)) return true;\r\n if (visited.has(nodeId)) return false;\r\n \r\n visited.add(nodeId);\r\n recursionStack.add(nodeId);\r\n \r\n const dependencies = this.dependencies.filter(dep => dep.sourceTaskId === nodeId);\r\n for (const dep of dependencies) {\r\n if (hasCycle(dep.targetTaskId)) return true;\r\n }\r\n \r\n recursionStack.delete(nodeId);\r\n return false;\r\n };\r\n \r\n // 临时添加新的依赖关系进行检查\r\n this.dependencies.push({\r\n id: 'temp',\r\n sourceTaskId: sourceId,\r\n targetTaskId: targetId,\r\n type: LinkType.FINISH_TO_START\r\n });\r\n \r\n const result = hasCycle(sourceId);\r\n \r\n // 移除临时依赖关系\r\n this.dependencies.pop();\r\n \r\n return result;\r\n }\r\n}\r\n\r\n// 创建全局实例\r\nexport const linkDataManager = new LinkDataManager();\r\n\r\n// 连线数据组合式函数\r\nexport function useLinkData() {\r\n return {\r\n dependencies: linkDataManager.getDependencies(),\r\n addDependency: linkDataManager.addDependency.bind(linkDataManager),\r\n removeDependency: linkDataManager.removeDependency.bind(linkDataManager),\r\n getTaskDependencies: linkDataManager.getTaskDependencies.bind(linkDataManager),\r\n clear: linkDataManager.clear.bind(linkDataManager),\r\n clearStorage: linkDataManager.clearStorage.bind(linkDataManager),\r\n wouldCreateCycle: linkDataManager.wouldCreateCycle.bind(linkDataManager)\r\n };\r\n}","/**\n * 简体中文语言包\n */\nexport default {\n // 通用\n common: {\n confirm: '确定',\n cancel: '取消',\n save: '保存',\n delete: '删除',\n edit: '编辑',\n add: '添加',\n close: '关闭',\n export: '导出',\n import: '导入',\n config: '配置',\n settings: '设置',\n theme: '主题',\n to: '至',\n selectDate: '请选择日期'\n },\n \n // 日期时间\n date: {\n year: '年',\n month: '月',\n day: '日',\n hour: '时',\n week: '周',\n today: '今天',\n monday: '一',\n tuesday: '二',\n wednesday: '三',\n thursday: '四',\n friday: '五',\n saturday: '六',\n sunday: '日',\n january: '一月',\n february: '二月',\n march: '三月',\n april: '四月',\n may: '五月',\n june: '六月',\n july: '七月',\n august: '八月',\n september: '九月',\n october: '十月',\n november: '十一月',\n december: '十二月'\n },\n \n // 日期格式\n dateFormat: {\n full: 'YYYY年MM月DD日',\n short: 'YYYY-MM-DD',\n monthDay: 'MM月DD日',\n yearMonth: 'YYYY年MM月'\n },\n \n // 视图模式\n viewMode: {\n month: '月',\n week: '周',\n day: '日',\n hour: '时'\n },\n \n // 任务\n task: {\n addRoot: '添加根任务',\n addSub: '添加子任务',\n remove: '删除任务',\n edit: '编辑任务',\n name: '任务名称',\n priority: '优先级',\n startDate: '开始时间',\n endDate: '结束时间',\n duration: '耗时',\n progress: '进度',\n serialNumber: '序号'\n },\n \n // 连线图例\n link: {\n legend: '连线图例',\n parentChild: '父子关系',\n finishToStart: '完成-开始',\n startToStart: '开始-开始',\n finishToFinish: '完成-完成',\n startToFinish: '开始-完成',\n fs: 'FS',\n ss: 'SS',\n ff: 'FF',\n sf: 'SF',\n pc: 'PC'\n },\n \n // 配置面板\n configPanel: {\n title: '甘特图配置',\n themeSettings: '主题设置',\n linkSettings: '连线设置',\n languageSettings: '语言设置',\n currentTheme: '当前',\n previewTheme: '预览',\n exportConfig: '导出配置',\n importConfig: '导入配置',\n \n // 连线配置\n linkConfig: {\n info: '以下配置用于任务依赖连线(完成-开始、开始-开始等关系)',\n pathType: '路径类型',\n straight: '直线',\n bezier: '贝塞尔',\n rightAngle: '直角',\n color: '颜色',\n width: '线宽',\n dashStyle: '虚线样式',\n solid: '实线',\n shortDash: '短虚线',\n mediumDash: '中虚线',\n longDash: '长虚线',\n dotDash: '点划线',\n curvature: '弯曲度',\n offset: '偏移距离',\n smoothCorners: '平滑转角',\n cornerRadius: '转角半径',\n showArrow: '显示箭头',\n arrowSize: '箭头大小',\n arrowColor: '箭头颜色',\n syncColor: '同步',\n dashAnimation: '虚线流动动画',\n animationSpeed: '动画速度',\n showLabels: '显示标签',\n labelColor: '标签颜色',\n fontSize: '字体大小',\n typeColors: '依赖类型颜色',\n parentChildStyle: '父子关系连线样式',\n parentChildInfo: '用于显示父任务与子任务之间的层级结构关系'\n }\n },\n \n // 主题\n theme: {\n metro: 'Metro 金属质感',\n light: '浅色主题',\n dark: '深色主题',\n colorful: '多彩主题',\n ocean: '海洋主题',\n apple: 'Apple 苹果风格',\n classic: '经典商务',\n metroDesc: '经典 Windows Metro 风格',\n lightDesc: '清爽明亮的浅色风格',\n darkDesc: '优雅专业的深色风格',\n colorfulDesc: '活力四射的多彩风格',\n oceanDesc: '沉静舒适的海洋风格',\n appleDesc: '简约优雅的 macOS 风格',\n classicDesc: '传统稳重的商务风格'\n },\n \n // 日期选择器\n datePicker: {\n selectDate: '请选择日期',\n clearDate: '清除日期'\n },\n \n // 提示信息\n tooltip: {\n addSubTask: '添加子任务',\n removeTask: '删除当前任务',\n syncArrowColor: '与线条颜色同步',\n close: '关闭'\n }\n};\n","/**\r\n * English language pack\r\n */\r\nexport default {\r\n // Common\r\n common: {\r\n confirm: 'Confirm',\r\n cancel: 'Cancel',\r\n save: 'Save',\r\n delete: 'Delete',\r\n edit: 'Edit',\r\n add: 'Add',\r\n close: 'Close',\r\n export: 'Export',\r\n import: 'Import',\r\n config: 'Config',\r\n settings: 'Settings',\r\n theme: 'Theme',\r\n to: 'to',\r\n selectDate: 'Select Date'\r\n },\r\n \r\n // Date & Time\r\n date: {\r\n year: 'Year',\r\n month: 'Month',\r\n day: 'Day',\r\n hour: 'Hour',\r\n week: 'Week',\r\n today: 'Today',\r\n monday: 'Mon',\r\n tuesday: 'Tue',\r\n wednesday: 'Wed',\r\n thursday: 'Thu',\r\n friday: 'Fri',\r\n saturday: 'Sat',\r\n sunday: 'Sun',\r\n january: 'January',\r\n february: 'February',\r\n march: 'March',\r\n april: 'April',\r\n may: 'May',\r\n june: 'June',\r\n july: 'July',\r\n august: 'August',\r\n september: 'September',\r\n october: 'October',\r\n november: 'November',\r\n december: 'December'\r\n },\r\n \r\n // Date Format\r\n dateFormat: {\r\n full: 'MMMM DD, YYYY',\r\n short: 'MM/DD/YYYY',\r\n monthDay: 'MMM DD',\r\n yearMonth: 'MMMM YYYY'\r\n },\r\n \r\n // View Mode\r\n viewMode: {\r\n month: 'Month',\r\n week: 'Week',\r\n day: 'Day',\r\n hour: 'Hour'\r\n },\r\n \r\n // Task\r\n task: {\r\n addRoot: 'Add Root Task',\r\n addSub: 'Add Sub Task',\r\n remove: 'Delete Task',\r\n edit: 'Edit Task',\r\n name: 'Task Name',\r\n priority: 'Priority',\r\n startDate: 'Start Date',\r\n endDate: 'End Date',\r\n duration: 'Duration',\r\n progress: 'Progress',\r\n serialNumber: 'No.'\r\n },\r\n \r\n // Link Legend\r\n link: {\r\n legend: 'Link Legend',\r\n parentChild: 'Parent-Child',\r\n finishToStart: 'Finish-to-Start',\r\n startToStart: 'Start-to-Start',\r\n finishToFinish: 'Finish-to-Finish',\r\n startToFinish: 'Start-to-Finish',\r\n fs: 'FS',\r\n ss: 'SS',\r\n ff: 'FF',\r\n sf: 'SF',\r\n pc: 'PC'\r\n },\r\n \r\n // Config Panel\r\n configPanel: {\r\n title: 'Gantt Configuration',\r\n themeSettings: 'Theme Settings',\r\n linkSettings: 'Link Settings',\r\n languageSettings: 'Language Settings',\r\n currentTheme: 'Current',\r\n previewTheme: 'Preview',\r\n exportConfig: 'Export Config',\r\n importConfig: 'Import Config',\r\n \r\n // Link Configuration\r\n linkConfig: {\r\n info: 'Configure task dependency links (Finish-to-Start, Start-to-Start, etc.)',\r\n pathType: 'Path Type',\r\n straight: 'Straight',\r\n bezier: 'Bezier',\r\n rightAngle: 'Right Angle',\r\n color: 'Color',\r\n width: 'Line Width',\r\n dashStyle: 'Dash Style',\r\n solid: 'Solid',\r\n shortDash: 'Short Dash',\r\n mediumDash: 'Medium Dash',\r\n longDash: 'Long Dash',\r\n dotDash: 'Dot Dash',\r\n curvature: 'Curvature',\r\n offset: 'Offset Distance',\r\n smoothCorners: 'Smooth Corners',\r\n cornerRadius: 'Corner Radius',\r\n showArrow: 'Show Arrow',\r\n arrowSize: 'Arrow Size',\r\n arrowColor: 'Arrow Color',\r\n syncColor: 'Sync',\r\n dashAnimation: 'Dash Animation',\r\n animationSpeed: 'Animation Speed',\r\n showLabels: 'Show Labels',\r\n labelColor: 'Label Color',\r\n fontSize: 'Font Size',\r\n typeColors: 'Dependency Type Colors',\r\n parentChildStyle: 'Parent-Child Link Style',\r\n parentChildInfo: 'Display hierarchical relationship between parent and child tasks'\r\n }\r\n },\r\n \r\n // Theme\r\n theme: {\r\n metro: 'Metro',\r\n light: 'Light',\r\n dark: 'Dark',\r\n colorful: 'Colorful',\r\n ocean: 'Ocean',\r\n apple: 'Apple',\r\n classic: 'Classic',\r\n metroDesc: 'Classic Windows Metro style',\r\n lightDesc: 'Fresh and bright light style',\r\n darkDesc: 'Elegant and professional dark style',\r\n colorfulDesc: 'Vibrant and colorful style',\r\n oceanDesc: 'Calm and comfortable ocean style',\r\n appleDesc: 'Minimalist and elegant macOS style',\r\n classicDesc: 'Traditional and stable business style'\r\n },\r\n \r\n // Date Picker\r\n datePicker: {\r\n selectDate: 'Select Date',\r\n clearDate: 'Clear Date'\r\n },\r\n \r\n // Tooltip\r\n tooltip: {\r\n addSubTask: 'Add Sub Task',\r\n removeTask: 'Delete Current Task',\r\n syncArrowColor: 'Sync with line color',\r\n close: 'Close'\r\n }\r\n};\r\n","/**\r\n * Japanese language pack\r\n * 日本語言語パック\r\n */\r\nexport default {\r\n // Common\r\n common: {\r\n confirm: '確認',\r\n cancel: 'キャンセル',\r\n save: '保存',\r\n delete: '削除',\r\n edit: '編集',\r\n add: '追加',\r\n close: '閉じる',\r\n export: 'エクスポート',\r\n import: 'インポート',\r\n config: '設定',\r\n settings: '設定',\r\n theme: 'テーマ',\r\n to: 'から',\r\n selectDate: '日付を選択'\r\n },\r\n \r\n // Date & Time\r\n date: {\r\n year: '年',\r\n month: '月',\r\n day: '日',\r\n hour: '時',\r\n week: '週',\r\n today: '今日',\r\n monday: '月',\r\n tuesday: '火',\r\n wednesday: '水',\r\n thursday: '木',\r\n friday: '金',\r\n saturday: '土',\r\n sunday: '日',\r\n january: '1月',\r\n february: '2月',\r\n march: '3月',\r\n april: '4月',\r\n may: '5月',\r\n june: '6月',\r\n july: '7月',\r\n august: '8月',\r\n september: '9月',\r\n october: '10月',\r\n november: '11月',\r\n december: '12月'\r\n },\r\n \r\n // Date Format\r\n dateFormat: {\r\n full: 'YYYY年MM月DD日',\r\n short: 'YYYY/MM/DD',\r\n monthDay: 'MM月DD日',\r\n yearMonth: 'YYYY年MM月'\r\n },\r\n \r\n // View Mode\r\n viewMode: {\r\n month: '月',\r\n week: '週',\r\n day: '日',\r\n hour: '時'\r\n },\r\n \r\n // Task\r\n task: {\r\n addRoot: 'ルートタスクを追加',\r\n addSub: 'サブタスクを追加',\r\n remove: 'タスクを削除',\r\n edit: 'タスクを編集',\r\n name: 'タスク名',\r\n priority: '優先度',\r\n startDate: '開始日',\r\n endDate: '終了日',\r\n duration: '期間',\r\n progress: '進捗',\r\n serialNumber: '番号'\r\n },\r\n \r\n // Link Legend\r\n link: {\r\n legend: 'リンク凡例',\r\n parentChild: '親子関係',\r\n finishToStart: '終了-開始',\r\n startToStart: '開始-開始',\r\n finishToFinish: '終了-終了',\r\n startToFinish: '開始-終了',\r\n fs: 'FS',\r\n ss: 'SS',\r\n ff: 'FF',\r\n sf: 'SF',\r\n pc: 'PC'\r\n },\r\n \r\n // Config Panel\r\n configPanel: {\r\n title: 'ガントチャート設定',\r\n themeSettings: 'テーマ設定',\r\n linkSettings: 'リンク設定',\r\n languageSettings: '言語設定',\r\n currentTheme: '現在',\r\n previewTheme: 'プレビュー',\r\n exportConfig: '設定をエクスポート',\r\n importConfig: '設定をインポート',\r\n \r\n // Link Configuration\r\n linkConfig: {\r\n info: 'タスク依存関係リンク(終了-開始、開始-開始など)を設定',\r\n pathType: 'パスタイプ',\r\n straight: '直線',\r\n bezier: 'ベジェ曲線',\r\n rightAngle: '直角',\r\n color: '色',\r\n width: '線の太さ',\r\n dashStyle: '破線スタイル',\r\n solid: '実線',\r\n shortDash: '短い破線',\r\n mediumDash: '中破線',\r\n longDash: '長い破線',\r\n dotDash: '点線破線',\r\n curvature: '曲率',\r\n offset: 'オフセット距離',\r\n smoothCorners: '滑らかな角',\r\n cornerRadius: '角の半径',\r\n showArrow: '矢印を表示',\r\n arrowSize: '矢印サイズ',\r\n arrowColor: '矢印の色',\r\n syncColor: '同期',\r\n dashAnimation: '破線アニメーション',\r\n animationSpeed: 'アニメーション速度',\r\n showLabels: 'ラベルを表示',\r\n labelColor: 'ラベルの色',\r\n fontSize: 'フォントサイズ',\r\n typeColors: '依存関係タイプの色',\r\n parentChildStyle: '親子リンクスタイル',\r\n parentChildInfo: '親タスクと子タスクの階層関係を表示'\r\n }\r\n },\r\n \r\n // Theme\r\n theme: {\r\n metro: 'メトロ',\r\n light: 'ライト',\r\n dark: 'ダーク',\r\n colorful: 'カラフル',\r\n ocean: 'オーシャン',\r\n apple: 'Apple',\r\n classic: 'クラシック',\r\n metroDesc: 'クラシックWindowsメトロスタイル',\r\n lightDesc: '明るく爽やかなライトスタイル',\r\n darkDesc: 'エレガントでプロフェッショナルなダークスタイル',\r\n colorfulDesc: '活気あるカラフルスタイル',\r\n oceanDesc: '落ち着いた快適なオーシャンスタイル',\r\n appleDesc: 'ミニマルでエレガントなmacOSスタイル',\r\n classicDesc: '伝統的で安定感のあるビジネススタイル'\r\n },\r\n \r\n // Date Picker\r\n datePicker: {\r\n selectDate: '日付を選択',\r\n clearDate: '日付をクリア'\r\n },\r\n \r\n // Tooltip\r\n tooltip: {\r\n addSubTask: 'サブタスクを追加',\r\n removeTask: '現在のタスクを削除',\r\n syncArrowColor: '線の色と同期',\r\n close: '閉じる'\r\n }\r\n};\r\n","/**\n * Korean language pack\n * 한국어 언어 팩\n */\nexport default {\n // Common\n common: {\n confirm: '확인',\n cancel: '취소',\n save: '저장',\n delete: '삭제',\n edit: '편집',\n add: '추가',\n close: '닫기',\n export: '내보내기',\n import: '가져오기',\n config: '설정',\n settings: '설정',\n theme: '테마',\n to: '에서',\n selectDate: '날짜 선택'\n },\n \n // Date & Time\n date: {\n year: '년',\n month: '월',\n day: '일',\n hour: '시',\n week: '주',\n today: '오늘',\n monday: '월',\n tuesday: '화',\n wednesday: '수',\n thursday: '목',\n friday: '금',\n saturday: '토',\n sunday: '일',\n january: '1월',\n february: '2월',\n march: '3월',\n april: '4월',\n may: '5월',\n june: '6월',\n july: '7월',\n august: '8월',\n september: '9월',\n october: '10월',\n november: '11월',\n december: '12월'\n },\n \n // Date Format\n dateFormat: {\n full: 'YYYY년 MM월 DD일',\n short: 'YYYY-MM-DD',\n monthDay: 'MM월 DD일',\n yearMonth: 'YYYY년 MM월'\n },\n \n // View Mode\n viewMode: {\n month: '월',\n week: '주',\n day: '일',\n hour: '시'\n },\n \n // Task\n task: {\n addRoot: '루트 작업 추가',\n addSub: '하위 작업 추가',\n remove: '작업 삭제',\n edit: '작업 편집',\n name: '작업 이름',\n priority: '우선순위',\n startDate: '시작일',\n endDate: '종료일',\n duration: '기간',\n progress: '진행률',\n serialNumber: '번호'\n },\n \n // Link Legend\n link: {\n legend: '링크 범례',\n parentChild: '부모-자식',\n finishToStart: '종료-시작',\n startToStart: '시작-시작',\n finishToFinish: '종료-종료',\n startToFinish: '시작-종료',\n fs: 'FS',\n ss: 'SS',\n ff: 'FF',\n sf: 'SF',\n pc: 'PC'\n },\n \n // Config Panel\n configPanel: {\n title: '간트 차트 설정',\n themeSettings: '테마 설정',\n linkSettings: '링크 설정',\n languageSettings: '언어 설정',\n currentTheme: '현재',\n previewTheme: '미리보기',\n exportConfig: '설정 내보내기',\n importConfig: '설정 가져오기',\n \n // Link Configuration\n linkConfig: {\n info: '작업 종속성 링크 설정 (종료-시작, 시작-시작 등)',\n pathType: '경로 유형',\n straight: '직선',\n bezier: '베지어 곡선',\n rightAngle: '직각',\n color: '색상',\n width: '선 두께',\n dashStyle: '파선 스타일',\n solid: '실선',\n shortDash: '짧은 파선',\n mediumDash: '중간 파선',\n longDash: '긴 파선',\n dotDash: '점선 파선',\n curvature: '곡률',\n offset: '오프셋 거리',\n smoothCorners: '부드러운 모서리',\n cornerRadius: '모서리 반경',\n showArrow: '화살표 표시',\n arrowSize: '화살표 크기',\n arrowColor: '화살표 색상',\n syncColor: '동기화',\n dashAnimation: '파선 애니메이션',\n animationSpeed: '애니메이션 속도',\n showLabels: '레이블 표시',\n labelColor: '레이블 색상',\n fontSize: '글꼴 크기',\n typeColors: '종속성 유형 색상',\n parentChildStyle: '부모-자식 링크 스타일',\n parentChildInfo: '부모 작업과 자식 작업의 계층 관계 표시'\n }\n },\n \n // Theme\n theme: {\n metro: '메트로',\n light: '라이트',\n dark: '다크',\n colorful: '컬러풀',\n ocean: '오션',\n apple: 'Apple',\n classic: '클래식',\n metroDesc: '클래식 Windows 메트로 스타일',\n lightDesc: '밝고 상쾌한 라이트 스타일',\n darkDesc: '우아하고 전문적인 다크 스타일',\n colorfulDesc: '활기찬 컬러풀 스타일',\n oceanDesc: '차분하고 편안한 오션 스타일',\n appleDesc: '미니멀하고 우아한 macOS 스타일',\n classicDesc: '전통적이고 안정적인 비즈니스 스타일'\n },\n \n // Date Picker\n datePicker: {\n selectDate: '날짜 선택',\n clearDate: '날짜 지우기'\n },\n \n // Tooltip\n tooltip: {\n addSubTask: '하위 작업 추가',\n removeTask: '현재 작업 삭제',\n syncArrowColor: '선 색상과 동기화',\n close: '닫기'\n }\n};\n","/**\n * French language pack\n * Pack de langue française\n */\nexport default {\n // Common\n common: {\n confirm: 'Confirmer',\n cancel: 'Annuler',\n save: 'Enregistrer',\n delete: 'Supprimer',\n edit: 'Modifier',\n add: 'Ajouter',\n close: 'Fermer',\n export: 'Exporter',\n import: 'Importer',\n config: 'Configuration',\n settings: 'Paramètres',\n theme: 'Thème',\n to: 'à',\n selectDate: 'Sélectionner la date'\n },\n \n // Date & Time\n date: {\n year: 'Année',\n month: 'Mois',\n day: 'Jour',\n hour: 'Heure',\n week: 'Semaine',\n today: \"Aujourd'hui\",\n monday: 'Lun',\n tuesday: 'Mar',\n wednesday: 'Mer',\n thursday: 'Jeu',\n friday: 'Ven',\n saturday: 'Sam',\n sunday: 'Dim',\n january: 'Janvier',\n february: 'Février',\n march: 'Mars',\n april: 'Avril',\n may: 'Mai',\n june: 'Juin',\n july: 'Juillet',\n august: 'Août',\n september: 'Septembre',\n october: 'Octobre',\n november: 'Novembre',\n december: 'Décembre'\n },\n \n // Date Format\n dateFormat: {\n full: 'DD MMMM YYYY',\n short: 'DD/MM/YYYY',\n monthDay: 'DD MMM',\n yearMonth: 'MMMM YYYY'\n },\n \n // View Mode\n viewMode: {\n month: 'Mois',\n week: 'Semaine',\n day: 'Jour',\n hour: 'Heure'\n },\n \n // Task\n task: {\n addRoot: 'Ajouter une tâche racine',\n addSub: 'Ajouter une sous-tâche',\n remove: 'Supprimer la tâche',\n edit: 'Modifier la tâche',\n name: 'Nom de la tâche',\n priority: 'Priorité',\n startDate: 'Date de début',\n endDate: 'Date de fin',\n duration: 'Durée',\n progress: 'Progrès',\n serialNumber: 'N°'\n },\n \n // Link Legend\n link: {\n legend: 'Légende des liens',\n parentChild: 'Parent-Enfant',\n finishToStart: 'Fin-Début',\n startToStart: 'Début-Début',\n finishToFinish: 'Fin-Fin',\n startToFinish: 'Début-Fin',\n fs: 'FD',\n ss: 'DD',\n ff: 'FF',\n sf: 'DF',\n pc: 'PE'\n },\n \n // Config Panel\n configPanel: {\n title: 'Configuration Gantt',\n themeSettings: 'Paramètres du thème',\n linkSettings: 'Paramètres des liens',\n languageSettings: 'Paramètres de langue',\n currentTheme: 'Actuel',\n previewTheme: 'Aperçu',\n exportConfig: 'Exporter la configuration',\n importConfig: 'Importer la configuration',\n \n // Link Configuration\n linkConfig: {\n info: 'Configurer les liens de dépendance des tâches (Fin-Début, Début-Début, etc.)',\n pathType: 'Type de chemin',\n straight: 'Droit',\n bezier: 'Bézier',\n rightAngle: 'Angle droit',\n color: 'Couleur',\n width: 'Épaisseur de ligne',\n dashStyle: 'Style de tiret',\n solid: 'Solide',\n shortDash: 'Tiret court',\n mediumDash: 'Tiret moyen',\n longDash: 'Tiret long',\n dotDash: 'Point-tiret',\n curvature: 'Courbure',\n offset: 'Distance de décalage',\n smoothCorners: 'Coins lisses',\n cornerRadius: 'Rayon du coin',\n showArrow: 'Afficher la flèche',\n arrowSize: 'Taille de la flèche',\n arrowColor: 'Couleur de la flèche',\n syncColor: 'Synchroniser',\n dashAnimation: 'Animation de tiret',\n animationSpeed: \"Vitesse d'animation\",\n showLabels: 'Afficher les étiquettes',\n labelColor: \"Couleur de l'étiquette\",\n fontSize: 'Taille de police',\n typeColors: 'Couleurs des types de dépendance',\n parentChildStyle: 'Style de lien parent-enfant',\n parentChildInfo: 'Afficher la relation hiérarchique entre les tâches parent et enfant'\n }\n },\n \n // Theme\n theme: {\n metro: 'Metro',\n light: 'Clair',\n dark: 'Sombre',\n colorful: 'Coloré',\n ocean: 'Océan',\n apple: 'Apple',\n classic: 'Classique',\n metroDesc: 'Style Metro Windows classique',\n lightDesc: 'Style clair frais et lumineux',\n darkDesc: 'Style sombre élégant et professionnel',\n colorfulDesc: 'Style coloré vibrant',\n oceanDesc: 'Style océan calme et confortable',\n appleDesc: 'Style macOS minimaliste et élégant',\n classicDesc: 'Style business traditionnel et stable'\n },\n \n // Date Picker\n datePicker: {\n selectDate: 'Sélectionner la date',\n clearDate: 'Effacer la date'\n },\n \n // Tooltip\n tooltip: {\n addSubTask: 'Ajouter une sous-tâche',\n removeTask: 'Supprimer la tâche actuelle',\n syncArrowColor: 'Synchroniser avec la couleur de la ligne',\n close: 'Fermer'\n }\n};\n","/**\r\n * German language pack\r\n * Deutsches Sprachpaket\r\n */\r\nexport default {\r\n // Common\r\n common: {\r\n confirm: 'Bestätigen',\r\n cancel: 'Abbrechen',\r\n save: 'Speichern',\r\n delete: 'Löschen',\r\n edit: 'Bearbeiten',\r\n add: 'Hinzufügen',\r\n close: 'Schließen',\r\n export: 'Exportieren',\r\n import: 'Importieren',\r\n config: 'Konfiguration',\r\n settings: 'Einstellungen',\r\n theme: 'Thema',\r\n to: 'bis',\r\n selectDate: 'Datum auswählen'\r\n },\r\n \r\n // Date & Time\r\n date: {\r\n year: 'Jahr',\r\n month: 'Monat',\r\n day: 'Tag',\r\n hour: 'Stunde',\r\n week: 'Woche',\r\n today: 'Heute',\r\n monday: 'Mo',\r\n tuesday: 'Di',\r\n wednesday: 'Mi',\r\n thursday: 'Do',\r\n friday: 'Fr',\r\n saturday: 'Sa',\r\n sunday: 'So',\r\n january: 'Januar',\r\n february: 'Februar',\r\n march: 'März',\r\n april: 'April',\r\n may: 'Mai',\r\n june: 'Juni',\r\n july: 'Juli',\r\n august: 'August',\r\n september: 'September',\r\n october: 'Oktober',\r\n november: 'November',\r\n december: 'Dezember'\r\n },\r\n \r\n // Date Format\r\n dateFormat: {\r\n full: 'DD. MMMM YYYY',\r\n short: 'DD.MM.YYYY',\r\n monthDay: 'DD. MMM',\r\n yearMonth: 'MMMM YYYY'\r\n },\r\n \r\n // View Mode\r\n viewMode: {\r\n month: 'Monat',\r\n week: 'Woche',\r\n day: 'Tag',\r\n hour: 'Stunde'\r\n },\r\n \r\n // Task\r\n task: {\r\n addRoot: 'Hauptaufgabe hinzufügen',\r\n addSub: 'Unteraufgabe hinzufügen',\r\n remove: 'Aufgabe löschen',\r\n edit: 'Aufgabe bearbeiten',\r\n name: 'Aufgabenname',\r\n priority: 'Priorität',\r\n startDate: 'Startdatum',\r\n endDate: 'Enddatum',\r\n duration: 'Dauer',\r\n progress: 'Fortschritt',\r\n serialNumber: 'Nr.'\r\n },\r\n \r\n // Link Legend\r\n link: {\r\n legend: 'Verknüpfungslegende',\r\n parentChild: 'Übergeordnet-Untergeordnet',\r\n finishToStart: 'Ende-Anfang',\r\n startToStart: 'Anfang-Anfang',\r\n finishToFinish: 'Ende-Ende',\r\n startToFinish: 'Anfang-Ende',\r\n fs: 'EA',\r\n ss: 'AA',\r\n ff: 'EE',\r\n sf: 'AE',\r\n pc: 'ÜU'\r\n },\r\n \r\n // Config Panel\r\n configPanel: {\r\n title: 'Gantt-Konfiguration',\r\n themeSettings: 'Themeneinstellungen',\r\n linkSettings: 'Verknüpfungseinstellungen',\r\n languageSettings: 'Spracheinstellungen',\r\n currentTheme: 'Aktuell',\r\n previewTheme: 'Vorschau',\r\n exportConfig: 'Konfiguration exportieren',\r\n importConfig: 'Konfiguration importieren',\r\n \r\n // Link Configuration\r\n linkConfig: {\r\n info: 'Aufgabenabhängigkeitsverknüpfungen konfigurieren (Ende-Anfang, Anfang-Anfang usw.)',\r\n pathType: 'Pfadtyp',\r\n straight: 'Gerade',\r\n bezier: 'Bézier',\r\n rightAngle: 'Rechter Winkel',\r\n color: 'Farbe',\r\n width: 'Linienstärke',\r\n dashStyle: 'Strichstil',\r\n solid: 'Durchgezogen',\r\n shortDash: 'Kurzer Strich',\r\n mediumDash: 'Mittlerer Strich',\r\n longDash: 'Langer Strich',\r\n dotDash: 'Punkt-Strich',\r\n curvature: 'Krümmung',\r\n offset: 'Versatzabstand',\r\n smoothCorners: 'Glatte Ecken',\r\n cornerRadius: 'Eckenradius',\r\n showArrow: 'Pfeil anzeigen',\r\n arrowSize: 'Pfeilgröße',\r\n arrowColor: 'Pfeilfarbe',\r\n syncColor: 'Synchronisieren',\r\n dashAnimation: 'Strich-Animation',\r\n animationSpeed: 'Animationsgeschwindigkeit',\r\n showLabels: 'Beschriftungen anzeigen',\r\n labelColor: 'Beschriftungsfarbe',\r\n fontSize: 'Schriftgröße',\r\n typeColors: 'Abhängigkeitstypfarben',\r\n parentChildStyle: 'Übergeordnet-Untergeordnet-Verknüpfungsstil',\r\n parentChildInfo: 'Hierarchische Beziehung zwischen übergeordneten und untergeordneten Aufgaben anzeigen'\r\n }\r\n },\r\n \r\n // Theme\r\n theme: {\r\n metro: 'Metro',\r\n light: 'Hell',\r\n dark: 'Dunkel',\r\n colorful: 'Farbenfroh',\r\n ocean: 'Ozean',\r\n apple: 'Apple',\r\n classic: 'Klassisch',\r\n metroDesc: 'Klassischer Windows Metro-Stil',\r\n lightDesc: 'Frischer und heller Stil',\r\n darkDesc: 'Eleganter und professioneller dunkler Stil',\r\n colorfulDesc: 'Lebendiger farbenfroher Stil',\r\n oceanDesc: 'Ruhiger und komfortabler Ozean-Stil',\r\n appleDesc: 'Minimalistischer und eleganter macOS-Stil',\r\n classicDesc: 'Traditioneller und stabiler Geschäftsstil'\r\n },\r\n \r\n // Date Picker\r\n datePicker: {\r\n selectDate: 'Datum auswählen',\r\n clearDate: 'Datum löschen'\r\n },\r\n \r\n // Tooltip\r\n tooltip: {\r\n addSubTask: 'Unteraufgabe hinzufügen',\r\n removeTask: 'Aktuelle Aufgabe löschen',\r\n syncArrowColor: 'Mit Linienfarbe synchronisieren',\r\n close: 'Schließen'\r\n }\r\n};\r\n","/**\n * Spanish language pack\n * Paquete de idioma español\n */\nexport default {\n // Common\n common: {\n confirm: 'Confirmar',\n cancel: 'Cancelar',\n save: 'Guardar',\n delete: 'Eliminar',\n edit: 'Editar',\n add: 'Agregar',\n close: 'Cerrar',\n export: 'Exportar',\n import: 'Importar',\n config: 'Configuración',\n settings: 'Ajustes',\n theme: 'Tema',\n to: 'a',\n selectDate: 'Seleccionar fecha'\n },\n \n // Date & Time\n date: {\n year: 'Año',\n month: 'Mes',\n day: 'Día',\n hour: 'Hora',\n week: 'Semana',\n today: 'Hoy',\n monday: 'Lun',\n tuesday: 'Mar',\n wednesday: 'Mié',\n thursday: 'Jue',\n friday: 'Vie',\n saturday: 'Sáb',\n sunday: 'Dom',\n january: 'Enero',\n february: 'Febrero',\n march: 'Marzo',\n april: 'Abril',\n may: 'Mayo',\n june: 'Junio',\n july: 'Julio',\n august: 'Agosto',\n september: 'Septiembre',\n october: 'Octubre',\n november: 'Noviembre',\n december: 'Diciembre'\n },\n \n // Date Format\n dateFormat: {\n full: 'DD [de] MMMM [de] YYYY',\n short: 'DD/MM/YYYY',\n monthDay: 'DD MMM',\n yearMonth: 'MMMM YYYY'\n },\n \n // View Mode\n viewMode: {\n month: 'Mes',\n week: 'Semana',\n day: 'Día',\n hour: 'Hora'\n },\n \n // Task\n task: {\n addRoot: 'Agregar tarea raíz',\n addSub: 'Agregar subtarea',\n remove: 'Eliminar tarea',\n edit: 'Editar tarea',\n name: 'Nombre de tarea',\n priority: 'Prioridad',\n startDate: 'Fecha de inicio',\n endDate: 'Fecha de fin',\n duration: 'Duración',\n progress: 'Progreso',\n serialNumber: 'Nº'\n },\n \n // Link Legend\n link: {\n legend: 'Leyenda de enlaces',\n parentChild: 'Padre-Hijo',\n finishToStart: 'Fin-Inicio',\n startToStart: 'Inicio-Inicio',\n finishToFinish: 'Fin-Fin',\n startToFinish: 'Inicio-Fin',\n fs: 'FI',\n ss: 'II',\n ff: 'FF',\n sf: 'IF',\n pc: 'PH'\n },\n \n // Config Panel\n configPanel: {\n title: 'Configuración Gantt',\n themeSettings: 'Configuración de tema',\n linkSettings: 'Configuración de enlaces',\n languageSettings: 'Configuración de idioma',\n currentTheme: 'Actual',\n previewTheme: 'Vista previa',\n exportConfig: 'Exportar configuración',\n importConfig: 'Importar configuración',\n \n // Link Configuration\n linkConfig: {\n info: 'Configurar enlaces de dependencia de tareas (Fin-Inicio, Inicio-Inicio, etc.)',\n pathType: 'Tipo de ruta',\n straight: 'Recta',\n bezier: 'Bézier',\n rightAngle: 'Ángulo recto',\n color: 'Color',\n width: 'Grosor de línea',\n dashStyle: 'Estilo de guión',\n solid: 'Sólido',\n shortDash: 'Guión corto',\n mediumDash: 'Guión medio',\n longDash: 'Guión largo',\n dotDash: 'Punto-guión',\n curvature: 'Curvatura',\n offset: 'Distancia de desplazamiento',\n smoothCorners: 'Esquinas suaves',\n cornerRadius: 'Radio de esquina',\n showArrow: 'Mostrar flecha',\n arrowSize: 'Tamaño de flecha',\n arrowColor: 'Color de flecha',\n syncColor: 'Sincronizar',\n dashAnimation: 'Animación de guión',\n animationSpeed: 'Velocidad de animación',\n showLabels: 'Mostrar etiquetas',\n labelColor: 'Color de etiqueta',\n fontSize: 'Tamaño de fuente',\n typeColors: 'Colores de tipo de dependencia',\n parentChildStyle: 'Estilo de enlace padre-hijo',\n parentChildInfo: 'Mostrar relación jerárquica entre tareas padre e hijo'\n }\n },\n \n // Theme\n theme: {\n metro: 'Metro',\n light: 'Claro',\n dark: 'Oscuro',\n colorful: 'Colorido',\n ocean: 'Océano',\n apple: 'Apple',\n classic: 'Clásico',\n metroDesc: 'Estilo Metro Windows clásico',\n lightDesc: 'Estilo claro fresco y brillante',\n darkDesc: 'Estilo oscuro elegante y profesional',\n colorfulDesc: 'Estilo colorido vibrante',\n oceanDesc: 'Estilo océano tranquilo y cómodo',\n appleDesc: 'Estilo macOS minimalista y elegante',\n classicDesc: 'Estilo empresarial tradicional y estable'\n },\n \n // Date Picker\n datePicker: {\n selectDate: 'Seleccionar fecha',\n clearDate: 'Borrar fecha'\n },\n \n // Tooltip\n tooltip: {\n addSubTask: 'Agregar subtarea',\n removeTask: 'Eliminar tarea actual',\n syncArrowColor: 'Sincronizar con color de línea',\n close: 'Cerrar'\n }\n};\n","/**\r\n * Russian language pack\r\n * Русский языковой пакет\r\n */\r\nexport default {\r\n // Common\r\n common: {\r\n confirm: 'Подтвердить',\r\n cancel: 'Отмена',\r\n save: 'Сохранить',\r\n delete: 'Удалить',\r\n edit: 'Редактировать',\r\n add: 'Добавить',\r\n close: 'Закрыть',\r\n export: 'Экспорт',\r\n import: 'Импорт',\r\n config: 'Конфигурация',\r\n settings: 'Настройки',\r\n theme: 'Тема',\r\n to: 'до',\r\n selectDate: 'Выбрать дату'\r\n },\r\n \r\n // Date & Time\r\n date: {\r\n year: 'Год',\r\n month: 'Месяц',\r\n day: 'День',\r\n hour: 'Час',\r\n week: 'Неделя',\r\n today: 'Сегодня',\r\n monday: 'Пн',\r\n tuesday: 'Вт',\r\n wednesday: 'Ср',\r\n thursday: 'Чт',\r\n friday: 'Пт',\r\n saturday: 'Сб',\r\n sunday: 'Вс',\r\n january: 'Январь',\r\n february: 'Февраль',\r\n march: 'Март',\r\n april: 'Апрель',\r\n may: 'Май',\r\n june: 'Июнь',\r\n july: 'Июль',\r\n august: 'Август',\r\n september: 'Сентябрь',\r\n october: 'Октябрь',\r\n november: 'Ноябрь',\r\n december: 'Декабрь'\r\n },\r\n \r\n // Date Format\r\n dateFormat: {\r\n full: 'DD MMMM YYYY г.',\r\n short: 'DD.MM.YYYY',\r\n monthDay: 'DD MMM',\r\n yearMonth: 'MMMM YYYY'\r\n },\r\n \r\n // View Mode\r\n viewMode: {\r\n month: 'Месяц',\r\n week: 'Неделя',\r\n day: 'День',\r\n hour: 'Час'\r\n },\r\n \r\n // Task\r\n task: {\r\n addRoot: 'Добавить корневую задачу',\r\n addSub: 'Добавить подзадачу',\r\n remove: 'Удалить задачу',\r\n edit: 'Редактировать задачу',\r\n name: 'Название задачи',\r\n priority: 'Приоритет',\r\n startDate: 'Дата начала',\r\n endDate: 'Дата окончания',\r\n duration: 'Длительность',\r\n progress: 'Прогресс',\r\n serialNumber: '№'\r\n },\r\n \r\n // Link Legend\r\n link: {\r\n legend: 'Легенда связей',\r\n parentChild: 'Родитель-Потомок',\r\n finishToStart: 'Окончание-Начало',\r\n startToStart: 'Начало-Начало',\r\n finishToFinish: 'Окончание-Окончание',\r\n startToFinish: 'Начало-Окончание',\r\n fs: 'ОН',\r\n ss: 'НН',\r\n ff: 'ОО',\r\n sf: 'НО',\r\n pc: 'РП'\r\n },\r\n \r\n // Config Panel\r\n configPanel: {\r\n title: 'Конфигурация Gantt',\r\n themeSettings: 'Настройки темы',\r\n linkSettings: 'Настройки связей',\r\n languageSettings: 'Настройки языка',\r\n currentTheme: 'Текущая',\r\n previewTheme: 'Предпросмотр',\r\n exportConfig: 'Экспорт конфигурации',\r\n importConfig: 'Импорт конфигурации',\r\n \r\n // Link Configuration\r\n linkConfig: {\r\n info: 'Настройка связей зависимостей задач (Окончание-Начало, Начало-Начало и т.д.)',\r\n pathType: 'Тип пути',\r\n straight: 'Прямая',\r\n bezier: 'Безье',\r\n rightAngle: 'Прямой угол',\r\n color: 'Цвет',\r\n width: 'Толщина линии',\r\n dashStyle: 'Стиль пунктира',\r\n solid: 'Сплошная',\r\n shortDash: 'Короткий пунктир',\r\n mediumDash: 'Средний пунктир',\r\n longDash: 'Длинный пунктир',\r\n dotDash: 'Точка-тире',\r\n curvature: 'Кривизна',\r\n offset: 'Расстояние смещения',\r\n smoothCorners: 'Сглаженные углы',\r\n cornerRadius: 'Радиус угла',\r\n showArrow: 'Показать стрелку',\r\n arrowSize: 'Размер стрелки',\r\n arrowColor: 'Цвет стрелки',\r\n syncColor: 'Синхронизировать',\r\n dashAnimation: 'Анимация пунктира',\r\n animationSpeed: 'Скорость анимации',\r\n showLabels: 'Показать метки',\r\n labelColor: 'Цвет метки',\r\n fontSize: 'Размер шрифта',\r\n typeColors: 'Цвета типов зависимостей',\r\n parentChildStyle: 'Стиль связи родитель-потомок',\r\n parentChildInfo: 'Показать иерархическую связь между родительскими и дочерними задачами'\r\n }\r\n },\r\n \r\n // Theme\r\n theme: {\r\n metro: 'Метро',\r\n light: 'Светлая',\r\n dark: 'Темная',\r\n colorful: 'Красочная',\r\n ocean: 'Океан',\r\n apple: 'Apple',\r\n classic: 'Классический',\r\n metroDesc: 'Классический стиль Windows Metro',\r\n lightDesc: 'Свежий и яркий светлый стиль',\r\n darkDesc: 'Элегантный и профессиональный темный стиль',\r\n colorfulDesc: 'Яркий красочный стиль',\r\n oceanDesc: 'Спокойный и комфортный океанский стиль',\r\n appleDesc: 'Минималистичный и элегантный стиль macOS',\r\n classicDesc: 'Традиционный и стабильный деловой стиль'\r\n },\r\n \r\n // Date Picker\r\n datePicker: {\r\n selectDate: 'Выбрать дату',\r\n clearDate: 'Очистить дату'\r\n },\r\n \r\n // Tooltip\r\n tooltip: {\r\n addSubTask: 'Добавить подзадачу',\r\n removeTask: 'Удалить текущую задачу',\r\n syncArrowColor: 'Синхронизировать с цветом линии',\r\n close: 'Закрыть'\r\n }\r\n};\r\n","/**\n * 甘特图国际化系统\n * 支持中文、英文等多语言切换\n */\n\nimport { ref, computed } from 'vue';\nimport zhCN from './locales/zh-CN';\nimport enUS from './locales/en-US';\nimport jaJP from './locales/ja-JP';\nimport koKR from './locales/ko-KR';\nimport frFR from './locales/fr-FR';\nimport deDE from './locales/de-DE';\nimport esES from './locales/es-ES';\nimport ruRU from './locales/ru-RU';\n\n// 支持的语言类型\nexport type Locale = 'zh-CN' | 'en-US' | 'ja-JP' | 'ko-KR' | 'fr-FR' | 'de-DE' | 'es-ES' | 'ru-RU';\n\n// 语言包类型\nexport type Messages = typeof zhCN;\n\n// 所有语言包\nconst messages: Record<Locale, Messages> = {\n 'zh-CN': zhCN,\n 'en-US': enUS,\n 'ja-JP': jaJP,\n 'ko-KR': koKR,\n 'fr-FR': frFR,\n 'de-DE': deDE,\n 'es-ES': esES,\n 'ru-RU': ruRU\n};\n\n// 当前语言\nconst currentLocale = ref<Locale>('zh-CN');\n\n// 从localStorage读取保存的语言设置\nconst savedLocale = localStorage.getItem('gantt-locale') as Locale;\nif (savedLocale && messages[savedLocale]) {\n currentLocale.value = savedLocale;\n}\n\n/**\n * 获取翻译文本\n * @param key 翻译键,支持点号路径如 'common.confirm'\n * @returns 翻译后的文本\n */\nexport function t(key: string): string {\n const keys = key.split('.');\n let value: any = messages[currentLocale.value];\n \n for (const k of keys) {\n if (value && typeof value === 'object') {\n value = value[k];\n } else {\n return key; // 如果找不到,返回原key\n }\n }\n \n return typeof value === 'string' ? value : key;\n}\n\n/**\n * 设置当前语言\n * @param locale 语言代码\n */\nexport function setLocale(locale: Locale) {\n if (messages[locale]) {\n currentLocale.value = locale;\n localStorage.setItem('gantt-locale', locale);\n }\n}\n\n/**\n * 获取当前语言\n */\nexport function getLocale(): Locale {\n return currentLocale.value;\n}\n\n/**\n * 获取所有支持的语言\n */\nexport function getLocales(): { value: Locale; label: string }[] {\n return [\n { value: 'zh-CN', label: '🇨🇳 简体中文' },\n { value: 'en-US', label: '🇺🇸 English' },\n { value: 'ja-JP', label: '🇯🇵 日本語' },\n { value: 'ko-KR', label: '🇰🇷 한국어' },\n { value: 'fr-FR', label: '🇫🇷 Français' },\n { value: 'de-DE', label: '🇩🇪 Deutsch' },\n { value: 'es-ES', label: '🇪🇸 Español' },\n { value: 'ru-RU', label: '🇷🇺 Русский' }\n ];\n}\n\n/**\n * 创建响应式i18n hook\n */\nexport function useI18n() {\n const locale = computed(() => currentLocale.value);\n \n return {\n locale,\n t,\n setLocale,\n getLocale,\n getLocales\n };\n}\n\nexport default {\n t,\n setLocale,\n getLocale,\n getLocales,\n useI18n\n};\n","<template>\r\n <div>\r\n <!-- 添加文本框 -->\r\n <div class=\"date-picker-input-wrapper\">\r\n <input type=\"text\" v-model=\"selectedDateText\" @click=\"showCalendar = true\" readonly :placeholder=\"t('datePicker.selectDate')\"\r\n class=\"date-picker-input\" ref=\"inputRef\" />\r\n <span class=\"clear-date-button\" @click=\"clearDate\" v-if=\"selectedDateText\">\r\n <svg viewBox=\"0 0 24 24\">\r\n <path\r\n d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\">\r\n </path>\r\n </svg>\r\n </span>\r\n </div>\r\n <!-- 日期选择器 -->\r\n <div class=\"e-calendar\" v-show=\"showCalendar\" ref=\"calendarRef\">\r\n <div class=\"e-date-select\">\r\n <div class=\"e-date-year\">\r\n <transition name=\"fadeY\">\r\n <div :key=\"selectDate.year\" class=\"e-date-year-select\" @click=\"openYearList\" :class=\"{ active: showYear }\">\r\n {{ selectDate.year }}\r\n </div>\r\n </transition>\r\n </div>\r\n <div class=\"e-date-monthday\">\r\n <transition name=\"fadeY\">\r\n <div :key=\"selectDate.day\" class=\"e-date-monthday-select\" :class=\"{ active: !showYear }\"\r\n @click=\"openCalendarList\">\r\n <span>{{ keepDoubleDigit(selectDate.month) }}-{{ keepDoubleDigit(selectDate.day) }}</span> \r\n <span style=\"cursor: pointer;\" @click=\"openMonthList\">{{ showDate.monthStr }}</span>\r\n </div>\r\n </transition>\r\n </div>\r\n </div>\r\n\r\n <div class=\"e-calendar-container\" v-show=\"!showYear && !showMonth\">\r\n <div class=\"e-calendar-toolbar\">\r\n <div class=\"e-calendar-svg\" @click=\"prevMonth\">\r\n <svg viewBox=\"0 0 24 24\" class=\"e-calendar-svg-icon\">\r\n <path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"></path>\r\n </svg>\r\n <transition name=\"e_calendar_svg_btn\">\r\n <div class=\"e-calendar-svg-cover\" v-if=\"prevMonthClick\"></div>\r\n </transition>\r\n </div>\r\n <div class=\"e-calendar-toolbar-title\">\r\n <transition :name=\"fadeXType\">\r\n <div :key=\"showDate.monthStr\" class=\"e-calendar-toolbar-title-content\">\r\n <strong>{{ showDate.year }}</strong> \r\n <span style=\"cursor: pointer;\" @click=\"openMonthList\">{{ showDate.monthStr }}</span>\r\n </div>\r\n </transition>\r\n </div>\r\n <div class=\"e-calendar-svg\" @click=\"nextMonth\">\r\n <svg viewBox=\"0 0 24 24\" class=\"e-calendar-svg-icon\">\r\n <path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"></path>\r\n </svg>\r\n <transition name=\"e_calendar_svg_btn\">\r\n <div class=\"e-calendar-svg-cover\" v-if=\"nextMonthClick\"></div>\r\n </transition>\r\n </div>\r\n </div>\r\n <div class=\"e-calendar-week\">\r\n <span v-for=\"(weekName, index) in getWeekNames\" :key=\"index\" class=\"e-calendar-week-day\">{{ weekName }}</span>\r\n </div>\r\n <div class=\"e-calendar-monthday\">\r\n <transition :name=\"fadeXType\">\r\n <div :key=\"showDate.monthStr\" class=\"e-calendar-monthday-wrapper\">\r\n <div v-for=\"(row, index) in rows\" :key=\"index\" class=\"e-calendar-monthday-row\">\r\n <span v-for=\"(day, dayIndex) in row\" :key=\"dayIndex\" class=\"e-calendar-monthday-row-day\"\r\n @click=\"selectDay(day)\" @mouseenter=\"handleDayMouseEnter(dayIndex, index)\"\r\n @mouseleave=\"handleDayMouseLeave()\" :class=\"{\r\n active: day.selected,\r\n disabled: day.disabled,\r\n pointer: day.value !== '',\r\n hover: isDayHovered(dayIndex, index)\r\n }\">\r\n <span v-text=\"day.value\" class=\"e-calendar-monthday-row-day-value\"></span>\r\n <transition name=\"e_calendar_day\">\r\n <span class=\"e-calendar-monthday-row-day-cover\" v-if=\"day.selected\"></span>\r\n </transition>\r\n </span>\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n </div>\r\n <ul class=\"e-calendar-year\" v-show=\"showYear\" ref=\"yearList\">\r\n <li v-for=\"(item, index) in yearList\" :key=\"index\" :class=\"{\r\n active: item === selectDate.year,\r\n hover: isYearHovered(index)\r\n }\" @click=\"selectYear(item)\" @mouseenter=\"handleYearMouseEnter(index)\" @mouseleave=\"handleYearMouseLeave()\">\r\n {{ item }}\r\n </li>\r\n </ul>\r\n <ul class=\"e-calendar-year\" v-show=\"showMonth\" ref=\"monthList\">\r\n <li v-for=\"(item, index) in monthList\" :key=\"index\" :class=\"{\r\n active: item === selectDate.month,\r\n hover: isMonthHovered(index)\r\n }\" @click=\"selectMonth(item)\" @mouseenter=\"handleMonthMouseEnter(index)\" @mouseleave=\"handleMonthMouseLeave()\">\r\n {{ getMonthName(item) }}\r\n </li>\r\n </ul>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed, onBeforeMount, onMounted, onUnmounted, watchEffect, watch } from 'vue';\r\nimport { useI18n } from './i18n';\r\nimport dayjs from 'dayjs';\r\nimport 'dayjs/locale/zh-cn';\r\nimport 'dayjs/locale/en';\r\nimport 'dayjs/locale/ja';\r\nimport 'dayjs/locale/ko';\r\nimport 'dayjs/locale/fr';\r\nimport 'dayjs/locale/de';\r\nimport 'dayjs/locale/es';\r\nimport 'dayjs/locale/ru';\r\n\r\nexport default defineComponent({\r\n props: {\r\n // 打开date picker的初始值,必传,格式是(2017-08-11)\r\n date: {\r\n type: String,\r\n required: true,\r\n },\r\n // 日期最小值\r\n minDate: String,\r\n // 日期最大值\r\n maxDate: String,\r\n },\r\n setup(props, { emit }) {\r\n const { t, locale } = useI18n();\r\n \r\n // 获取 dayjs locale\r\n const getDayjsLocale = () => {\r\n const localeMap: Record<string, string> = {\r\n 'zh-CN': 'zh-cn',\r\n 'en-US': 'en',\r\n 'ja-JP': 'ja',\r\n 'ko-KR': 'ko',\r\n 'fr-FR': 'fr',\r\n 'de-DE': 'de',\r\n 'es-ES': 'es',\r\n 'ru-RU': 'ru'\r\n };\r\n return localeMap[locale.value] || 'en';\r\n };\r\n \r\n // 获取星期名称\r\n const getWeekNames = computed(() => {\r\n const dayjsLocale = getDayjsLocale();\r\n const weekNames = [];\r\n for (let i = 1; i <= 7; i++) {\r\n // 使用 dayjs 获取本地化的星期名称(简写)\r\n const day = dayjs().day(i).locale(dayjsLocale);\r\n weekNames.push(day.format('dd'));\r\n }\r\n return weekNames;\r\n });\r\n \r\n // 获取月份名称\r\n const getMonthName = (month: number) => {\r\n const dayjsLocale = getDayjsLocale();\r\n return dayjs().month(month - 1).locale(dayjsLocale).format('MMMM');\r\n };\r\n \r\n // 定义响应式数据\r\n let selectDate = ref({\r\n year: 0,\r\n month: 0,\r\n day: 0,\r\n week: 0,\r\n date: '',\r\n weekStr: '',\r\n monthStr: '',\r\n });\r\n let showDate = ref({\r\n year: 0,\r\n month: 0,\r\n day: 0,\r\n week: 0,\r\n date: '',\r\n monthStr: '',\r\n weekStr: '',\r\n });\r\n let copyMinDate = ref({\r\n year: 0,\r\n month: 0,\r\n day: 0,\r\n });\r\n let copyMaxDate = ref({\r\n year: 0,\r\n month: 0,\r\n day: 0,\r\n });\r\n\r\n const fadeXType = ref('fadeX_Prev');\r\n const nextMonthClick = ref(false);\r\n const prevMonthClick = ref(false);\r\n const showYear = ref(false);\r\n const showMonth = ref(false);\r\n const yearListRef = ref<HTMLUListElement | null>(null);\r\n const monthListRef = ref<HTMLUListElement | null>(null);\r\n const showCalendar = ref(false); // 控制日期选择器的显示和隐藏\r\n const selectedDateText = ref(''); // 文本框显示的日期\r\n const calendarRef = ref<HTMLDivElement | null>(null); // 日期组件的引用\r\n const inputRef = ref<HTMLInputElement | null>(null); // 新增文本框引用\r\n\r\n const hoveredYearIndex = ref(-1);\r\n const hoveredMonthIndex = ref(-1);\r\n const hoveredDayIndex = ref({ row: -1, col: -1 });\r\n\r\n const yearList = computed(() => {\r\n const result: number[] = [];\r\n for (let i = copyMinDate.value.year; i <= copyMaxDate.value.year; i += 1) {\r\n result.push(i);\r\n }\r\n return result;\r\n });\r\n\r\n const monthList = computed(() => {\r\n const result: number[] = [];\r\n for (let i = 1; i <= 12; i += 1) {\r\n result.push(i);\r\n }\r\n return result;\r\n });\r\n\r\n const rows = computed(() => {\r\n const { year, month } = showDate.value;\r\n const months = new Date(year, month, 0).getDate();\r\n const result: {\r\n value: number | string;\r\n selected?: boolean;\r\n disabled?: boolean;\r\n }[][] = [];\r\n let row: {\r\n value: number | string;\r\n selected?: boolean;\r\n disabled?: boolean;\r\n }[] = [];\r\n let weekValue: number;\r\n // 按照星期分组\r\n for (let i = 1; i <= months; i += 1) {\r\n // 根据日期获取星期,并让开头是1,而非0\r\n weekValue = new Date(year, month - 1, i).getDay() + 1;\r\n // 判断月第一天在星期几,并填充前面的空白区域\r\n if (i === 1 && weekValue !== 1) {\r\n addRowEmptyValue(row, weekValue);\r\n addRowDayValue(row, i);\r\n } else {\r\n addRowDayValue(row, i);\r\n // 判断月最后一天在星期几,并填充后面的空白区域\r\n if (i === months && weekValue !== 7) {\r\n addRowEmptyValue(row, (7 - weekValue) + 1);\r\n }\r\n }\r\n // 按照一周分组\r\n if (weekValue % 7 === 0 || i === months) {\r\n result.push(row);\r\n row = [];\r\n }\r\n }\r\n showDate.value.monthStr = getMonthName(showDate.value.month);\r\n return result;\r\n });\r\n\r\n // 定义函数,接收一个 number 类型的参数,返回一个 string 类型的值\r\n const keepDoubleDigit = (number: number): string => {\r\n // 判断传入的数字是否大于 9\r\n return number > 9 ? String(number) : `0${number}`;\r\n };\r\n\r\n // 拆分日期\r\n const splitDate = (date: string, addStr = false) => {\r\n let result: {\r\n year: number;\r\n month: number;\r\n day: number;\r\n week?: number;\r\n monthStr?: string;\r\n weekStr?: string;\r\n } = {\r\n year: 0,\r\n month: 0,\r\n day: 0,\r\n };\r\n const splitValue = date.split('-');\r\n try {\r\n if (!splitValue || splitValue.length < 3) {\r\n throw new Error('时间格式不正确');\r\n }\r\n result = {\r\n year: Number(splitValue[0]),\r\n month: Number(splitValue[1]),\r\n day: Number(splitValue[2]),\r\n };\r\n if (addStr) {\r\n result.week = new Date(result.year, result.month - 1, result.day).getDay() + 1;\r\n result.monthStr = getMonthName(result.month);\r\n const dayjsLocale = getDayjsLocale();\r\n result.weekStr = dayjs().day(result.week).locale(dayjsLocale).format('dddd');\r\n }\r\n } catch (error) {\r\n console.error(error);\r\n }\r\n return result;\r\n };\r\n\r\n // 初始化日期选择器\r\n const initDatePicker = () => {\r\n const splitResult = splitDate(props.date, true);\r\n showDate.value = {\r\n ...splitResult,\r\n date: `${splitResult.year}-${keepDoubleDigit(splitResult.month)}-${keepDoubleDigit(\r\n splitResult.day\r\n )}`,\r\n week: splitResult.week || 0,\r\n monthStr: splitResult.monthStr || '',\r\n weekStr: splitResult.weekStr || '',\r\n };\r\n copyMinDate.value = { ...splitDate(props.minDate || '1970-01-01') };\r\n copyMaxDate.value = { ...splitDate(props.maxDate || '2099-12-31') };\r\n selectDate.value = { ...showDate.value };\r\n \r\n // 使用国际化日期格式\r\n const dayjsLocale = getDayjsLocale();\r\n const dateObj = dayjs(showDate.value.date).locale(dayjsLocale);\r\n const dateFormat = t('dateFormat.full');\r\n selectedDateText.value = dateObj.format(dateFormat);\r\n };\r\n\r\n watchEffect(() => {\r\n if (props.date) {\r\n initDatePicker(); // 当 props.date 变化时重新初始化日期选择器\r\n }\r\n });\r\n\r\n onBeforeMount(() => {\r\n initDatePicker();\r\n });\r\n\r\n // 添加空值\r\n const addRowEmptyValue = (\r\n row: {\r\n value: number | string;\r\n selected?: boolean;\r\n disabled?: boolean;\r\n }[],\r\n count: number\r\n ) => {\r\n for (let w = 1; w < count; w += 1) {\r\n row.push({\r\n value: '',\r\n });\r\n }\r\n };\r\n\r\n // 添加日期值\r\n const addRowDayValue = (\r\n row: {\r\n value: number | string;\r\n selected?: boolean;\r\n disabled?: boolean;\r\n }[],\r\n i: number\r\n ) => {\r\n const value = { value: i };\r\n const { day, month, year } = selectDate.value;\r\n const showDateValue = showDate.value;\r\n // 判断已经选择的\r\n if (year === showDateValue.year && month === showDateValue.month && day === i) {\r\n // 为对象添加 selected 属性\r\n const newValue = { ...value, selected: true };\r\n row.push(newValue);\r\n return; // 添加 return 避免重复添加\r\n }\r\n // 当日期在最小值之外,禁止点击\r\n if (isMinLimitMonth() && i < copyMinDate.value.day) {\r\n // 修复:添加 disabled 属性\r\n const newValue = { ...value, disabled: true };\r\n row.push(newValue);\r\n return; // 添加 return 避免重复添加\r\n }\r\n // 当日期在最大值之外,禁止点击\r\n if (isMaxLimitMonth() && i > copyMaxDate.value.day) {\r\n // 修复:添加 disabled 属性\r\n const newValue = { ...value, disabled: true };\r\n row.push(newValue);\r\n return; // 添加 return 避免重复添加\r\n }\r\n row.push(value);\r\n };\r\n\r\n // 切换到上一个月\r\n const prevMonth = () => {\r\n if (prevMonthClick.value) {\r\n return;\r\n }\r\n prevMonthClick.value = true;\r\n setTimeout(() => {\r\n prevMonthClick.value = false;\r\n }, 500);\r\n fadeXType.value = 'fadeX_Prev';\r\n // 如何当前月份已经小于等于minMonth 就不让其在执行\r\n if (isMinLimitMonth()) {\r\n return;\r\n }\r\n const { year, month } = showDate.value;\r\n // 判断当前月份,如果已经等于1(1就是一月,而不是二月)\r\n if (month <= 1) {\r\n showDate.value.year = year - 1;\r\n showDate.value.month = 12;\r\n } else {\r\n showDate.value.month -= 1;\r\n }\r\n };\r\n\r\n // 切换到下一个月\r\n const nextMonth = () => {\r\n if (nextMonthClick.value) {\r\n return;\r\n }\r\n nextMonthClick.value = true;\r\n setTimeout(() => {\r\n nextMonthClick.value = false;\r\n }, 500);\r\n fadeXType.value = 'fadeX_Next';\r\n // 如何当前月份已经大于等于maxMonth 就不让其在执行\r\n if (isMaxLimitMonth()) {\r\n return;\r\n }\r\n const { year, month } = showDate.value;\r\n // 判断当前月份,如果已经等于12(12就是十二月)\r\n if (month >= 12) {\r\n showDate.value.year = year + 1;\r\n showDate.value.month = 1;\r\n } else {\r\n showDate.value.month += 1;\r\n }\r\n };\r\n\r\n // 重置选择日期\r\n let resetSelectDate = (dayValue: number) => {\r\n // 修改为逐个修改属性\r\n selectDate.value.year = showDate.value.year;\r\n selectDate.value.month = showDate.value.month;\r\n selectDate.value.week = showDate.value.week;\r\n selectDate.value.date = showDate.value.date;\r\n selectDate.value.weekStr = showDate.value.weekStr;\r\n selectDate.value.monthStr = showDate.value.monthStr;\r\n selectDate.value.day = dayValue;\r\n selectDate.value.week = new Date(showDate.value.year, showDate.value.month - 1, dayValue).getDay() + 1;\r\n const dayjsLocale = getDayjsLocale();\r\n selectDate.value.weekStr = dayjs().day(selectDate.value.week).locale(dayjsLocale).format('dddd');\r\n \r\n // 使用国际化日期格式\r\n const dateObj = dayjs(`${selectDate.value.year}-${keepDoubleDigit(selectDate.value.month)}-${keepDoubleDigit(selectDate.value.day)}`).locale(dayjsLocale);\r\n const dateFormat = t('dateFormat.full');\r\n selectedDateText.value = dateObj.format(dateFormat);\r\n \r\n showCalendar.value = false; // 选择日期后隐藏日期选择器\r\n };\r\n\r\n // 选择日期\r\n const selectDay = (days: { value: number | string; disabled?: boolean }) => {\r\n if (days.disabled || days.value === '') {\r\n return;\r\n }\r\n resetSelectDate(Number(days.value));\r\n const { year, month, day, week, weekStr, monthStr } = selectDate.value;\r\n emit('confirm', {\r\n date: `${year}-${keepDoubleDigit(month)}-${keepDoubleDigit(day)}`,\r\n year,\r\n month,\r\n week,\r\n monthStr,\r\n weekStr,\r\n day,\r\n });\r\n };\r\n\r\n // 选择月份\r\n const selectMonth = (value: number) => {\r\n showYear.value = false;\r\n showMonth.value = false;\r\n showDate.value.month = value;\r\n let type: 'copyMinDate' | 'copyMaxDate' | undefined;\r\n // 当月份在最小值之外,日期换成最小值日期 或者 当月份在最大值之外,日期换成最大值日期\r\n if (isMinLimitMonth()) {\r\n type = 'copyMinDate';\r\n } else if (isMaxLimitMonth()) {\r\n type = 'copyMaxDate';\r\n }\r\n if (type) {\r\n showDate.value.day = type === 'copyMinDate' ? copyMinDate.value.day : copyMaxDate.value.day;\r\n resetSelectDate(showDate.value.day);\r\n return;\r\n }\r\n let dayValue = selectDate.value.day;\r\n // 判断日是最大值,防止另一个月没有这个日期\r\n const daysInMonth = new Date(showDate.value.year, showDate.value.month + 1, 0).getDate();\r\n dayValue = Math.min(dayValue, daysInMonth); // 确保日期不超过当前月份的最大天数\r\n resetSelectDate(dayValue);\r\n };\r\n\r\n // 选择年份\r\n const selectYear = (value: number) => {\r\n showYear.value = false;\r\n showMonth.value = false;\r\n showDate.value.year = value;\r\n let type: 'copyMinDate' | 'copyMaxDate' | undefined;\r\n // 当日期在最小值之外,月份换成最小值月份 或者 当日期在最大值之外,月份换成最大值月份\r\n if (isMinLimitMonth()) {\r\n type = 'copyMinDate';\r\n } else if (isMaxLimitMonth()) {\r\n type = 'copyMaxDate';\r\n }\r\n if (type) {\r\n showDate.value.month = type === 'copyMinDate' ? copyMinDate.value.month : copyMaxDate.value.month;\r\n showDate.value.day = type === 'copyMinDate' ? copyMinDate.value.day : copyMaxDate.value.day;\r\n resetSelectDate(showDate.value.day);\r\n return;\r\n }\r\n let dayValue = selectDate.value.day;\r\n // 判断日是最大值,防止另一个月没有这个日期\r\n const months = new Date(showDate.value.year, showDate.value.month, 0).getDate();\r\n dayValue = Math.min(dayValue, months); // 确保日期不超过当前月份的最大天数\r\n resetSelectDate(dayValue);\r\n };\r\n\r\n // 判断是否为最小月份限制\r\n const isMinLimitMonth = () => {\r\n return showDate.value.year <= copyMinDate.value.year && showDate.value.month <= copyMinDate.value.month;\r\n };\r\n\r\n // 判断是否为最大月份限制\r\n const isMaxLimitMonth = () => {\r\n return showDate.value.year >= copyMaxDate.value.year && showDate.value.month >= copyMaxDate.value.month;\r\n };\r\n\r\n // 打开年份列表\r\n const openYearList = () => {\r\n if (showYear.value) {\r\n showYear.value = false;\r\n showMonth.value = false;\r\n return;\r\n }\r\n const index = yearList.value.indexOf(selectDate.value.year);\r\n showYear.value = true;\r\n showMonth.value = false;\r\n setTimeout(() => {\r\n if (yearListRef.value) {\r\n yearListRef.value.scrollTop = (index - 3) * 40;\r\n }\r\n });\r\n };\r\n\r\n // 打开月份列表\r\n const openMonthList = () => {\r\n if (showMonth.value) {\r\n showYear.value = false;\r\n showMonth.value = false;\r\n return;\r\n }\r\n const index = monthList.value.indexOf(selectDate.value.month);\r\n showMonth.value = true;\r\n showYear.value = false;\r\n setTimeout(() => {\r\n if (monthListRef.value) {\r\n monthListRef.value.scrollTop = (index - 3) * 20;\r\n }\r\n });\r\n };\r\n\r\n const openCalendarList = () => {\r\n showYear.value = false;\r\n };\r\n\r\n // 清除日期的方法\r\n const clearDate = () => {\r\n selectedDateText.value = '';\r\n showCalendar.value = false;\r\n };\r\n\r\n // 点击文本框和日期组件以外的区域,隐藏日期组件\r\n const handleClickOutside = (event: MouseEvent) => {\r\n if (\r\n calendarRef.value &&\r\n inputRef.value &&\r\n !calendarRef.value.contains(event.target as Node) &&\r\n !inputRef.value.contains(event.target as Node)\r\n ) {\r\n showCalendar.value = false;\r\n }\r\n };\r\n\r\n const isYearHovered = (index: number) => hoveredYearIndex.value === index;\r\n const isMonthHovered = (index: number) => hoveredMonthIndex.value === index;\r\n const isDayHovered = (col: number, row: number) =>\r\n hoveredDayIndex.value.row === row && hoveredDayIndex.value.col === col;\r\n\r\n const handleYearMouseEnter = (index: number) => {\r\n hoveredYearIndex.value = index;\r\n };\r\n\r\n const handleYearMouseLeave = () => {\r\n hoveredYearIndex.value = -1;\r\n };\r\n\r\n const handleMonthMouseEnter = (index: number) => {\r\n hoveredMonthIndex.value = index;\r\n };\r\n\r\n const handleMonthMouseLeave = () => {\r\n hoveredMonthIndex.value = -1;\r\n };\r\n\r\n const handleDayMouseEnter = (col: number, row: number) => {\r\n hoveredDayIndex.value = { row, col };\r\n };\r\n\r\n const handleDayMouseLeave = () => {\r\n hoveredDayIndex.value = { row: -1, col: -1 };\r\n };\r\n\r\n onMounted(() => {\r\n document.addEventListener('click', handleClickOutside);\r\n });\r\n\r\n onUnmounted(() => {\r\n document.removeEventListener('click', handleClickOutside);\r\n });\r\n\r\n return {\r\n t,\r\n locale,\r\n getWeekNames,\r\n getMonthName,\r\n selectDate,\r\n showDate,\r\n copyMinDate,\r\n copyMaxDate,\r\n fadeXType,\r\n nextMonthClick,\r\n prevMonthClick,\r\n keepDoubleDigit,\r\n showYear,\r\n yearList,\r\n rows,\r\n yearListRef,\r\n prevMonth,\r\n nextMonth,\r\n selectDay,\r\n selectYear,\r\n openYearList,\r\n openMonthList,\r\n monthList,\r\n monthListRef,\r\n showMonth,\r\n selectMonth,\r\n openCalendarList,\r\n showCalendar,\r\n selectedDateText,\r\n clearDate,\r\n calendarRef,\r\n inputRef,\r\n isYearHovered,\r\n isMonthHovered,\r\n isDayHovered,\r\n handleYearMouseEnter,\r\n handleYearMouseLeave,\r\n handleMonthMouseEnter,\r\n handleMonthMouseLeave,\r\n handleDayMouseEnter,\r\n handleDayMouseLeave\r\n };\r\n },\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.e-calendar {\r\n background: var(--bg-content);\r\n width: 310px;\r\n border: 1px solid var(--border);\r\n box-shadow: var(--shadow-outset);\r\n z-index: 999;\r\n position: absolute;\r\n font-family: var(--font-family);\r\n}\r\n\r\n.e-date-select {\r\n background: var(--bg-active);\r\n padding: 12px 20px;\r\n color: var(--text-white);\r\n font-weight: 600;\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n box-shadow: var(--shadow-active);\r\n}\r\n\r\n.date-picker-input-wrapper {\r\n position: relative;\r\n display: inline-block;\r\n}\r\n\r\n.date-picker-input {\r\n width: 200px;\r\n padding: 8px 12px;\r\n background: var(--bg-content);\r\n border: 1px solid var(--border);\r\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\r\n font-family: inherit;\r\n font-size: 14px;\r\n color: var(--text-primary);\r\n transition: all var(--transition-fast);\r\n border-radius: 0;\r\n}\r\n\r\n.date-picker-input:focus {\r\n outline: none;\r\n border-color: var(--primary);\r\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(0, 120, 212, 0.2);\r\n}\r\n\r\n.clear-date-button {\r\n position: absolute;\r\n right: 8px;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n cursor: pointer;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n background: var(--bg-metal-normal);\r\n border: 1px solid var(--border);\r\n transition: all var(--transition-fast);\r\n}\r\n\r\n.clear-date-button:hover {\r\n background: var(--bg-metal-light);\r\n}\r\n\r\n.clear-date-button svg {\r\n fill: var(--text-secondary);\r\n width: 14px;\r\n height: 14px;\r\n transition: fill var(--transition-fast);\r\n}\r\n\r\n.clear-date-button:hover svg {\r\n fill: var(--text-primary);\r\n}\r\n\r\n.e-date-year {\r\n font-size: 18px;\r\n padding-bottom: 4px;\r\n position: relative;\r\n width: 66px;\r\n height: 25px;\r\n overflow: hidden;\r\n cursor: pointer;\r\n}\r\n\r\n.e-date-year-select {\r\n position: absolute;\r\n opacity: 0.7;\r\n font-size: 20px;\r\n}\r\n\r\n.e-date-year-select.active {\r\n opacity: 1;\r\n}\r\n\r\n.e-date-monthday {\r\n font-size: 26px;\r\n position: relative;\r\n width: 100%;\r\n height: 36px;\r\n overflow: hidden;\r\n}\r\n\r\n.e-date-monthday-select {\r\n position: absolute;\r\n opacity: 0.7;\r\n}\r\n\r\n.e-date-monthday-select.active {\r\n opacity: 1;\r\n}\r\n\r\n.e-calendar-toolbar {\r\n margin: 8px;\r\n height: 40px;\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n background: var(--bg-metal-normal);\r\n border: 1px solid var(--border);\r\n box-shadow: var(--shadow-inset);\r\n padding: 0 8px;\r\n}\r\n\r\n.e-calendar-toolbar-title {\r\n position: relative;\r\n width: 120px;\r\n height: 22px;\r\n text-align: center;\r\n}\r\n\r\n.e-calendar-toolbar-title-content {\r\n position: absolute;\r\n width: 100%;\r\n font-size: 14px;\r\n font-weight: 600;\r\n color: var(--text-primary);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.e-calendar-svg {\r\n padding: 6px;\r\n position: relative;\r\n height: 32px;\r\n width: 32px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n background: var(--bg-metal-normal);\r\n border: 1px solid var(--border);\r\n cursor: pointer;\r\n transition: all var(--transition-fast);\r\n}\r\n\r\n.e-calendar-svg:hover {\r\n background: var(--bg-metal-light);\r\n}\r\n\r\n.e-calendar-svg:active {\r\n background: var(--bg-metal-pressed);\r\n}\r\n\r\n.e-calendar-svg-icon {\r\n display: block;\r\n fill: var(--text-secondary);\r\n height: 20px;\r\n width: 20px;\r\n user-select: none;\r\n position: relative;\r\n z-index: 2;\r\n transition: fill var(--transition-fast);\r\n}\r\n\r\n.e-calendar-svg:hover .e-calendar-svg-icon {\r\n fill: var(--text-primary);\r\n}\r\n\r\n.e-calendar-svg-cover {\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n z-index: 1;\r\n width: 100%;\r\n height: 100%;\r\n background: var(--bg-metal-pressed);\r\n opacity: 0;\r\n display: inline-block;\r\n transition: opacity var(--transition-fast);\r\n}\r\n\r\n.e-calendar-week {\r\n width: 100%;\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--text-secondary);\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n height: 24px;\r\n background: var(--bg-metal-dark);\r\n border-top: 1px solid var(--border);\r\n border-bottom: 1px solid var(--border);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.e-calendar-week-day {\r\n flex: 1;\r\n text-align: center;\r\n}\r\n\r\n.e-calendar-monthday {\r\n padding-top: 10px;\r\n font-size: 14px;\r\n position: relative;\r\n width: 100%;\r\n min-height: 220px;\r\n overflow: hidden;\r\n}\r\n\r\n.e-calendar-monthday-wrapper {\r\n position: absolute;\r\n width: 100%;\r\n height: 100%;\r\n}\r\n\r\n.e-calendar-monthday-row {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n}\r\n\r\n.e-calendar-monthday-row-day {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n flex: 1;\r\n position: relative;\r\n height: 35px;\r\n border: 1px solid transparent;\r\n transition: all var(--transition-fast);\r\n}\r\n\r\n.e-calendar-monthday-row-day.pointer {\r\n cursor: pointer;\r\n background: var(--bg-metal-light);\r\n border-color: var(--border);\r\n}\r\n\r\n.e-calendar-monthday-row-day.pointer:hover {\r\n background: var(--bg-metal-normal);\r\n border-color: var(--primary);\r\n}\r\n\r\n.e-calendar-monthday-row-day.active {\r\n color: var(--text-white);\r\n background: var(--bg-active);\r\n border-color: var(--primary-dark);\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.e-calendar-monthday-row-day.disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n background: var(--bg-metal-dark);\r\n}\r\n\r\n.e-calendar-monthday-row-day-value {\r\n position: relative;\r\n z-index: 1;\r\n font-size: 13px;\r\n font-weight: 500;\r\n}\r\n\r\n.e-calendar-monthday-row-day-cover {\r\n width: 100%;\r\n height: 100%;\r\n background: var(--bg-active);\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n transform: translate3d(0, 0, 0);\r\n z-index: 0;\r\n opacity: 1;\r\n display: block;\r\n}\r\n\r\n.e-calendar-monthday-row-day.hover {\r\n background: var(--bg-metal-normal);\r\n border-color: var(--primary);\r\n}\r\n\r\n.e-calendar-year {\r\n height: 276px;\r\n overflow: auto;\r\n background: var(--bg-content);\r\n border-top: 1px solid var(--border);\r\n}\r\n\r\n.e-calendar-year li {\r\n padding: 12px;\r\n text-align: center;\r\n font-size: 14px;\r\n font-weight: 500;\r\n cursor: pointer;\r\n border-bottom: 1px solid var(--border);\r\n background: var(--bg-metal-light);\r\n color: var(--text-primary);\r\n transition: all var(--transition-fast);\r\n}\r\n\r\n.e-calendar-year li:hover {\r\n background: var(--bg-metal-normal);\r\n color: var(--primary);\r\n}\r\n\r\n.e-calendar-year li.active {\r\n color: var(--text-white);\r\n background: var(--bg-active);\r\n font-weight: 700;\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.e-calendar-year li.hover {\r\n background: var(--bg-metal-normal);\r\n}\r\n\r\n.fadeX_Prev-enter-active,\r\n.fadeX_Prev-leave-active,\r\n.fadeX_Next-enter-active,\r\n.fadeX_Next-leave-active,\r\n.fadeY-enter-active,\r\n.fadeY-leave-active {\r\n transition: all 0.5s;\r\n}\r\n\r\n.fadeX_Prev-enter {\r\n transform: translateX(-100px);\r\n opacity: 0;\r\n}\r\n\r\n.fadeX_Prev-leave-active {\r\n transform: translateX(100px);\r\n opacity: 0;\r\n}\r\n\r\n.fadeX_Next-enter {\r\n transform: translateX(100px);\r\n opacity: 0;\r\n}\r\n\r\n.fadeX_Next-leave-active {\r\n transform: translateX(-100px);\r\n opacity: 0;\r\n}\r\n\r\n.fadeY-enter {\r\n transform: translateY(30px);\r\n opacity: 0;\r\n}\r\n\r\n.fadeY-leave-active {\r\n transform: translateY(-30px);\r\n opacity: 0;\r\n}\r\n\r\n.e_calendar_svg_btn-enter-active,\r\n.e_calendar_svg_btn-leave-active {\r\n transition: all 1s;\r\n}\r\n\r\n.e_calendar_svg_btn-enter {\r\n opacity: 1;\r\n}\r\n\r\n.e_calendar_day-enter-active {\r\n transition: all 0.2s;\r\n}\r\n\r\n.e_calendar_svg_btn-leave-active,\r\n.e_calendar_day-enter {\r\n opacity: 0;\r\n}\r\n\r\n.e_calendar_day-enter {\r\n width: 0;\r\n height: 0;\r\n transform: translate3d(12px, 12px, 0);\r\n}\r\n</style>","<template>\r\n <div>\r\n <!-- 添加文本框 -->\r\n <div class=\"date-picker-input-wrapper\">\r\n <input type=\"text\" v-model=\"selectedDateText\" @click=\"showCalendar = true\" readonly :placeholder=\"t('datePicker.selectDate')\"\r\n class=\"date-picker-input\" ref=\"inputRef\" />\r\n <span class=\"clear-date-button\" @click=\"clearDate\" v-if=\"selectedDateText\">\r\n <svg viewBox=\"0 0 24 24\">\r\n <path\r\n d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\">\r\n </path>\r\n </svg>\r\n </span>\r\n </div>\r\n <!-- 日期选择器 -->\r\n <div class=\"e-calendar\" v-show=\"showCalendar\" ref=\"calendarRef\">\r\n <div class=\"e-date-select\">\r\n <div class=\"e-date-year\">\r\n <transition name=\"fadeY\">\r\n <div :key=\"selectDate.year\" class=\"e-date-year-select\" @click=\"openYearList\" :class=\"{ active: showYear }\">\r\n {{ selectDate.year }}\r\n </div>\r\n </transition>\r\n </div>\r\n <div class=\"e-date-monthday\">\r\n <transition name=\"fadeY\">\r\n <div :key=\"selectDate.day\" class=\"e-date-monthday-select\" :class=\"{ active: !showYear }\"\r\n @click=\"openCalendarList\">\r\n <span>{{ keepDoubleDigit(selectDate.month) }}-{{ keepDoubleDigit(selectDate.day) }}</span> \r\n <span style=\"cursor: pointer;\" @click=\"openMonthList\">{{ showDate.monthStr }}</span>\r\n </div>\r\n </transition>\r\n </div>\r\n </div>\r\n\r\n <div class=\"e-calendar-container\" v-show=\"!showYear && !showMonth\">\r\n <div class=\"e-calendar-toolbar\">\r\n <div class=\"e-calendar-svg\" @click=\"prevMonth\">\r\n <svg viewBox=\"0 0 24 24\" class=\"e-calendar-svg-icon\">\r\n <path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"></path>\r\n </svg>\r\n <transition name=\"e_calendar_svg_btn\">\r\n <div class=\"e-calendar-svg-cover\" v-if=\"prevMonthClick\"></div>\r\n </transition>\r\n </div>\r\n <div class=\"e-calendar-toolbar-title\">\r\n <transition :name=\"fadeXType\">\r\n <div :key=\"showDate.monthStr\" class=\"e-calendar-toolbar-title-content\">\r\n <strong>{{ showDate.year }}</strong> \r\n <span style=\"cursor: pointer;\" @click=\"openMonthList\">{{ showDate.monthStr }}</span>\r\n </div>\r\n </transition>\r\n </div>\r\n <div class=\"e-calendar-svg\" @click=\"nextMonth\">\r\n <svg viewBox=\"0 0 24 24\" class=\"e-calendar-svg-icon\">\r\n <path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"></path>\r\n </svg>\r\n <transition name=\"e_calendar_svg_btn\">\r\n <div class=\"e-calendar-svg-cover\" v-if=\"nextMonthClick\"></div>\r\n </transition>\r\n </div>\r\n </div>\r\n <div class=\"e-calendar-week\">\r\n <span v-for=\"(weekName, index) in getWeekNames\" :key=\"index\" class=\"e-calendar-week-day\">{{ weekName }}</span>\r\n </div>\r\n <div class=\"e-calendar-monthday\">\r\n <transition :name=\"fadeXType\">\r\n <div :key=\"showDate.monthStr\" class=\"e-calendar-monthday-wrapper\">\r\n <div v-for=\"(row, index) in rows\" :key=\"index\" class=\"e-calendar-monthday-row\">\r\n <span v-for=\"(day, dayIndex) in row\" :key=\"dayIndex\" class=\"e-calendar-monthday-row-day\"\r\n @click=\"selectDay(day)\" @mouseenter=\"handleDayMouseEnter(dayIndex, index)\"\r\n @mouseleave=\"handleDayMouseLeave()\" :class=\"{\r\n active: day.selected,\r\n disabled: day.disabled,\r\n pointer: day.value !== '',\r\n hover: isDayHovered(dayIndex, index)\r\n }\">\r\n <span v-text=\"day.value\" class=\"e-calendar-monthday-row-day-value\"></span>\r\n <transition name=\"e_calendar_day\">\r\n <span class=\"e-calendar-monthday-row-day-cover\" v-if=\"day.selected\"></span>\r\n </transition>\r\n </span>\r\n </div>\r\n </div>\r\n </transition>\r\n </div>\r\n </div>\r\n <ul class=\"e-calendar-year\" v-show=\"showYear\" ref=\"yearList\">\r\n <li v-for=\"(item, index) in yearList\" :key=\"index\" :class=\"{\r\n active: item === selectDate.year,\r\n hover: isYearHovered(index)\r\n }\" @click=\"selectYear(item)\" @mouseenter=\"handleYearMouseEnter(index)\" @mouseleave=\"handleYearMouseLeave()\">\r\n {{ item }}\r\n </li>\r\n </ul>\r\n <ul class=\"e-calendar-year\" v-show=\"showMonth\" ref=\"monthList\">\r\n <li v-for=\"(item, index) in monthList\" :key=\"index\" :class=\"{\r\n active: item === selectDate.month,\r\n hover: isMonthHovered(index)\r\n }\" @click=\"selectMonth(item)\" @mouseenter=\"handleMonthMouseEnter(index)\" @mouseleave=\"handleMonthMouseLeave()\">\r\n {{ getMonthName(item) }}\r\n </li>\r\n </ul>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed, onBeforeMount, onMounted, onUnmounted, watchEffect, watch } from 'vue';\r\nimport { useI18n } from './i18n';\r\nimport dayjs from 'dayjs';\r\nimport 'dayjs/locale/zh-cn';\r\nimport 'dayjs/locale/en';\r\nimport 'dayjs/locale/ja';\r\nimport 'dayjs/locale/ko';\r\nimport 'dayjs/locale/fr';\r\nimport 'dayjs/locale/de';\r\nimport 'dayjs/locale/es';\r\nimport 'dayjs/locale/ru';\r\n\r\nexport default defineComponent({\r\n props: {\r\n // 打开date picker的初始值,必传,格式是(2017-08-11)\r\n date: {\r\n type: String,\r\n required: true,\r\n },\r\n // 日期最小值\r\n minDate: String,\r\n // 日期最大值\r\n maxDate: String,\r\n },\r\n setup(props, { emit }) {\r\n const { t, locale } = useI18n();\r\n \r\n // 获取 dayjs locale\r\n const getDayjsLocale = () => {\r\n const localeMap: Record<string, string> = {\r\n 'zh-CN': 'zh-cn',\r\n 'en-US': 'en',\r\n 'ja-JP': 'ja',\r\n 'ko-KR': 'ko',\r\n 'fr-FR': 'fr',\r\n 'de-DE': 'de',\r\n 'es-ES': 'es',\r\n 'ru-RU': 'ru'\r\n };\r\n return localeMap[locale.value] || 'en';\r\n };\r\n \r\n // 获取星期名称\r\n const getWeekNames = computed(() => {\r\n const dayjsLocale = getDayjsLocale();\r\n const weekNames = [];\r\n for (let i = 1; i <= 7; i++) {\r\n // 使用 dayjs 获取本地化的星期名称(简写)\r\n const day = dayjs().day(i).locale(dayjsLocale);\r\n weekNames.push(day.format('dd'));\r\n }\r\n return weekNames;\r\n });\r\n \r\n // 获取月份名称\r\n const getMonthName = (month: number) => {\r\n const dayjsLocale = getDayjsLocale();\r\n return dayjs().month(month - 1).locale(dayjsLocale).format('MMMM');\r\n };\r\n \r\n // 定义响应式数据\r\n let selectDate = ref({\r\n year: 0,\r\n month: 0,\r\n day: 0,\r\n week: 0,\r\n date: '',\r\n weekStr: '',\r\n monthStr: '',\r\n });\r\n let showDate = ref({\r\n year: 0,\r\n month: 0,\r\n day: 0,\r\n week: 0,\r\n date: '',\r\n monthStr: '',\r\n weekStr: '',\r\n });\r\n let copyMinDate = ref({\r\n year: 0,\r\n month: 0,\r\n day: 0,\r\n });\r\n let copyMaxDate = ref({\r\n year: 0,\r\n month: 0,\r\n day: 0,\r\n });\r\n\r\n const fadeXType = ref('fadeX_Prev');\r\n const nextMonthClick = ref(false);\r\n const prevMonthClick = ref(false);\r\n const showYear = ref(false);\r\n const showMonth = ref(false);\r\n const yearListRef = ref<HTMLUListElement | null>(null);\r\n const monthListRef = ref<HTMLUListElement | null>(null);\r\n const showCalendar = ref(false); // 控制日期选择器的显示和隐藏\r\n const selectedDateText = ref(''); // 文本框显示的日期\r\n const calendarRef = ref<HTMLDivElement | null>(null); // 日期组件的引用\r\n const inputRef = ref<HTMLInputElement | null>(null); // 新增文本框引用\r\n\r\n const hoveredYearIndex = ref(-1);\r\n const hoveredMonthIndex = ref(-1);\r\n const hoveredDayIndex = ref({ row: -1, col: -1 });\r\n\r\n const yearList = computed(() => {\r\n const result: number[] = [];\r\n for (let i = copyMinDate.value.year; i <= copyMaxDate.value.year; i += 1) {\r\n result.push(i);\r\n }\r\n return result;\r\n });\r\n\r\n const monthList = computed(() => {\r\n const result: number[] = [];\r\n for (let i = 1; i <= 12; i += 1) {\r\n result.push(i);\r\n }\r\n return result;\r\n });\r\n\r\n const rows = computed(() => {\r\n const { year, month } = showDate.value;\r\n const months = new Date(year, month, 0).getDate();\r\n const result: {\r\n value: number | string;\r\n selected?: boolean;\r\n disabled?: boolean;\r\n }[][] = [];\r\n let row: {\r\n value: number | string;\r\n selected?: boolean;\r\n disabled?: boolean;\r\n }[] = [];\r\n let weekValue: number;\r\n // 按照星期分组\r\n for (let i = 1; i <= months; i += 1) {\r\n // 根据日期获取星期,并让开头是1,而非0\r\n weekValue = new Date(year, month - 1, i).getDay() + 1;\r\n // 判断月第一天在星期几,并填充前面的空白区域\r\n if (i === 1 && weekValue !== 1) {\r\n addRowEmptyValue(row, weekValue);\r\n addRowDayValue(row, i);\r\n } else {\r\n addRowDayValue(row, i);\r\n // 判断月最后一天在星期几,并填充后面的空白区域\r\n if (i === months && weekValue !== 7) {\r\n addRowEmptyValue(row, (7 - weekValue) + 1);\r\n }\r\n }\r\n // 按照一周分组\r\n if (weekValue % 7 === 0 || i === months) {\r\n result.push(row);\r\n row = [];\r\n }\r\n }\r\n showDate.value.monthStr = getMonthName(showDate.value.month);\r\n return result;\r\n });\r\n\r\n // 定义函数,接收一个 number 类型的参数,返回一个 string 类型的值\r\n const keepDoubleDigit = (number: number): string => {\r\n // 判断传入的数字是否大于 9\r\n return number > 9 ? String(number) : `0${number}`;\r\n };\r\n\r\n // 拆分日期\r\n const splitDate = (date: string, addStr = false) => {\r\n let result: {\r\n year: number;\r\n month: number;\r\n day: number;\r\n week?: number;\r\n monthStr?: string;\r\n weekStr?: string;\r\n } = {\r\n year: 0,\r\n month: 0,\r\n day: 0,\r\n };\r\n const splitValue = date.split('-');\r\n try {\r\n if (!splitValue || splitValue.length < 3) {\r\n throw new Error('时间格式不正确');\r\n }\r\n result = {\r\n year: Number(splitValue[0]),\r\n month: Number(splitValue[1]),\r\n day: Number(splitValue[2]),\r\n };\r\n if (addStr) {\r\n result.week = new Date(result.year, result.month - 1, result.day).getDay() + 1;\r\n result.monthStr = getMonthName(result.month);\r\n const dayjsLocale = getDayjsLocale();\r\n result.weekStr = dayjs().day(result.week).locale(dayjsLocale).format('dddd');\r\n }\r\n } catch (error) {\r\n console.error(error);\r\n }\r\n return result;\r\n };\r\n\r\n // 初始化日期选择器\r\n const initDatePicker = () => {\r\n const splitResult = splitDate(props.date, true);\r\n showDate.value = {\r\n ...splitResult,\r\n date: `${splitResult.year}-${keepDoubleDigit(splitResult.month)}-${keepDoubleDigit(\r\n splitResult.day\r\n )}`,\r\n week: splitResult.week || 0,\r\n monthStr: splitResult.monthStr || '',\r\n weekStr: splitResult.weekStr || '',\r\n };\r\n copyMinDate.value = { ...splitDate(props.minDate || '1970-01-01') };\r\n copyMaxDate.value = { ...splitDate(props.maxDate || '2099-12-31') };\r\n selectDate.value = { ...showDate.value };\r\n \r\n // 使用国际化日期格式\r\n const dayjsLocale = getDayjsLocale();\r\n const dateObj = dayjs(showDate.value.date).locale(dayjsLocale);\r\n const dateFormat = t('dateFormat.full');\r\n selectedDateText.value = dateObj.format(dateFormat);\r\n };\r\n\r\n watchEffect(() => {\r\n if (props.date) {\r\n initDatePicker(); // 当 props.date 变化时重新初始化日期选择器\r\n }\r\n });\r\n\r\n onBeforeMount(() => {\r\n initDatePicker();\r\n });\r\n\r\n // 添加空值\r\n const addRowEmptyValue = (\r\n row: {\r\n value: number | string;\r\n selected?: boolean;\r\n disabled?: boolean;\r\n }[],\r\n count: number\r\n ) => {\r\n for (let w = 1; w < count; w += 1) {\r\n row.push({\r\n value: '',\r\n });\r\n }\r\n };\r\n\r\n // 添加日期值\r\n const addRowDayValue = (\r\n row: {\r\n value: number | string;\r\n selected?: boolean;\r\n disabled?: boolean;\r\n }[],\r\n i: number\r\n ) => {\r\n const value = { value: i };\r\n const { day, month, year } = selectDate.value;\r\n const showDateValue = showDate.value;\r\n // 判断已经选择的\r\n if (year === showDateValue.year && month === showDateValue.month && day === i) {\r\n // 为对象添加 selected 属性\r\n const newValue = { ...value, selected: true };\r\n row.push(newValue);\r\n return; // 添加 return 避免重复添加\r\n }\r\n // 当日期在最小值之外,禁止点击\r\n if (isMinLimitMonth() && i < copyMinDate.value.day) {\r\n // 修复:添加 disabled 属性\r\n const newValue = { ...value, disabled: true };\r\n row.push(newValue);\r\n return; // 添加 return 避免重复添加\r\n }\r\n // 当日期在最大值之外,禁止点击\r\n if (isMaxLimitMonth() && i > copyMaxDate.value.day) {\r\n // 修复:添加 disabled 属性\r\n const newValue = { ...value, disabled: true };\r\n row.push(newValue);\r\n return; // 添加 return 避免重复添加\r\n }\r\n row.push(value);\r\n };\r\n\r\n // 切换到上一个月\r\n const prevMonth = () => {\r\n if (prevMonthClick.value) {\r\n return;\r\n }\r\n prevMonthClick.value = true;\r\n setTimeout(() => {\r\n prevMonthClick.value = false;\r\n }, 500);\r\n fadeXType.value = 'fadeX_Prev';\r\n // 如何当前月份已经小于等于minMonth 就不让其在执行\r\n if (isMinLimitMonth()) {\r\n return;\r\n }\r\n const { year, month } = showDate.value;\r\n // 判断当前月份,如果已经等于1(1就是一月,而不是二月)\r\n if (month <= 1) {\r\n showDate.value.year = year - 1;\r\n showDate.value.month = 12;\r\n } else {\r\n showDate.value.month -= 1;\r\n }\r\n };\r\n\r\n // 切换到下一个月\r\n const nextMonth = () => {\r\n if (nextMonthClick.value) {\r\n return;\r\n }\r\n nextMonthClick.value = true;\r\n setTimeout(() => {\r\n nextMonthClick.value = false;\r\n }, 500);\r\n fadeXType.value = 'fadeX_Next';\r\n // 如何当前月份已经大于等于maxMonth 就不让其在执行\r\n if (isMaxLimitMonth()) {\r\n return;\r\n }\r\n const { year, month } = showDate.value;\r\n // 判断当前月份,如果已经等于12(12就是十二月)\r\n if (month >= 12) {\r\n showDate.value.year = year + 1;\r\n showDate.value.month = 1;\r\n } else {\r\n showDate.value.month += 1;\r\n }\r\n };\r\n\r\n // 重置选择日期\r\n let resetSelectDate = (dayValue: number) => {\r\n // 修改为逐个修改属性\r\n selectDate.value.year = showDate.value.year;\r\n selectDate.value.month = showDate.value.month;\r\n selectDate.value.week = showDate.value.week;\r\n selectDate.value.date = showDate.value.date;\r\n selectDate.value.weekStr = showDate.value.weekStr;\r\n selectDate.value.monthStr = showDate.value.monthStr;\r\n selectDate.value.day = dayValue;\r\n selectDate.value.week = new Date(showDate.value.year, showDate.value.month - 1, dayValue).getDay() + 1;\r\n const dayjsLocale = getDayjsLocale();\r\n selectDate.value.weekStr = dayjs().day(selectDate.value.week).locale(dayjsLocale).format('dddd');\r\n \r\n // 使用国际化日期格式\r\n const dateObj = dayjs(`${selectDate.value.year}-${keepDoubleDigit(selectDate.value.month)}-${keepDoubleDigit(selectDate.value.day)}`).locale(dayjsLocale);\r\n const dateFormat = t('dateFormat.full');\r\n selectedDateText.value = dateObj.format(dateFormat);\r\n \r\n showCalendar.value = false; // 选择日期后隐藏日期选择器\r\n };\r\n\r\n // 选择日期\r\n const selectDay = (days: { value: number | string; disabled?: boolean }) => {\r\n if (days.disabled || days.value === '') {\r\n return;\r\n }\r\n resetSelectDate(Number(days.value));\r\n const { year, month, day, week, weekStr, monthStr } = selectDate.value;\r\n emit('confirm', {\r\n date: `${year}-${keepDoubleDigit(month)}-${keepDoubleDigit(day)}`,\r\n year,\r\n month,\r\n week,\r\n monthStr,\r\n weekStr,\r\n day,\r\n });\r\n };\r\n\r\n // 选择月份\r\n const selectMonth = (value: number) => {\r\n showYear.value = false;\r\n showMonth.value = false;\r\n showDate.value.month = value;\r\n let type: 'copyMinDate' | 'copyMaxDate' | undefined;\r\n // 当月份在最小值之外,日期换成最小值日期 或者 当月份在最大值之外,日期换成最大值日期\r\n if (isMinLimitMonth()) {\r\n type = 'copyMinDate';\r\n } else if (isMaxLimitMonth()) {\r\n type = 'copyMaxDate';\r\n }\r\n if (type) {\r\n showDate.value.day = type === 'copyMinDate' ? copyMinDate.value.day : copyMaxDate.value.day;\r\n resetSelectDate(showDate.value.day);\r\n return;\r\n }\r\n let dayValue = selectDate.value.day;\r\n // 判断日是最大值,防止另一个月没有这个日期\r\n const daysInMonth = new Date(showDate.value.year, showDate.value.month + 1, 0).getDate();\r\n dayValue = Math.min(dayValue, daysInMonth); // 确保日期不超过当前月份的最大天数\r\n resetSelectDate(dayValue);\r\n };\r\n\r\n // 选择年份\r\n const selectYear = (value: number) => {\r\n showYear.value = false;\r\n showMonth.value = false;\r\n showDate.value.year = value;\r\n let type: 'copyMinDate' | 'copyMaxDate' | undefined;\r\n // 当日期在最小值之外,月份换成最小值月份 或者 当日期在最大值之外,月份换成最大值月份\r\n if (isMinLimitMonth()) {\r\n type = 'copyMinDate';\r\n } else if (isMaxLimitMonth()) {\r\n type = 'copyMaxDate';\r\n }\r\n if (type) {\r\n showDate.value.month = type === 'copyMinDate' ? copyMinDate.value.month : copyMaxDate.value.month;\r\n showDate.value.day = type === 'copyMinDate' ? copyMinDate.value.day : copyMaxDate.value.day;\r\n resetSelectDate(showDate.value.day);\r\n return;\r\n }\r\n let dayValue = selectDate.value.day;\r\n // 判断日是最大值,防止另一个月没有这个日期\r\n const months = new Date(showDate.value.year, showDate.value.month, 0).getDate();\r\n dayValue = Math.min(dayValue, months); // 确保日期不超过当前月份的最大天数\r\n resetSelectDate(dayValue);\r\n };\r\n\r\n // 判断是否为最小月份限制\r\n const isMinLimitMonth = () => {\r\n return showDate.value.year <= copyMinDate.value.year && showDate.value.month <= copyMinDate.value.month;\r\n };\r\n\r\n // 判断是否为最大月份限制\r\n const isMaxLimitMonth = () => {\r\n return showDate.value.year >= copyMaxDate.value.year && showDate.value.month >= copyMaxDate.value.month;\r\n };\r\n\r\n // 打开年份列表\r\n const openYearList = () => {\r\n if (showYear.value) {\r\n showYear.value = false;\r\n showMonth.value = false;\r\n return;\r\n }\r\n const index = yearList.value.indexOf(selectDate.value.year);\r\n showYear.value = true;\r\n showMonth.value = false;\r\n setTimeout(() => {\r\n if (yearListRef.value) {\r\n yearListRef.value.scrollTop = (index - 3) * 40;\r\n }\r\n });\r\n };\r\n\r\n // 打开月份列表\r\n const openMonthList = () => {\r\n if (showMonth.value) {\r\n showYear.value = false;\r\n showMonth.value = false;\r\n return;\r\n }\r\n const index = monthList.value.indexOf(selectDate.value.month);\r\n showMonth.value = true;\r\n showYear.value = false;\r\n setTimeout(() => {\r\n if (monthListRef.value) {\r\n monthListRef.value.scrollTop = (index - 3) * 20;\r\n }\r\n });\r\n };\r\n\r\n const openCalendarList = () => {\r\n showYear.value = false;\r\n };\r\n\r\n // 清除日期的方法\r\n const clearDate = () => {\r\n selectedDateText.value = '';\r\n showCalendar.value = false;\r\n };\r\n\r\n // 点击文本框和日期组件以外的区域,隐藏日期组件\r\n const handleClickOutside = (event: MouseEvent) => {\r\n if (\r\n calendarRef.value &&\r\n inputRef.value &&\r\n !calendarRef.value.contains(event.target as Node) &&\r\n !inputRef.value.contains(event.target as Node)\r\n ) {\r\n showCalendar.value = false;\r\n }\r\n };\r\n\r\n const isYearHovered = (index: number) => hoveredYearIndex.value === index;\r\n const isMonthHovered = (index: number) => hoveredMonthIndex.value === index;\r\n const isDayHovered = (col: number, row: number) =>\r\n hoveredDayIndex.value.row === row && hoveredDayIndex.value.col === col;\r\n\r\n const handleYearMouseEnter = (index: number) => {\r\n hoveredYearIndex.value = index;\r\n };\r\n\r\n const handleYearMouseLeave = () => {\r\n hoveredYearIndex.value = -1;\r\n };\r\n\r\n const handleMonthMouseEnter = (index: number) => {\r\n hoveredMonthIndex.value = index;\r\n };\r\n\r\n const handleMonthMouseLeave = () => {\r\n hoveredMonthIndex.value = -1;\r\n };\r\n\r\n const handleDayMouseEnter = (col: number, row: number) => {\r\n hoveredDayIndex.value = { row, col };\r\n };\r\n\r\n const handleDayMouseLeave = () => {\r\n hoveredDayIndex.value = { row: -1, col: -1 };\r\n };\r\n\r\n onMounted(() => {\r\n document.addEventListener('click', handleClickOutside);\r\n });\r\n\r\n onUnmounted(() => {\r\n document.removeEventListener('click', handleClickOutside);\r\n });\r\n\r\n return {\r\n t,\r\n locale,\r\n getWeekNames,\r\n getMonthName,\r\n selectDate,\r\n showDate,\r\n copyMinDate,\r\n copyMaxDate,\r\n fadeXType,\r\n nextMonthClick,\r\n prevMonthClick,\r\n keepDoubleDigit,\r\n showYear,\r\n yearList,\r\n rows,\r\n yearListRef,\r\n prevMonth,\r\n nextMonth,\r\n selectDay,\r\n selectYear,\r\n openYearList,\r\n openMonthList,\r\n monthList,\r\n monthListRef,\r\n showMonth,\r\n selectMonth,\r\n openCalendarList,\r\n showCalendar,\r\n selectedDateText,\r\n clearDate,\r\n calendarRef,\r\n inputRef,\r\n isYearHovered,\r\n isMonthHovered,\r\n isDayHovered,\r\n handleYearMouseEnter,\r\n handleYearMouseLeave,\r\n handleMonthMouseEnter,\r\n handleMonthMouseLeave,\r\n handleDayMouseEnter,\r\n handleDayMouseLeave\r\n };\r\n },\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.e-calendar {\r\n background: var(--bg-content);\r\n width: 310px;\r\n border: 1px solid var(--border);\r\n box-shadow: var(--shadow-outset);\r\n z-index: 999;\r\n position: absolute;\r\n font-family: var(--font-family);\r\n}\r\n\r\n.e-date-select {\r\n background: var(--bg-active);\r\n padding: 12px 20px;\r\n color: var(--text-white);\r\n font-weight: 600;\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n box-shadow: var(--shadow-active);\r\n}\r\n\r\n.date-picker-input-wrapper {\r\n position: relative;\r\n display: inline-block;\r\n}\r\n\r\n.date-picker-input {\r\n width: 200px;\r\n padding: 8px 12px;\r\n background: var(--bg-content);\r\n border: 1px solid var(--border);\r\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\r\n font-family: inherit;\r\n font-size: 14px;\r\n color: var(--text-primary);\r\n transition: all var(--transition-fast);\r\n border-radius: 0;\r\n}\r\n\r\n.date-picker-input:focus {\r\n outline: none;\r\n border-color: var(--primary);\r\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 0 2px rgba(0, 120, 212, 0.2);\r\n}\r\n\r\n.clear-date-button {\r\n position: absolute;\r\n right: 8px;\r\n top: 50%;\r\n transform: translateY(-50%);\r\n cursor: pointer;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n background: var(--bg-metal-normal);\r\n border: 1px solid var(--border);\r\n transition: all var(--transition-fast);\r\n}\r\n\r\n.clear-date-button:hover {\r\n background: var(--bg-metal-light);\r\n}\r\n\r\n.clear-date-button svg {\r\n fill: var(--text-secondary);\r\n width: 14px;\r\n height: 14px;\r\n transition: fill var(--transition-fast);\r\n}\r\n\r\n.clear-date-button:hover svg {\r\n fill: var(--text-primary);\r\n}\r\n\r\n.e-date-year {\r\n font-size: 18px;\r\n padding-bottom: 4px;\r\n position: relative;\r\n width: 66px;\r\n height: 25px;\r\n overflow: hidden;\r\n cursor: pointer;\r\n}\r\n\r\n.e-date-year-select {\r\n position: absolute;\r\n opacity: 0.7;\r\n font-size: 20px;\r\n}\r\n\r\n.e-date-year-select.active {\r\n opacity: 1;\r\n}\r\n\r\n.e-date-monthday {\r\n font-size: 26px;\r\n position: relative;\r\n width: 100%;\r\n height: 36px;\r\n overflow: hidden;\r\n}\r\n\r\n.e-date-monthday-select {\r\n position: absolute;\r\n opacity: 0.7;\r\n}\r\n\r\n.e-date-monthday-select.active {\r\n opacity: 1;\r\n}\r\n\r\n.e-calendar-toolbar {\r\n margin: 8px;\r\n height: 40px;\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n background: var(--bg-metal-normal);\r\n border: 1px solid var(--border);\r\n box-shadow: var(--shadow-inset);\r\n padding: 0 8px;\r\n}\r\n\r\n.e-calendar-toolbar-title {\r\n position: relative;\r\n width: 120px;\r\n height: 22px;\r\n text-align: center;\r\n}\r\n\r\n.e-calendar-toolbar-title-content {\r\n position: absolute;\r\n width: 100%;\r\n font-size: 14px;\r\n font-weight: 600;\r\n color: var(--text-primary);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.e-calendar-svg {\r\n padding: 6px;\r\n position: relative;\r\n height: 32px;\r\n width: 32px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n background: var(--bg-metal-normal);\r\n border: 1px solid var(--border);\r\n cursor: pointer;\r\n transition: all var(--transition-fast);\r\n}\r\n\r\n.e-calendar-svg:hover {\r\n background: var(--bg-metal-light);\r\n}\r\n\r\n.e-calendar-svg:active {\r\n background: var(--bg-metal-pressed);\r\n}\r\n\r\n.e-calendar-svg-icon {\r\n display: block;\r\n fill: var(--text-secondary);\r\n height: 20px;\r\n width: 20px;\r\n user-select: none;\r\n position: relative;\r\n z-index: 2;\r\n transition: fill var(--transition-fast);\r\n}\r\n\r\n.e-calendar-svg:hover .e-calendar-svg-icon {\r\n fill: var(--text-primary);\r\n}\r\n\r\n.e-calendar-svg-cover {\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n z-index: 1;\r\n width: 100%;\r\n height: 100%;\r\n background: var(--bg-metal-pressed);\r\n opacity: 0;\r\n display: inline-block;\r\n transition: opacity var(--transition-fast);\r\n}\r\n\r\n.e-calendar-week {\r\n width: 100%;\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--text-secondary);\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n height: 24px;\r\n background: var(--bg-metal-dark);\r\n border-top: 1px solid var(--border);\r\n border-bottom: 1px solid var(--border);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.e-calendar-week-day {\r\n flex: 1;\r\n text-align: center;\r\n}\r\n\r\n.e-calendar-monthday {\r\n padding-top: 10px;\r\n font-size: 14px;\r\n position: relative;\r\n width: 100%;\r\n min-height: 220px;\r\n overflow: hidden;\r\n}\r\n\r\n.e-calendar-monthday-wrapper {\r\n position: absolute;\r\n width: 100%;\r\n height: 100%;\r\n}\r\n\r\n.e-calendar-monthday-row {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n}\r\n\r\n.e-calendar-monthday-row-day {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n flex: 1;\r\n position: relative;\r\n height: 35px;\r\n border: 1px solid transparent;\r\n transition: all var(--transition-fast);\r\n}\r\n\r\n.e-calendar-monthday-row-day.pointer {\r\n cursor: pointer;\r\n background: var(--bg-metal-light);\r\n border-color: var(--border);\r\n}\r\n\r\n.e-calendar-monthday-row-day.pointer:hover {\r\n background: var(--bg-metal-normal);\r\n border-color: var(--primary);\r\n}\r\n\r\n.e-calendar-monthday-row-day.active {\r\n color: var(--text-white);\r\n background: var(--bg-active);\r\n border-color: var(--primary-dark);\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.e-calendar-monthday-row-day.disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n background: var(--bg-metal-dark);\r\n}\r\n\r\n.e-calendar-monthday-row-day-value {\r\n position: relative;\r\n z-index: 1;\r\n font-size: 13px;\r\n font-weight: 500;\r\n}\r\n\r\n.e-calendar-monthday-row-day-cover {\r\n width: 100%;\r\n height: 100%;\r\n background: var(--bg-active);\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n transform: translate3d(0, 0, 0);\r\n z-index: 0;\r\n opacity: 1;\r\n display: block;\r\n}\r\n\r\n.e-calendar-monthday-row-day.hover {\r\n background: var(--bg-metal-normal);\r\n border-color: var(--primary);\r\n}\r\n\r\n.e-calendar-year {\r\n height: 276px;\r\n overflow: auto;\r\n background: var(--bg-content);\r\n border-top: 1px solid var(--border);\r\n}\r\n\r\n.e-calendar-year li {\r\n padding: 12px;\r\n text-align: center;\r\n font-size: 14px;\r\n font-weight: 500;\r\n cursor: pointer;\r\n border-bottom: 1px solid var(--border);\r\n background: var(--bg-metal-light);\r\n color: var(--text-primary);\r\n transition: all var(--transition-fast);\r\n}\r\n\r\n.e-calendar-year li:hover {\r\n background: var(--bg-metal-normal);\r\n color: var(--primary);\r\n}\r\n\r\n.e-calendar-year li.active {\r\n color: var(--text-white);\r\n background: var(--bg-active);\r\n font-weight: 700;\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.e-calendar-year li.hover {\r\n background: var(--bg-metal-normal);\r\n}\r\n\r\n.fadeX_Prev-enter-active,\r\n.fadeX_Prev-leave-active,\r\n.fadeX_Next-enter-active,\r\n.fadeX_Next-leave-active,\r\n.fadeY-enter-active,\r\n.fadeY-leave-active {\r\n transition: all 0.5s;\r\n}\r\n\r\n.fadeX_Prev-enter {\r\n transform: translateX(-100px);\r\n opacity: 0;\r\n}\r\n\r\n.fadeX_Prev-leave-active {\r\n transform: translateX(100px);\r\n opacity: 0;\r\n}\r\n\r\n.fadeX_Next-enter {\r\n transform: translateX(100px);\r\n opacity: 0;\r\n}\r\n\r\n.fadeX_Next-leave-active {\r\n transform: translateX(-100px);\r\n opacity: 0;\r\n}\r\n\r\n.fadeY-enter {\r\n transform: translateY(30px);\r\n opacity: 0;\r\n}\r\n\r\n.fadeY-leave-active {\r\n transform: translateY(-30px);\r\n opacity: 0;\r\n}\r\n\r\n.e_calendar_svg_btn-enter-active,\r\n.e_calendar_svg_btn-leave-active {\r\n transition: all 1s;\r\n}\r\n\r\n.e_calendar_svg_btn-enter {\r\n opacity: 1;\r\n}\r\n\r\n.e_calendar_day-enter-active {\r\n transition: all 0.2s;\r\n}\r\n\r\n.e_calendar_svg_btn-leave-active,\r\n.e_calendar_day-enter {\r\n opacity: 0;\r\n}\r\n\r\n.e_calendar_day-enter {\r\n width: 0;\r\n height: 0;\r\n transform: translate3d(12px, 12px, 0);\r\n}\r\n</style>","<template>\r\n <div ref=\"splitPane\" class=\"split-pane\" :class=\"direction\" :style=\"{ flexDirection: direction }\">\r\n <div class=\"pane pane-one\" :style=\"`${lengthType}: ${paneLengthValue}`\">\r\n <slot name=\"one\"></slot>\r\n </div>\r\n <div\r\n ref=\"trigger\"\r\n class=\"pane-trigger\"\r\n v-if=\"triggerDefaultColor && triggerMoveColor\"\r\n :style=\"`${lengthType}: ${triggerLengthValue}; ${triggerBackGroud}`\"\r\n >\r\n <div\r\n @click=\"handleMouseOver\"\r\n @mouseover=\"handleMouseOver\"\r\n @mouseleave=\"handleMouseLeave\"\r\n @mousedown=\"handleMouseDown\"\r\n class=\"icon\"\r\n :style=\"`${lengthType}: ${triggerLengthValue}`\"\r\n ></div>\r\n </div>\r\n <div class=\"pane pane-two\" :style=\"`${lengthType}: calc(${100 - paneLengthPercent}% - ${triggerLength / 2}px)`\">\r\n <slot name=\"two\"></slot>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed, onMounted, nextTick } from 'vue';\r\n\r\nexport default defineComponent({\r\n props: {\r\n direction: {\r\n type: String as () => 'row' | 'column' ,\r\n default: 'row'\r\n },\r\n min: {\r\n type: Number,\r\n required: true\r\n },\r\n max: {\r\n type: Number,\r\n required: true\r\n },\r\n paneLengthPercent: {\r\n type: Number,\r\n required: true\r\n },\r\n triggerLength: {\r\n type: Number,\r\n required: true\r\n }\r\n },\r\n emits: ['update:paneLengthPercent'],\r\n setup(props, { emit }) {\r\n let splitPane = ref<HTMLElement | null>(null);\r\n let trigger = ref<HTMLElement | null>(null);\r\n let triggerLeftOffset = ref(0); // 鼠标距滑动器左(顶)侧偏移量\r\n let triggerBackGroud = ref('');\r\n\r\n // 计算属性\r\n const lengthType = computed(() => (props.direction === 'row' ? 'width' : 'height'));\r\n\r\n // 拖拽条默认颜色\r\n const triggerDefaultColor = computed(() =>\r\n props.direction === 'row'\r\n ? '-webkit-gradient(linear,left top,right top,from(white), to(#D7D7D9))'\r\n : '-webkit-gradient(linear, 0 0, 0 bottom, from(white), to(#D7D7D9))'\r\n );\r\n\r\n // 鼠标拖动时拖拽条的颜色\r\n const triggerMoveColor = computed(() =>\r\n props.direction === 'row'\r\n ? '-webkit-gradient(linear,left top,right top,from(#A6D4E1), to(#2591C8))'\r\n : '-webkit-gradient(linear, 0 0, 0 bottom, from(#A6D4E1), to(#2591C8))'\r\n );\r\n\r\n const paneLengthValue = computed(() => `calc(${props.paneLengthPercent}% - ${props.triggerLength / 2}px)`);\r\n const triggerLengthValue = computed(() => `${props.triggerLength}px`);\r\n\r\n // 生命周期钩子\r\n onMounted(async () => {\r\n await nextTick();\r\n triggerBackGroud.value = `background: ${triggerDefaultColor.value}`;\r\n });\r\n\r\n // 方法\r\n const handleMouseLeave = async () => {\r\n await nextTick();\r\n triggerBackGroud.value = `background: ${triggerDefaultColor.value}`;\r\n };\r\n\r\n const handleMouseOver = async () => {\r\n await nextTick();\r\n triggerBackGroud.value = `background: ${triggerMoveColor.value}`;\r\n };\r\n\r\n // 按下滑动器\r\n const handleMouseDown = (e: MouseEvent) => {\r\n document.addEventListener('mousemove', handleMouseMove);\r\n document.addEventListener('mouseup', handleMouseUp);\r\n\r\n if (props.direction === 'row') {\r\n triggerLeftOffset.value = e.pageX - (e.target as HTMLElement).getBoundingClientRect().left;\r\n } else {\r\n triggerLeftOffset.value = e.pageY - (e.target as HTMLElement).getBoundingClientRect().top;\r\n }\r\n };\r\n\r\n // 按下滑动器后移动鼠标\r\n const handleMouseMove = async (e: MouseEvent) => {\r\n await nextTick();\r\n triggerBackGroud.value = `background: ${triggerMoveColor.value}`;\r\n if (splitPane.value) {\r\n const clientRect = splitPane.value.getBoundingClientRect();\r\n let paneLengthPercent = 0;\r\n if (props.direction === 'row') {\r\n const offset = e.pageX - clientRect.left - triggerLeftOffset.value + props.triggerLength / 2;\r\n paneLengthPercent = (offset / clientRect.width) * 100;\r\n } else {\r\n const offset = e.pageY - clientRect.top - triggerLeftOffset.value + props.triggerLength / 2;\r\n paneLengthPercent = (offset / clientRect.height) * 100;\r\n }\r\n if (paneLengthPercent < props.min) {\r\n paneLengthPercent = props.min;\r\n }\r\n if (paneLengthPercent > props.max) {\r\n paneLengthPercent = props.max;\r\n }\r\n emit('update:paneLengthPercent', paneLengthPercent);\r\n }\r\n };\r\n\r\n // 松开滑动器\r\n const handleMouseUp = async () => {\r\n await nextTick();\r\n triggerBackGroud.value = `background: ${triggerDefaultColor.value}`;\r\n document.removeEventListener('mousemove', handleMouseMove);\r\n };\r\n\r\n return {\r\n splitPane,\r\n trigger,\r\n lengthType,\r\n triggerDefaultColor,\r\n triggerMoveColor,\r\n paneLengthValue,\r\n triggerLengthValue,\r\n triggerBackGroud,\r\n handleMouseLeave,\r\n handleMouseOver,\r\n handleMouseDown,\r\n handleMouseUp\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n$icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABHNCSVQICAgIfAhkiAAAAIJJREFUKFNjZMANBIBS64E4EIg/YFPGiEdzA1AuHogbgRjExgAgzQeA+D8WOQckMZAanJrxOAC3FD5nEzSQYs0gv2HzM1E2k6URZDLI2cihStA2ZAUU+5kk29BtxpVICBoKS2HYFNojCR7ElcJw2dAAlCCYtnFpBuWqDUAcAMRYcxUAYvURjNoDrtgAAAAASUVORK5CYII=';\r\n$background-size: 10px 10px;\r\n\r\n.split-pane {\r\n background: transparent;\r\n height: 100%;\r\n display: flex;\r\n\r\n .pane-one {\r\n background: transparent;\r\n }\r\n\r\n .pane-trigger {\r\n border-radius: 25px;\r\n user-select: none;\r\n border-width: 0.1em;\r\n }\r\n\r\n .pane-two {\r\n flex: 1;\r\n background: transparent;\r\n }\r\n\r\n // 横向布局\r\n &.row {\r\n .pane {\r\n height: 100%;\r\n }\r\n\r\n .pane-trigger {\r\n margin-left: 1px;\r\n margin-right: 1px;\r\n height: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n\r\n .icon {\r\n cursor: col-resize;\r\n height: 10px;\r\n width: 100%;\r\n background-image: url(#{$icon});\r\n background-repeat: no-repeat;\r\n background-size: $background-size;\r\n transform: rotate(90deg);\r\n }\r\n }\r\n }\r\n\r\n // 纵向布局\r\n &.column {\r\n .pane {\r\n width: 100%;\r\n }\r\n\r\n .pane-trigger {\r\n margin-top: 1px;\r\n margin-bottom: 1px;\r\n width: 100%;\r\n display: flex;\r\n flex-direction: row;\r\n align-items: center;\r\n justify-content: center;\r\n\r\n .icon {\r\n cursor: row-resize;\r\n height: 100%;\r\n width: 10px;\r\n background-image: url(#{$icon});\r\n background-repeat: no-repeat;\r\n background-size: $background-size;\r\n }\r\n }\r\n }\r\n}\r\n</style>","<template>\r\n <div ref=\"splitPane\" class=\"split-pane\" :class=\"direction\" :style=\"{ flexDirection: direction }\">\r\n <div class=\"pane pane-one\" :style=\"`${lengthType}: ${paneLengthValue}`\">\r\n <slot name=\"one\"></slot>\r\n </div>\r\n <div\r\n ref=\"trigger\"\r\n class=\"pane-trigger\"\r\n v-if=\"triggerDefaultColor && triggerMoveColor\"\r\n :style=\"`${lengthType}: ${triggerLengthValue}; ${triggerBackGroud}`\"\r\n >\r\n <div\r\n @click=\"handleMouseOver\"\r\n @mouseover=\"handleMouseOver\"\r\n @mouseleave=\"handleMouseLeave\"\r\n @mousedown=\"handleMouseDown\"\r\n class=\"icon\"\r\n :style=\"`${lengthType}: ${triggerLengthValue}`\"\r\n ></div>\r\n </div>\r\n <div class=\"pane pane-two\" :style=\"`${lengthType}: calc(${100 - paneLengthPercent}% - ${triggerLength / 2}px)`\">\r\n <slot name=\"two\"></slot>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed, onMounted, nextTick } from 'vue';\r\n\r\nexport default defineComponent({\r\n props: {\r\n direction: {\r\n type: String as () => 'row' | 'column' ,\r\n default: 'row'\r\n },\r\n min: {\r\n type: Number,\r\n required: true\r\n },\r\n max: {\r\n type: Number,\r\n required: true\r\n },\r\n paneLengthPercent: {\r\n type: Number,\r\n required: true\r\n },\r\n triggerLength: {\r\n type: Number,\r\n required: true\r\n }\r\n },\r\n emits: ['update:paneLengthPercent'],\r\n setup(props, { emit }) {\r\n let splitPane = ref<HTMLElement | null>(null);\r\n let trigger = ref<HTMLElement | null>(null);\r\n let triggerLeftOffset = ref(0); // 鼠标距滑动器左(顶)侧偏移量\r\n let triggerBackGroud = ref('');\r\n\r\n // 计算属性\r\n const lengthType = computed(() => (props.direction === 'row' ? 'width' : 'height'));\r\n\r\n // 拖拽条默认颜色\r\n const triggerDefaultColor = computed(() =>\r\n props.direction === 'row'\r\n ? '-webkit-gradient(linear,left top,right top,from(white), to(#D7D7D9))'\r\n : '-webkit-gradient(linear, 0 0, 0 bottom, from(white), to(#D7D7D9))'\r\n );\r\n\r\n // 鼠标拖动时拖拽条的颜色\r\n const triggerMoveColor = computed(() =>\r\n props.direction === 'row'\r\n ? '-webkit-gradient(linear,left top,right top,from(#A6D4E1), to(#2591C8))'\r\n : '-webkit-gradient(linear, 0 0, 0 bottom, from(#A6D4E1), to(#2591C8))'\r\n );\r\n\r\n const paneLengthValue = computed(() => `calc(${props.paneLengthPercent}% - ${props.triggerLength / 2}px)`);\r\n const triggerLengthValue = computed(() => `${props.triggerLength}px`);\r\n\r\n // 生命周期钩子\r\n onMounted(async () => {\r\n await nextTick();\r\n triggerBackGroud.value = `background: ${triggerDefaultColor.value}`;\r\n });\r\n\r\n // 方法\r\n const handleMouseLeave = async () => {\r\n await nextTick();\r\n triggerBackGroud.value = `background: ${triggerDefaultColor.value}`;\r\n };\r\n\r\n const handleMouseOver = async () => {\r\n await nextTick();\r\n triggerBackGroud.value = `background: ${triggerMoveColor.value}`;\r\n };\r\n\r\n // 按下滑动器\r\n const handleMouseDown = (e: MouseEvent) => {\r\n document.addEventListener('mousemove', handleMouseMove);\r\n document.addEventListener('mouseup', handleMouseUp);\r\n\r\n if (props.direction === 'row') {\r\n triggerLeftOffset.value = e.pageX - (e.target as HTMLElement).getBoundingClientRect().left;\r\n } else {\r\n triggerLeftOffset.value = e.pageY - (e.target as HTMLElement).getBoundingClientRect().top;\r\n }\r\n };\r\n\r\n // 按下滑动器后移动鼠标\r\n const handleMouseMove = async (e: MouseEvent) => {\r\n await nextTick();\r\n triggerBackGroud.value = `background: ${triggerMoveColor.value}`;\r\n if (splitPane.value) {\r\n const clientRect = splitPane.value.getBoundingClientRect();\r\n let paneLengthPercent = 0;\r\n if (props.direction === 'row') {\r\n const offset = e.pageX - clientRect.left - triggerLeftOffset.value + props.triggerLength / 2;\r\n paneLengthPercent = (offset / clientRect.width) * 100;\r\n } else {\r\n const offset = e.pageY - clientRect.top - triggerLeftOffset.value + props.triggerLength / 2;\r\n paneLengthPercent = (offset / clientRect.height) * 100;\r\n }\r\n if (paneLengthPercent < props.min) {\r\n paneLengthPercent = props.min;\r\n }\r\n if (paneLengthPercent > props.max) {\r\n paneLengthPercent = props.max;\r\n }\r\n emit('update:paneLengthPercent', paneLengthPercent);\r\n }\r\n };\r\n\r\n // 松开滑动器\r\n const handleMouseUp = async () => {\r\n await nextTick();\r\n triggerBackGroud.value = `background: ${triggerDefaultColor.value}`;\r\n document.removeEventListener('mousemove', handleMouseMove);\r\n };\r\n\r\n return {\r\n splitPane,\r\n trigger,\r\n lengthType,\r\n triggerDefaultColor,\r\n triggerMoveColor,\r\n paneLengthValue,\r\n triggerLengthValue,\r\n triggerBackGroud,\r\n handleMouseLeave,\r\n handleMouseOver,\r\n handleMouseDown,\r\n handleMouseUp\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n$icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAABHNCSVQICAgIfAhkiAAAAIJJREFUKFNjZMANBIBS64E4EIg/YFPGiEdzA1AuHogbgRjExgAgzQeA+D8WOQckMZAanJrxOAC3FD5nEzSQYs0gv2HzM1E2k6URZDLI2cihStA2ZAUU+5kk29BtxpVICBoKS2HYFNojCR7ElcJw2dAAlCCYtnFpBuWqDUAcAMRYcxUAYvURjNoDrtgAAAAASUVORK5CYII=';\r\n$background-size: 10px 10px;\r\n\r\n.split-pane {\r\n background: transparent;\r\n height: 100%;\r\n display: flex;\r\n\r\n .pane-one {\r\n background: transparent;\r\n }\r\n\r\n .pane-trigger {\r\n border-radius: 25px;\r\n user-select: none;\r\n border-width: 0.1em;\r\n }\r\n\r\n .pane-two {\r\n flex: 1;\r\n background: transparent;\r\n }\r\n\r\n // 横向布局\r\n &.row {\r\n .pane {\r\n height: 100%;\r\n }\r\n\r\n .pane-trigger {\r\n margin-left: 1px;\r\n margin-right: 1px;\r\n height: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n\r\n .icon {\r\n cursor: col-resize;\r\n height: 10px;\r\n width: 100%;\r\n background-image: url(#{$icon});\r\n background-repeat: no-repeat;\r\n background-size: $background-size;\r\n transform: rotate(90deg);\r\n }\r\n }\r\n }\r\n\r\n // 纵向布局\r\n &.column {\r\n .pane {\r\n width: 100%;\r\n }\r\n\r\n .pane-trigger {\r\n margin-top: 1px;\r\n margin-bottom: 1px;\r\n width: 100%;\r\n display: flex;\r\n flex-direction: row;\r\n align-items: center;\r\n justify-content: center;\r\n\r\n .icon {\r\n cursor: row-resize;\r\n height: 100%;\r\n width: 10px;\r\n background-image: url(#{$icon});\r\n background-repeat: no-repeat;\r\n background-size: $background-size;\r\n }\r\n }\r\n }\r\n}\r\n</style>","<template>\r\n <div class=\"header\">\r\n <template v-for='(item, index) in headers' :key=\"index\">\r\n <div \r\n :property='item.property' \r\n :columnindex='index' \r\n v-show=\"item.show\" \r\n class=\"headerCaption\"\r\n :style=\"{ width: `${item.width}px` }\"\r\n >\r\n <span>{{ getHeaderTitle(item) }}</span>\r\n <!-- 列宽调整拖动手柄 -->\r\n <div \r\n v-if=\"index < headers.length - 1 && item.show\"\r\n class=\"resize-handle\"\r\n @mousedown=\"startResize($event, index)\"\r\n ></div>\r\n </div>\r\n </template>\r\n </div>\r\n </template>\r\n\r\n <script lang=\"ts\">\r\n import { defineComponent, ref } from 'vue';\r\n import { useI18n } from '../i18n';\r\n\r\n export default defineComponent({\r\n props: {\r\n headers: {\r\n type: Array as () => {\r\n property: string;\r\n show: boolean;\r\n width: number;\r\n title: string;\r\n }[],\r\n required: true\r\n }\r\n },\r\n setup(props) {\r\n const { t } = useI18n();\r\n \r\n // 拖动调整状态\r\n const resizing = ref(false);\r\n const resizingIndex = ref(-1);\r\n const startX = ref(0);\r\n const startWidth = ref(0);\r\n const currentHeaderElement = ref<HTMLElement | null>(null);\r\n \r\n // 根据 property 获取翻译后的标题\r\n const getHeaderTitle = (header: { property: string; title: string }) => {\r\n const propertyMap: Record<string, string> = {\r\n 'no': 'task.serialNumber',\r\n 'task': 'task.name',\r\n 'priority': 'task.priority',\r\n 'startdate': 'task.startDate',\r\n 'enddate': 'task.endDate',\r\n 'takestime': 'task.duration',\r\n 'progress': 'task.progress',\r\n 'id': 'ID',\r\n 'parentId': 'Parent ID'\r\n };\r\n \r\n const translationKey = propertyMap[header.property];\r\n if (translationKey) {\r\n if (translationKey.includes('.')) {\r\n return t(translationKey);\r\n }\r\n return translationKey;\r\n }\r\n return header.title;\r\n };\r\n \r\n // 开始拖动调整列宽\r\n const startResize = (event: MouseEvent, index: number) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n \r\n resizing.value = true;\r\n resizingIndex.value = index;\r\n startX.value = event.clientX;\r\n startWidth.value = props.headers[index].width;\r\n \r\n // 获取当前列的 DOM 元素\r\n const target = event.target as HTMLElement;\r\n currentHeaderElement.value = target.closest('.headerCaption') as HTMLElement;\r\n \r\n // 添加全局鼠标移动和释放事件\r\n document.addEventListener('mousemove', handleMouseMove, { passive: false });\r\n document.addEventListener('mouseup', handleMouseUp);\r\n \r\n // 添加禁止选择的样式\r\n document.body.style.cursor = 'col-resize';\r\n document.body.style.userSelect = 'none';\r\n };\r\n \r\n // 处理鼠标移动 - 使用 requestAnimationFrame 优化性能\r\n let rafId: number | null = null;\r\n const handleMouseMove = (event: MouseEvent) => {\r\n if (!resizing.value || resizingIndex.value < 0) return;\r\n \r\n event.preventDefault();\r\n \r\n // 取消之前的动画帧\r\n if (rafId !== null) {\r\n cancelAnimationFrame(rafId);\r\n }\r\n \r\n // 使用 requestAnimationFrame 确保流畅更新\r\n rafId = requestAnimationFrame(() => {\r\n const deltaX = event.clientX - startX.value;\r\n const newWidth = Math.max(50, startWidth.value + deltaX);\r\n \r\n // 直接设置 DOM 样式,避免 Vue 响应式更新延迟\r\n if (currentHeaderElement.value) {\r\n currentHeaderElement.value.style.width = `${newWidth}px`;\r\n }\r\n \r\n // 同时更新对应的内容列\r\n const contentCells = document.querySelectorAll(\r\n `.cellNo[columnindex=\"${resizingIndex.value}\"], .cell[columnindex=\"${resizingIndex.value}\"]`\r\n );\r\n contentCells.forEach((cell) => {\r\n (cell as HTMLElement).style.minWidth = `${newWidth}px`;\r\n (cell as HTMLElement).style.maxWidth = `${newWidth}px`;\r\n });\r\n \r\n rafId = null;\r\n });\r\n };\r\n \r\n // 处理鼠标释放\r\n const handleMouseUp = () => {\r\n if (!resizing.value) return;\r\n \r\n // 取消未完成的动画帧\r\n if (rafId !== null) {\r\n cancelAnimationFrame(rafId);\r\n rafId = null;\r\n }\r\n \r\n // 计算最终宽度并更新到 props\r\n if (currentHeaderElement.value && resizingIndex.value >= 0) {\r\n const finalWidth = parseInt(currentHeaderElement.value.style.width);\r\n props.headers[resizingIndex.value].width = finalWidth;\r\n }\r\n \r\n resizing.value = false;\r\n resizingIndex.value = -1;\r\n currentHeaderElement.value = null;\r\n \r\n // 移除全局事件监听\r\n document.removeEventListener('mousemove', handleMouseMove);\r\n document.removeEventListener('mouseup', handleMouseUp);\r\n \r\n // 恢复样式\r\n document.body.style.cursor = '';\r\n document.body.style.userSelect = '';\r\n };\r\n \r\n return {\r\n getHeaderTitle,\r\n startResize\r\n };\r\n }\r\n });\r\n </script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.header {\r\n height: 100%;\r\n display: flex;\r\n flex-flow: row nowrap;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n font-family: var(--font-family, 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif);\r\n \r\n .headerCaption {\r\n text-align: center;\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: center;\r\n position: relative;\r\n color: var(--text-primary, #333333);\r\n font-size: 14px;\r\n font-weight: 600;\r\n box-sizing: border-box;\r\n letter-spacing: 0.5px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n transition: all var(--transition-fast, 0.15s ease);\r\n flex-shrink: 0;\r\n \r\n &::before {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n bottom: 0;\r\n left: 0;\r\n border-top: 1px solid var(--border, #cecece);\r\n border-bottom: 1px solid var(--border, #cecece);\r\n pointer-events: none;\r\n }\r\n \r\n &:not(:last-child)::after {\r\n content: '';\r\n position: absolute;\r\n right: -1px;\r\n top: 0;\r\n bottom: 0;\r\n background: var(--border, #cecece);\r\n border-left: 1px solid var(--border, #cecece);\r\n }\r\n \r\n &:first-child::before {\r\n border-left: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:last-child::before {\r\n border-right: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:hover {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n color: var(--primary, #0078d4);\r\n }\r\n\r\n // 列宽调整拖动手柄\r\n .resize-handle {\r\n position: absolute;\r\n right: -4px;\r\n top: 0;\r\n bottom: 0;\r\n width: 8px;\r\n cursor: col-resize;\r\n z-index: 10;\r\n background: transparent;\r\n transition: background 0.2s ease;\r\n\r\n &::before {\r\n content: '';\r\n position: absolute;\r\n left: 50%;\r\n top: 50%;\r\n transform: translate(-50%, -50%);\r\n width: 2px;\r\n height: 60%;\r\n background: transparent;\r\n transition: background 0.2s ease;\r\n }\r\n\r\n &:hover {\r\n background: rgba(51, 112, 255, 0.1);\r\n\r\n &::before {\r\n background: var(--primary, #3370ff);\r\n }\r\n }\r\n\r\n &:active {\r\n background: rgba(51, 112, 255, 0.15);\r\n }\r\n }\r\n }\r\n}\r\n</style>","<template>\r\n <div class=\"header\">\r\n <template v-for='(item, index) in headers' :key=\"index\">\r\n <div \r\n :property='item.property' \r\n :columnindex='index' \r\n v-show=\"item.show\" \r\n class=\"headerCaption\"\r\n :style=\"{ width: `${item.width}px` }\"\r\n >\r\n <span>{{ getHeaderTitle(item) }}</span>\r\n <!-- 列宽调整拖动手柄 -->\r\n <div \r\n v-if=\"index < headers.length - 1 && item.show\"\r\n class=\"resize-handle\"\r\n @mousedown=\"startResize($event, index)\"\r\n ></div>\r\n </div>\r\n </template>\r\n </div>\r\n </template>\r\n\r\n <script lang=\"ts\">\r\n import { defineComponent, ref } from 'vue';\r\n import { useI18n } from '../i18n';\r\n\r\n export default defineComponent({\r\n props: {\r\n headers: {\r\n type: Array as () => {\r\n property: string;\r\n show: boolean;\r\n width: number;\r\n title: string;\r\n }[],\r\n required: true\r\n }\r\n },\r\n setup(props) {\r\n const { t } = useI18n();\r\n \r\n // 拖动调整状态\r\n const resizing = ref(false);\r\n const resizingIndex = ref(-1);\r\n const startX = ref(0);\r\n const startWidth = ref(0);\r\n const currentHeaderElement = ref<HTMLElement | null>(null);\r\n \r\n // 根据 property 获取翻译后的标题\r\n const getHeaderTitle = (header: { property: string; title: string }) => {\r\n const propertyMap: Record<string, string> = {\r\n 'no': 'task.serialNumber',\r\n 'task': 'task.name',\r\n 'priority': 'task.priority',\r\n 'startdate': 'task.startDate',\r\n 'enddate': 'task.endDate',\r\n 'takestime': 'task.duration',\r\n 'progress': 'task.progress',\r\n 'id': 'ID',\r\n 'parentId': 'Parent ID'\r\n };\r\n \r\n const translationKey = propertyMap[header.property];\r\n if (translationKey) {\r\n if (translationKey.includes('.')) {\r\n return t(translationKey);\r\n }\r\n return translationKey;\r\n }\r\n return header.title;\r\n };\r\n \r\n // 开始拖动调整列宽\r\n const startResize = (event: MouseEvent, index: number) => {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n \r\n resizing.value = true;\r\n resizingIndex.value = index;\r\n startX.value = event.clientX;\r\n startWidth.value = props.headers[index].width;\r\n \r\n // 获取当前列的 DOM 元素\r\n const target = event.target as HTMLElement;\r\n currentHeaderElement.value = target.closest('.headerCaption') as HTMLElement;\r\n \r\n // 添加全局鼠标移动和释放事件\r\n document.addEventListener('mousemove', handleMouseMove, { passive: false });\r\n document.addEventListener('mouseup', handleMouseUp);\r\n \r\n // 添加禁止选择的样式\r\n document.body.style.cursor = 'col-resize';\r\n document.body.style.userSelect = 'none';\r\n };\r\n \r\n // 处理鼠标移动 - 使用 requestAnimationFrame 优化性能\r\n let rafId: number | null = null;\r\n const handleMouseMove = (event: MouseEvent) => {\r\n if (!resizing.value || resizingIndex.value < 0) return;\r\n \r\n event.preventDefault();\r\n \r\n // 取消之前的动画帧\r\n if (rafId !== null) {\r\n cancelAnimationFrame(rafId);\r\n }\r\n \r\n // 使用 requestAnimationFrame 确保流畅更新\r\n rafId = requestAnimationFrame(() => {\r\n const deltaX = event.clientX - startX.value;\r\n const newWidth = Math.max(50, startWidth.value + deltaX);\r\n \r\n // 直接设置 DOM 样式,避免 Vue 响应式更新延迟\r\n if (currentHeaderElement.value) {\r\n currentHeaderElement.value.style.width = `${newWidth}px`;\r\n }\r\n \r\n // 同时更新对应的内容列\r\n const contentCells = document.querySelectorAll(\r\n `.cellNo[columnindex=\"${resizingIndex.value}\"], .cell[columnindex=\"${resizingIndex.value}\"]`\r\n );\r\n contentCells.forEach((cell) => {\r\n (cell as HTMLElement).style.minWidth = `${newWidth}px`;\r\n (cell as HTMLElement).style.maxWidth = `${newWidth}px`;\r\n });\r\n \r\n rafId = null;\r\n });\r\n };\r\n \r\n // 处理鼠标释放\r\n const handleMouseUp = () => {\r\n if (!resizing.value) return;\r\n \r\n // 取消未完成的动画帧\r\n if (rafId !== null) {\r\n cancelAnimationFrame(rafId);\r\n rafId = null;\r\n }\r\n \r\n // 计算最终宽度并更新到 props\r\n if (currentHeaderElement.value && resizingIndex.value >= 0) {\r\n const finalWidth = parseInt(currentHeaderElement.value.style.width);\r\n props.headers[resizingIndex.value].width = finalWidth;\r\n }\r\n \r\n resizing.value = false;\r\n resizingIndex.value = -1;\r\n currentHeaderElement.value = null;\r\n \r\n // 移除全局事件监听\r\n document.removeEventListener('mousemove', handleMouseMove);\r\n document.removeEventListener('mouseup', handleMouseUp);\r\n \r\n // 恢复样式\r\n document.body.style.cursor = '';\r\n document.body.style.userSelect = '';\r\n };\r\n \r\n return {\r\n getHeaderTitle,\r\n startResize\r\n };\r\n }\r\n });\r\n </script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.header {\r\n height: 100%;\r\n display: flex;\r\n flex-flow: row nowrap;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n font-family: var(--font-family, 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif);\r\n \r\n .headerCaption {\r\n text-align: center;\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: center;\r\n position: relative;\r\n color: var(--text-primary, #333333);\r\n font-size: 14px;\r\n font-weight: 600;\r\n box-sizing: border-box;\r\n letter-spacing: 0.5px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n transition: all var(--transition-fast, 0.15s ease);\r\n flex-shrink: 0;\r\n \r\n &::before {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n bottom: 0;\r\n left: 0;\r\n border-top: 1px solid var(--border, #cecece);\r\n border-bottom: 1px solid var(--border, #cecece);\r\n pointer-events: none;\r\n }\r\n \r\n &:not(:last-child)::after {\r\n content: '';\r\n position: absolute;\r\n right: -1px;\r\n top: 0;\r\n bottom: 0;\r\n background: var(--border, #cecece);\r\n border-left: 1px solid var(--border, #cecece);\r\n }\r\n \r\n &:first-child::before {\r\n border-left: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:last-child::before {\r\n border-right: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:hover {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n color: var(--primary, #0078d4);\r\n }\r\n\r\n // 列宽调整拖动手柄\r\n .resize-handle {\r\n position: absolute;\r\n right: -4px;\r\n top: 0;\r\n bottom: 0;\r\n width: 8px;\r\n cursor: col-resize;\r\n z-index: 10;\r\n background: transparent;\r\n transition: background 0.2s ease;\r\n\r\n &::before {\r\n content: '';\r\n position: absolute;\r\n left: 50%;\r\n top: 50%;\r\n transform: translate(-50%, -50%);\r\n width: 2px;\r\n height: 60%;\r\n background: transparent;\r\n transition: background 0.2s ease;\r\n }\r\n\r\n &:hover {\r\n background: rgba(51, 112, 255, 0.1);\r\n\r\n &::before {\r\n background: var(--primary, #3370ff);\r\n }\r\n }\r\n\r\n &:active {\r\n background: rgba(51, 112, 255, 0.15);\r\n }\r\n }\r\n }\r\n}\r\n</style>","import { reactive } from 'vue';\r\n\r\n// 定义 Store 接口\r\ninterface StoreType {\r\n monthHeaders: any[];\r\n weekHeaders: any[];\r\n dayHeaders: any[];\r\n hourHeaders: any[];\r\n tasks: any[];\r\n taskHeaders: any[];\r\n mapFields: Record<string, any>;\r\n scale: number;\r\n timelineCellCount: number;\r\n startGanttDate: Date | null;\r\n endGanttDate: Date | null;\r\n scrollFlag: boolean;\r\n mode: string | null;\r\n expandRow: {\r\n pid: number;\r\n expand: boolean;\r\n };\r\n collapsedTasks: Set<any>; // 记录已折叠的任务ID集合\r\n rootTask: any;\r\n subTask: any;\r\n editTask: any;\r\n removeTask: any;\r\n allowChangeTaskDate: any;\r\n barDate: {\r\n id: string;\r\n startDate: string;\r\n endDate: string;\r\n };\r\n}\r\n\r\n// 初始状态\r\nconst initialStore: StoreType = {\r\n monthHeaders: [],\r\n weekHeaders: [],\r\n dayHeaders: [],\r\n hourHeaders: [],\r\n tasks: [],\r\n taskHeaders: [],\r\n mapFields: {},\r\n scale: 90,\r\n timelineCellCount: 0,\r\n startGanttDate: null,\r\n endGanttDate: null,\r\n scrollFlag: true,\r\n mode: null,\r\n expandRow: {\r\n pid: 0,\r\n expand: true\r\n },\r\n collapsedTasks: new Set(),\r\n rootTask: {},\r\n subTask: {},\r\n editTask: {},\r\n removeTask: {},\r\n allowChangeTaskDate: {},\r\n barDate: {\r\n id: '',\r\n startDate: '',\r\n endDate: ''\r\n }\r\n};\r\n\r\nexport let serialNumber: number = 0;\r\n// 使用reactive保证响应式正常工作\r\nexport let store = reactive(initialStore) as StoreType;\r\n\r\n// 定义 Mutations 类型\r\ninterface MutationsType {\r\n setMonthHeaders: (monthHeaders: any[]) => void;\r\n setDayHeaders: (dayHeaders: any[]) => void;\r\n setTasks: (tasks: any[]) => void;\r\n setTaskHeaders: (taskHeaders: any[]) => void;\r\n setWeekHeaders: (weekHeaders: any[]) => void;\r\n setHourHeaders: (hourHeaders: any[]) => void;\r\n setScale: (scale: number) => void;\r\n setMapFields: (mapFields: Record<string, any>) => void;\r\n setTimelineCellCount: (timelineCellCount: number) => void;\r\n setStartGanttDate: (startGanttDate: Date | null) => void;\r\n setEndGanttDate: (endGanttDate: Date | null) => void;\r\n setScrollFlag: (scrollFlag: boolean) => void;\r\n setMode: (mode: string | null) => void;\r\n setExpandRow: (expandRow: { pid: number; expand: boolean }) => void;\r\n toggleTaskCollapse: (taskId: any) => void; // 切换任务折叠状态\r\n setRootTask: (rootTask: any) => void;\r\n setSubTask: (subTask: any) => void;\r\n setEditTask: (editTask: any) => void;\r\n setRemoveTask: (removeTask: any) => void;\r\n setBarDate: (barDate: { id: string; startDate: string; endDate: string }) => void;\r\n setAllowChangeTaskDate: (task: any) => void;\r\n}\r\n\r\n// 定义 Mutations\r\nexport let mutations: MutationsType = {\r\n setMonthHeaders(monthHeaders: any[]): void {\r\n store.monthHeaders = monthHeaders;\r\n },\r\n setDayHeaders(dayHeaders: any[]): void {\r\n store.dayHeaders = dayHeaders;\r\n },\r\n setTasks(tasks: any[]): void {\r\n store.tasks = tasks;\r\n },\r\n setTaskHeaders(taskHeaders: any[]): void {\r\n store.taskHeaders = taskHeaders;\r\n },\r\n setWeekHeaders(weekHeaders: any[]): void {\r\n store.weekHeaders = weekHeaders;\r\n },\r\n setHourHeaders(hourHeaders: any[]): void {\r\n store.hourHeaders = hourHeaders;\r\n },\r\n setScale(scale: number): void {\r\n store.scale = scale;\r\n },\r\n setMapFields(mapFields: Record<string, any>): void {\r\n store.mapFields = mapFields;\r\n },\r\n setTimelineCellCount(timelineCellCount: number): void {\r\n store.timelineCellCount = timelineCellCount;\r\n },\r\n setStartGanttDate(startGanttDate: Date | null): void {\r\n store.startGanttDate = startGanttDate;\r\n },\r\n setEndGanttDate(endGanttDate: Date | null): void {\r\n store.endGanttDate = endGanttDate;\r\n },\r\n setScrollFlag(scrollFlag: boolean): void {\r\n store.scrollFlag = scrollFlag;\r\n },\r\n setMode(mode: string | null): void {\r\n store.mode = mode;\r\n },\r\n setExpandRow(expandRow: { pid: number; expand: boolean }): void {\r\n store.expandRow = expandRow;\r\n },\r\n toggleTaskCollapse(taskId: any): void {\r\n if (store.collapsedTasks.has(taskId)) {\r\n store.collapsedTasks.delete(taskId);\r\n } else {\r\n store.collapsedTasks.add(taskId);\r\n }\r\n // 触发响应式更新\r\n store.collapsedTasks = new Set(store.collapsedTasks);\r\n },\r\n setRootTask(rootTask: any): void {\r\n store.rootTask = rootTask;\r\n },\r\n setSubTask(subTask: any): void {\r\n store.subTask = subTask;\r\n },\r\n setEditTask(editTask: any): void {\r\n store.editTask = editTask;\r\n },\r\n setRemoveTask(removeTask: any): void {\r\n store.removeTask = removeTask;\r\n },\r\n setBarDate(barDate: { id: string; startDate: string; endDate: string }): void {\r\n store.barDate = barDate;\r\n },\r\n setAllowChangeTaskDate(task: any): void {\r\n store.allowChangeTaskDate = task;\r\n }\r\n};","import { reactive, ref } from 'vue';\r\n\r\nconst sharedState = reactive({\r\n shouldScrollToToday: false,\r\n triggerScrollToToday() {\r\n this.shouldScrollToToday = true;\r\n },\r\n\r\n shouldScroll: false,\r\n triggerScroll() {\r\n this.shouldScroll = true;\r\n },\r\n\r\n highlightedId: <number | null> null,\r\n triggerHighlight(id: number | null) {\r\n this.highlightedId = id;\r\n }\r\n});\r\nexport default sharedState;\r\n\r\n// 创建一个 ref 来存储滚动位置 \r\nconst scrollTop = ref(0); \r\n// 创建一个 ref 来存储滚动标志 \r\nconst scrollFlag = ref(false); \r\n \r\n// 定义设置滚动位置的函数 \r\n// 为了避免隐式的 'any' 类型错误,明确指定参数 'value' 的类型为 'number'\r\nconst setScrollTop = (value: number) => {\r\n scrollTop.value = value; \r\n}; \r\n \r\n// 定义设置滚动标志的函数 \r\n// 为了避免隐式的 'any' 类型错误,明确指定参数 'value' 的类型为 'boolean'\r\nconst setScrollFlag = (value: boolean) => {\r\n scrollFlag.value = value; \r\n}; \r\n \r\n// 导出共享状态和方法 \r\nexport const useScrollState = () => { \r\n return { \r\n scrollTop, \r\n scrollFlag, \r\n setScrollTop, \r\n setScrollFlag \r\n }; \r\n}; ","<template>\r\n <div v-if='showRow' @mouseover=\"hoverActive()\" @mouseleave=\"hoverInactive()\" :class=\"{ active: hover }\">\r\n <div class=\"row\" @dblclick=\"setEditTask(row)\" v-bind:style=\"{ height: rowHeight + 'px' }\">\r\n <template v-for='(header, headerIndex) in headers'>\r\n <div \r\n class=\"cellNo\" \r\n :key=\"headerIndex\" \r\n :columnindex=\"headerIndex\"\r\n v-if=\"header.property === 'no'\" \r\n v-bind:style=\"{\r\n minWidth: header.width + 'px',\r\n maxWidth: header.width + 'px',\r\n height: rowHeight + 'px'\r\n }\">\r\n <div class=\"no-cell-content\">\r\n <!-- 树形连线 -->\r\n <div class=\"tree-lines\">\r\n <!-- 祖先节点的贯穿线(连接兄弟节点) -->\r\n <div \r\n v-for=\"level in getAncestorLines\" \r\n :key=\"'ancestor-' + level\" \r\n class=\"tree-line-vertical ancestor\"\r\n :style=\"{ left: level * 16 + 8 + 'px' }\"\r\n ></div>\r\n \r\n <!-- 顶级节点有子节点且未折叠时,显示向下的竖线 -->\r\n <div \r\n v-if=\"row.treeLevel === 1 && hasChildren && !isCollapsed\"\r\n class=\"tree-line-vertical parent-to-child\"\r\n :style=\"{ left: row.treeLevel * 16 + 8 + 'px' }\"\r\n ></div>\r\n \r\n <!-- 子节点的连接线 -->\r\n <template v-if=\"row.treeLevel && row.treeLevel > 1\">\r\n <!-- 当前节点的垂直线 -->\r\n <div \r\n class=\"tree-line-vertical current\"\r\n :class=\"{ 'is-last-child': isLastChild }\"\r\n :style=\"{ left: (row.treeLevel - 1) * 16 + 8 + 'px' }\"\r\n ></div>\r\n \r\n <!-- 水平线(连接到当前节点) -->\r\n <div \r\n class=\"tree-line-horizontal\"\r\n :style=\"{ left: (row.treeLevel - 1) * 16 + 8 + 'px', width: '32px' }\"\r\n ></div>\r\n \r\n <!-- 如果当前节点有子节点且未折叠,显示向下的竖线 -->\r\n <div \r\n v-if=\"hasChildren && !isCollapsed\"\r\n class=\"tree-line-vertical parent-to-child\"\r\n :style=\"{ left: row.treeLevel * 16 + 8 + 'px' }\"\r\n ></div>\r\n </template>\r\n </div>\r\n \r\n <!-- 左侧:折叠按钮 + 序号 -->\r\n <div class=\"no-left-section\" :style=\"{ paddingLeft: (row.treeLevel || 0) * 16 + 'px' }\">\r\n <!-- 折叠/展开按钮 -->\r\n <button \r\n v-if=\"hasChildren\" \r\n @click.stop=\"toggleCollapse\" \r\n class=\"collapse-btn\"\r\n :class=\"{ collapsed: isCollapsed }\"\r\n :title=\"isCollapsed ? '展开' : '折叠'\"\r\n >\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <!-- 三角形箭头 -->\r\n <path \r\n class=\"arrow\" \r\n d=\"M5 4 L14 9 L5 14 Z\" \r\n fill=\"currentColor\"\r\n />\r\n </svg>\r\n </button>\r\n <!-- 无子节点时的占位空间(透明,不遮挡横线) -->\r\n <span v-else class=\"collapse-placeholder\"></span>\r\n \r\n <!-- 序号 -->\r\n <span class=\"no-text\">{{ row.no }}</span>\r\n </div>\r\n \r\n <!-- 右侧:操作按钮(鼠标悬停显示) -->\r\n <div class=\"action-buttons\">\r\n <button \r\n @click.stop=\"setSubTask(row)\" \r\n class=\"action-btn add-btn\"\r\n :title=\"'添加子任务'\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\r\n <path d=\"M8 2a.5.5 0 01.5.5v5h5a.5.5 0 010 1h-5v5a.5.5 0 01-1 0v-5h-5a.5.5 0 010-1h5v-5A.5.5 0 018 2z\"/>\r\n </svg>\r\n </button>\r\n <button \r\n @click.stop=\"setRemoveTask(row)\" \r\n class=\"action-btn delete-btn\"\r\n :title=\"'删除任务'\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\r\n <path d=\"M5.5 5.5A.5.5 0 016 6v6a.5.5 0 01-1 0V6a.5.5 0 01.5-.5zm2.5 0a.5.5 0 01.5.5v6a.5.5 0 01-1 0V6a.5.5 0 01.5-.5zm3 .5a.5.5 0 00-1 0v6a.5.5 0 001 0V6z\"/>\r\n <path fill-rule=\"evenodd\" d=\"M14.5 3a1 1 0 01-1 1H13v9a2 2 0 01-2 2H5a2 2 0 01-2-2V4h-.5a1 1 0 01-1-1V2a1 1 0 011-1H6a1 1 0 011-1h2a1 1 0 011 1h3.5a1 1 0 011 1v1zM4.118 4L4 4.059V13a1 1 0 001 1h6a1 1 0 001-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n <div \r\n v-else \r\n v-show=\"header.show\" \r\n class=\"cell\" \r\n :key=\"headerIndex + '-header'\"\r\n :columnindex=\"headerIndex\"\r\n :style=\"{ minWidth: header.width + 'px', maxWidth: header.width + 'px', height: rowHeight + 'px' }\">\r\n {{ checkField(row, header.property) }}\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, onMounted, computed, inject, watch } from 'vue';\r\nimport { store, mutations } from '../Store';\r\nimport sharedState from '../ShareState';\r\n\r\nexport default defineComponent({\r\n props: {\r\n headers: {\r\n type: Array as () => any[],\r\n default: () => []\r\n },\r\n rowHeight: {\r\n type: Number,\r\n default: 0\r\n },\r\n row: {\r\n type: Object as () => Record<string, any>,\r\n default: () => ({})\r\n }\r\n },\r\n setup(props) {\r\n const showRow = ref(true);\r\n const hover = ref(false);\r\n const addTips = '添加子任务';\r\n const removeTips = '删除当前任务';\r\n\r\n const mapFields = computed(() => store.mapFields);\r\n const subTask = computed(() => store.subTask);\r\n const collapsedTasks = computed(() => store.collapsedTasks);\r\n\r\n const barHover = inject('barHover') as ((rowId: any, hover: boolean) => void) | undefined;\r\n const addRootTask = inject('addRootTask') as ((row: any) => void) | undefined;\r\n\r\n // 判断当前任务是否有子任务\r\n const hasChildren = computed(() => {\r\n const currentId = props.row[mapFields.value['id']];\r\n return store.tasks.some(task => task[mapFields.value['parentId']] === currentId);\r\n });\r\n\r\n // 判断当前任务是否已折叠\r\n const isCollapsed = computed(() => {\r\n const currentId = props.row[mapFields.value['id']];\r\n return collapsedTasks.value.has(currentId);\r\n });\r\n \r\n // 判断是否是最后一个子节点\r\n const isLastChild = computed(() => {\r\n const parentId = props.row[mapFields.value['parentId']];\r\n if (!parentId || parentId === '0') return false;\r\n \r\n const siblings = store.tasks.filter(task => \r\n task[mapFields.value['parentId']] === parentId\r\n );\r\n \r\n if (siblings.length === 0) return false;\r\n \r\n const currentId = props.row[mapFields.value['id']];\r\n const lastSibling = siblings[siblings.length - 1];\r\n return lastSibling[mapFields.value['id']] === currentId;\r\n });\r\n \r\n // 获取需要显示祖先贯穿线的层级\r\n const getAncestorLines = computed(() => {\r\n const lines: number[] = [];\r\n const treeLevel = props.row.treeLevel || 0;\r\n \r\n if (treeLevel <= 1) return lines;\r\n \r\n // 当前节点的 current 线位置对应的层级(需要过滤掉,避免重叠)\r\n const currentLineLevel = treeLevel - 1;\r\n \r\n // 构建从根到当前节点的路径\r\n const path: any[] = [];\r\n let currentTask = props.row;\r\n \r\n while (currentTask) {\r\n path.unshift(currentTask);\r\n const parentId = currentTask[mapFields.value['parentId']];\r\n if (!parentId || parentId === '0') break;\r\n \r\n const parent = store.tasks.find(task => \r\n task[mapFields.value['id']] === parentId\r\n );\r\n if (!parent) break;\r\n currentTask = parent;\r\n }\r\n \r\n // 从直接父节点开始向上检查,遇到\"最后一个子节点\"就停止\r\n for (let i = path.length - 2; i >= 0; i--) {\r\n const node = path[i];\r\n const nodeId = node[mapFields.value['id']];\r\n const parentId = node[mapFields.value['parentId']];\r\n \r\n // 查找该节点的所有兄弟节点\r\n const siblings = store.tasks.filter(task => \r\n task[mapFields.value['parentId']] === parentId\r\n );\r\n \r\n if (siblings.length > 0) {\r\n const lastSibling = siblings[siblings.length - 1];\r\n const isLast = lastSibling[mapFields.value['id']] === nodeId;\r\n \r\n if (isLast) {\r\n // 如果这个节点是最后一个子节点,停止添加贯穿线\r\n break;\r\n } else {\r\n // 如果不是最后一个,需要显示贯穿线\r\n const nodeTreeLevel = node.treeLevel;\r\n // 过滤掉和 current 线位置相同的层级\r\n if (nodeTreeLevel && nodeTreeLevel >= 1 && nodeTreeLevel !== currentLineLevel) {\r\n lines.push(nodeTreeLevel);\r\n }\r\n }\r\n }\r\n }\r\n \r\n return lines;\r\n });\r\n \r\n // 切换折叠状态\r\n const toggleCollapse = () => {\r\n const currentId = props.row[mapFields.value['id']];\r\n mutations.toggleTaskCollapse(currentId);\r\n };\r\n\r\n onMounted(() => {\r\n\r\n });\r\n\r\n const setSubTask = mutations.setSubTask;\r\n const setEditTask = mutations.setEditTask;\r\n const setRemoveTask = mutations.setRemoveTask;\r\n\r\n const checkField = (row: Record<string, any>, property: string) => {\r\n if (mapFields.value[property]) {\r\n return row[mapFields.value[property]];\r\n } else if (row[property]) {\r\n return row[property];\r\n }\r\n return null;\r\n };\r\n\r\n watch(() => sharedState.highlightedId, (newId) => {\r\n if (props.row[mapFields.value['id']] === newId) {\r\n hover.value = true;\r\n } else {\r\n hover.value = false;\r\n }\r\n });\r\n\r\n const hoverActive = () => {\r\n sharedState.triggerHighlight(props.row[mapFields.value.id] as number|null);\r\n };\r\n\r\n const hoverInactive = () => {\r\n sharedState.triggerHighlight(null);\r\n };\r\n\r\n const handleAddRootTask = () => {\r\n if (addRootTask) {\r\n addRootTask(props.row);\r\n }\r\n };\r\n\r\n return {\r\n showRow,\r\n hover,\r\n addTips,\r\n removeTips,\r\n mapFields,\r\n subTask,\r\n hasChildren,\r\n isCollapsed,\r\n isLastChild,\r\n getAncestorLines,\r\n toggleCollapse,\r\n setSubTask,\r\n setEditTask,\r\n setRemoveTask,\r\n checkField,\r\n hoverActive,\r\n hoverInactive,\r\n addRootTask: handleAddRootTask\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.active .row {\r\n background: var(--row-hover, #FFF3A1) !important;\r\n}\r\n\r\n.row {\r\n display: flex;\r\n flex-flow: row nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n border-top: none;\r\n border-bottom: none;\r\n width: fit-content;\r\n background: var(--bg-content, #ffffff);\r\n color: var(--text-primary, #333333);\r\n\r\n &:first-child {\r\n border-top: 1px solid var(--border, #cecece);\r\n border-bottom: none;\r\n }\r\n\r\n &:not(:first-child:last-child) {\r\n border-right: 1px solid var(--border, #cecece);\r\n border-top: 1px solid var(--border, #cecece);\r\n border-bottom: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:last-child {\r\n border-top: none;\r\n border-bottom: 1px solid var(--border, #cecece);\r\n }\r\n\r\n .cellNo {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n font-size: 12px;\r\n border-top: none;\r\n border-bottom: none;\r\n margin: 0px 0px 0px 1px;\r\n position: relative;\r\n color: var(--text-primary, #333333);\r\n padding: 0 8px;\r\n\r\n &:first-child {\r\n border-left: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:not(:last-child) {\r\n border-right: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:last-child {\r\n border-right: 1px solid var(--border, #cecece);\r\n }\r\n\r\n .no-cell-content {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n width: 100%;\r\n height: 100%;\r\n position: relative;\r\n }\r\n\r\n .no-left-section {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n flex: 1;\r\n min-width: 0;\r\n }\r\n\r\n .tree-lines {\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n bottom: 0;\r\n width: 100%;\r\n pointer-events: none;\r\n z-index: 0;\r\n }\r\n\r\n .tree-line-vertical {\r\n position: absolute;\r\n width: 1px;\r\n background: var(--border, #d0d0d0);\r\n \r\n // 祖先贯穿线(从顶部到底部)\r\n &.ancestor {\r\n top: 0;\r\n bottom: 0;\r\n }\r\n \r\n &.current {\r\n top: 0;\r\n bottom: 0; // 默认贯穿整行,连接兄弟节点\r\n \r\n // 如果是最后一个子节点,垂直线只到中间(└ 形状)\r\n &.is-last-child {\r\n bottom: 50%;\r\n }\r\n }\r\n \r\n // 父节点到子节点的连接线(从中间向下)\r\n &.parent-to-child {\r\n top: 50%;\r\n bottom: 0;\r\n }\r\n }\r\n\r\n .tree-line-horizontal {\r\n position: absolute;\r\n top: 50%;\r\n height: 1px;\r\n background: var(--border, #d0d0d0);\r\n }\r\n\r\n .collapse-btn {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 22px;\r\n height: 22px;\r\n padding: 0;\r\n border: none;\r\n background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\r\n color: #6c757d;\r\n cursor: pointer;\r\n border-radius: 6px;\r\n transition: all 0.2s ease;\r\n flex-shrink: 0;\r\n position: relative;\r\n z-index: 1;\r\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.8);\r\n\r\n svg {\r\n width: 16px;\r\n height: 16px;\r\n transition: all 0.2s ease;\r\n }\r\n\r\n // 箭头旋转动画 - 展开状态向下\r\n .arrow {\r\n transform-origin: center;\r\n transition: transform 0.2s ease;\r\n transform: rotate(90deg);\r\n }\r\n\r\n // 折叠状态:箭头向右\r\n &.collapsed .arrow {\r\n transform: rotate(0deg);\r\n }\r\n\r\n // 悬停效果\r\n &:hover {\r\n background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);\r\n color: #495057;\r\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.9);\r\n \r\n svg {\r\n transform: scale(1.1);\r\n }\r\n }\r\n\r\n // 激活状态\r\n &:active {\r\n background: linear-gradient(135deg, #dee2e6 0%, #ced4da 100%);\r\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), inset 0 1px 2px rgba(0, 0, 0, 0.1);\r\n \r\n svg {\r\n transform: scale(0.95);\r\n }\r\n }\r\n\r\n // 聚焦状态\r\n &:focus-visible {\r\n outline: 2px solid var(--primary, #3370ff);\r\n outline-offset: 2px;\r\n }\r\n }\r\n\r\n .collapse-placeholder {\r\n width: 22px;\r\n height: 22px;\r\n flex-shrink: 0;\r\n position: relative;\r\n z-index: 1;\r\n // 透明背景,不遮挡横线\r\n }\r\n\r\n .no-text {\r\n flex: 1;\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n font-size: 12px;\r\n font-weight: 500;\r\n color: var(--text-primary, #333333);\r\n position: relative;\r\n z-index: 1;\r\n }\r\n\r\n .action-buttons {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n opacity: 0;\r\n transition: opacity 0.2s ease;\r\n }\r\n\r\n &:hover .action-buttons {\r\n opacity: 1;\r\n }\r\n\r\n .action-btn {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 22px;\r\n height: 22px;\r\n padding: 0;\r\n border: none;\r\n background: transparent;\r\n color: var(--text-secondary, #888);\r\n cursor: pointer;\r\n border-radius: 4px;\r\n transition: all 0.2s ease;\r\n flex-shrink: 0;\r\n\r\n svg {\r\n width: 14px;\r\n height: 14px;\r\n }\r\n\r\n &:hover {\r\n background: var(--hover-bg, rgba(0, 0, 0, 0.06));\r\n }\r\n\r\n &:active {\r\n transform: scale(0.95);\r\n }\r\n\r\n &.add-btn:hover {\r\n color: var(--success, #52c41a);\r\n background: rgba(82, 196, 26, 0.1);\r\n }\r\n\r\n &.delete-btn:hover {\r\n color: var(--danger, #ff4d4f);\r\n background: rgba(255, 77, 79, 0.1);\r\n }\r\n }\r\n }\r\n\r\n .cell {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 12px;\r\n border-top: none;\r\n border-bottom: none;\r\n position: relative;\r\n color: var(--text-primary, #333333);\r\n\r\n &::before {\r\n content: '';\r\n position: absolute;\r\n left: -1px;\r\n top: 0;\r\n bottom: 0;\r\n width: 1px;\r\n background: var(--border, #cecece);\r\n }\r\n\r\n &:first-child {\r\n border-left: 1px solid var(--border, #cecece);\r\n\r\n &::before {\r\n display: none;\r\n }\r\n }\r\n\r\n &:not(:last-child) {\r\n border-right: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:last-child {\r\n border-right: 1px solid var(--border, #cecece);\r\n }\r\n }\r\n}\r\n</style>","<template>\r\n <div v-if='showRow' @mouseover=\"hoverActive()\" @mouseleave=\"hoverInactive()\" :class=\"{ active: hover }\">\r\n <div class=\"row\" @dblclick=\"setEditTask(row)\" v-bind:style=\"{ height: rowHeight + 'px' }\">\r\n <template v-for='(header, headerIndex) in headers'>\r\n <div \r\n class=\"cellNo\" \r\n :key=\"headerIndex\" \r\n :columnindex=\"headerIndex\"\r\n v-if=\"header.property === 'no'\" \r\n v-bind:style=\"{\r\n minWidth: header.width + 'px',\r\n maxWidth: header.width + 'px',\r\n height: rowHeight + 'px'\r\n }\">\r\n <div class=\"no-cell-content\">\r\n <!-- 树形连线 -->\r\n <div class=\"tree-lines\">\r\n <!-- 祖先节点的贯穿线(连接兄弟节点) -->\r\n <div \r\n v-for=\"level in getAncestorLines\" \r\n :key=\"'ancestor-' + level\" \r\n class=\"tree-line-vertical ancestor\"\r\n :style=\"{ left: level * 16 + 8 + 'px' }\"\r\n ></div>\r\n \r\n <!-- 顶级节点有子节点且未折叠时,显示向下的竖线 -->\r\n <div \r\n v-if=\"row.treeLevel === 1 && hasChildren && !isCollapsed\"\r\n class=\"tree-line-vertical parent-to-child\"\r\n :style=\"{ left: row.treeLevel * 16 + 8 + 'px' }\"\r\n ></div>\r\n \r\n <!-- 子节点的连接线 -->\r\n <template v-if=\"row.treeLevel && row.treeLevel > 1\">\r\n <!-- 当前节点的垂直线 -->\r\n <div \r\n class=\"tree-line-vertical current\"\r\n :class=\"{ 'is-last-child': isLastChild }\"\r\n :style=\"{ left: (row.treeLevel - 1) * 16 + 8 + 'px' }\"\r\n ></div>\r\n \r\n <!-- 水平线(连接到当前节点) -->\r\n <div \r\n class=\"tree-line-horizontal\"\r\n :style=\"{ left: (row.treeLevel - 1) * 16 + 8 + 'px', width: '32px' }\"\r\n ></div>\r\n \r\n <!-- 如果当前节点有子节点且未折叠,显示向下的竖线 -->\r\n <div \r\n v-if=\"hasChildren && !isCollapsed\"\r\n class=\"tree-line-vertical parent-to-child\"\r\n :style=\"{ left: row.treeLevel * 16 + 8 + 'px' }\"\r\n ></div>\r\n </template>\r\n </div>\r\n \r\n <!-- 左侧:折叠按钮 + 序号 -->\r\n <div class=\"no-left-section\" :style=\"{ paddingLeft: (row.treeLevel || 0) * 16 + 'px' }\">\r\n <!-- 折叠/展开按钮 -->\r\n <button \r\n v-if=\"hasChildren\" \r\n @click.stop=\"toggleCollapse\" \r\n class=\"collapse-btn\"\r\n :class=\"{ collapsed: isCollapsed }\"\r\n :title=\"isCollapsed ? '展开' : '折叠'\"\r\n >\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <!-- 三角形箭头 -->\r\n <path \r\n class=\"arrow\" \r\n d=\"M5 4 L14 9 L5 14 Z\" \r\n fill=\"currentColor\"\r\n />\r\n </svg>\r\n </button>\r\n <!-- 无子节点时的占位空间(透明,不遮挡横线) -->\r\n <span v-else class=\"collapse-placeholder\"></span>\r\n \r\n <!-- 序号 -->\r\n <span class=\"no-text\">{{ row.no }}</span>\r\n </div>\r\n \r\n <!-- 右侧:操作按钮(鼠标悬停显示) -->\r\n <div class=\"action-buttons\">\r\n <button \r\n @click.stop=\"setSubTask(row)\" \r\n class=\"action-btn add-btn\"\r\n :title=\"'添加子任务'\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\r\n <path d=\"M8 2a.5.5 0 01.5.5v5h5a.5.5 0 010 1h-5v5a.5.5 0 01-1 0v-5h-5a.5.5 0 010-1h5v-5A.5.5 0 018 2z\"/>\r\n </svg>\r\n </button>\r\n <button \r\n @click.stop=\"setRemoveTask(row)\" \r\n class=\"action-btn delete-btn\"\r\n :title=\"'删除任务'\"\r\n >\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"currentColor\">\r\n <path d=\"M5.5 5.5A.5.5 0 016 6v6a.5.5 0 01-1 0V6a.5.5 0 01.5-.5zm2.5 0a.5.5 0 01.5.5v6a.5.5 0 01-1 0V6a.5.5 0 01.5-.5zm3 .5a.5.5 0 00-1 0v6a.5.5 0 001 0V6z\"/>\r\n <path fill-rule=\"evenodd\" d=\"M14.5 3a1 1 0 01-1 1H13v9a2 2 0 01-2 2H5a2 2 0 01-2-2V4h-.5a1 1 0 01-1-1V2a1 1 0 011-1H6a1 1 0 011-1h2a1 1 0 011 1h3.5a1 1 0 011 1v1zM4.118 4L4 4.059V13a1 1 0 001 1h6a1 1 0 001-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n <div \r\n v-else \r\n v-show=\"header.show\" \r\n class=\"cell\" \r\n :key=\"headerIndex + '-header'\"\r\n :columnindex=\"headerIndex\"\r\n :style=\"{ minWidth: header.width + 'px', maxWidth: header.width + 'px', height: rowHeight + 'px' }\">\r\n {{ checkField(row, header.property) }}\r\n </div>\r\n </template>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, onMounted, computed, inject, watch } from 'vue';\r\nimport { store, mutations } from '../Store';\r\nimport sharedState from '../ShareState';\r\n\r\nexport default defineComponent({\r\n props: {\r\n headers: {\r\n type: Array as () => any[],\r\n default: () => []\r\n },\r\n rowHeight: {\r\n type: Number,\r\n default: 0\r\n },\r\n row: {\r\n type: Object as () => Record<string, any>,\r\n default: () => ({})\r\n }\r\n },\r\n setup(props) {\r\n const showRow = ref(true);\r\n const hover = ref(false);\r\n const addTips = '添加子任务';\r\n const removeTips = '删除当前任务';\r\n\r\n const mapFields = computed(() => store.mapFields);\r\n const subTask = computed(() => store.subTask);\r\n const collapsedTasks = computed(() => store.collapsedTasks);\r\n\r\n const barHover = inject('barHover') as ((rowId: any, hover: boolean) => void) | undefined;\r\n const addRootTask = inject('addRootTask') as ((row: any) => void) | undefined;\r\n\r\n // 判断当前任务是否有子任务\r\n const hasChildren = computed(() => {\r\n const currentId = props.row[mapFields.value['id']];\r\n return store.tasks.some(task => task[mapFields.value['parentId']] === currentId);\r\n });\r\n\r\n // 判断当前任务是否已折叠\r\n const isCollapsed = computed(() => {\r\n const currentId = props.row[mapFields.value['id']];\r\n return collapsedTasks.value.has(currentId);\r\n });\r\n \r\n // 判断是否是最后一个子节点\r\n const isLastChild = computed(() => {\r\n const parentId = props.row[mapFields.value['parentId']];\r\n if (!parentId || parentId === '0') return false;\r\n \r\n const siblings = store.tasks.filter(task => \r\n task[mapFields.value['parentId']] === parentId\r\n );\r\n \r\n if (siblings.length === 0) return false;\r\n \r\n const currentId = props.row[mapFields.value['id']];\r\n const lastSibling = siblings[siblings.length - 1];\r\n return lastSibling[mapFields.value['id']] === currentId;\r\n });\r\n \r\n // 获取需要显示祖先贯穿线的层级\r\n const getAncestorLines = computed(() => {\r\n const lines: number[] = [];\r\n const treeLevel = props.row.treeLevel || 0;\r\n \r\n if (treeLevel <= 1) return lines;\r\n \r\n // 当前节点的 current 线位置对应的层级(需要过滤掉,避免重叠)\r\n const currentLineLevel = treeLevel - 1;\r\n \r\n // 构建从根到当前节点的路径\r\n const path: any[] = [];\r\n let currentTask = props.row;\r\n \r\n while (currentTask) {\r\n path.unshift(currentTask);\r\n const parentId = currentTask[mapFields.value['parentId']];\r\n if (!parentId || parentId === '0') break;\r\n \r\n const parent = store.tasks.find(task => \r\n task[mapFields.value['id']] === parentId\r\n );\r\n if (!parent) break;\r\n currentTask = parent;\r\n }\r\n \r\n // 从直接父节点开始向上检查,遇到\"最后一个子节点\"就停止\r\n for (let i = path.length - 2; i >= 0; i--) {\r\n const node = path[i];\r\n const nodeId = node[mapFields.value['id']];\r\n const parentId = node[mapFields.value['parentId']];\r\n \r\n // 查找该节点的所有兄弟节点\r\n const siblings = store.tasks.filter(task => \r\n task[mapFields.value['parentId']] === parentId\r\n );\r\n \r\n if (siblings.length > 0) {\r\n const lastSibling = siblings[siblings.length - 1];\r\n const isLast = lastSibling[mapFields.value['id']] === nodeId;\r\n \r\n if (isLast) {\r\n // 如果这个节点是最后一个子节点,停止添加贯穿线\r\n break;\r\n } else {\r\n // 如果不是最后一个,需要显示贯穿线\r\n const nodeTreeLevel = node.treeLevel;\r\n // 过滤掉和 current 线位置相同的层级\r\n if (nodeTreeLevel && nodeTreeLevel >= 1 && nodeTreeLevel !== currentLineLevel) {\r\n lines.push(nodeTreeLevel);\r\n }\r\n }\r\n }\r\n }\r\n \r\n return lines;\r\n });\r\n \r\n // 切换折叠状态\r\n const toggleCollapse = () => {\r\n const currentId = props.row[mapFields.value['id']];\r\n mutations.toggleTaskCollapse(currentId);\r\n };\r\n\r\n onMounted(() => {\r\n\r\n });\r\n\r\n const setSubTask = mutations.setSubTask;\r\n const setEditTask = mutations.setEditTask;\r\n const setRemoveTask = mutations.setRemoveTask;\r\n\r\n const checkField = (row: Record<string, any>, property: string) => {\r\n if (mapFields.value[property]) {\r\n return row[mapFields.value[property]];\r\n } else if (row[property]) {\r\n return row[property];\r\n }\r\n return null;\r\n };\r\n\r\n watch(() => sharedState.highlightedId, (newId) => {\r\n if (props.row[mapFields.value['id']] === newId) {\r\n hover.value = true;\r\n } else {\r\n hover.value = false;\r\n }\r\n });\r\n\r\n const hoverActive = () => {\r\n sharedState.triggerHighlight(props.row[mapFields.value.id] as number|null);\r\n };\r\n\r\n const hoverInactive = () => {\r\n sharedState.triggerHighlight(null);\r\n };\r\n\r\n const handleAddRootTask = () => {\r\n if (addRootTask) {\r\n addRootTask(props.row);\r\n }\r\n };\r\n\r\n return {\r\n showRow,\r\n hover,\r\n addTips,\r\n removeTips,\r\n mapFields,\r\n subTask,\r\n hasChildren,\r\n isCollapsed,\r\n isLastChild,\r\n getAncestorLines,\r\n toggleCollapse,\r\n setSubTask,\r\n setEditTask,\r\n setRemoveTask,\r\n checkField,\r\n hoverActive,\r\n hoverInactive,\r\n addRootTask: handleAddRootTask\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.active .row {\r\n background: var(--row-hover, #FFF3A1) !important;\r\n}\r\n\r\n.row {\r\n display: flex;\r\n flex-flow: row nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n border-top: none;\r\n border-bottom: none;\r\n width: fit-content;\r\n background: var(--bg-content, #ffffff);\r\n color: var(--text-primary, #333333);\r\n\r\n &:first-child {\r\n border-top: 1px solid var(--border, #cecece);\r\n border-bottom: none;\r\n }\r\n\r\n &:not(:first-child:last-child) {\r\n border-right: 1px solid var(--border, #cecece);\r\n border-top: 1px solid var(--border, #cecece);\r\n border-bottom: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:last-child {\r\n border-top: none;\r\n border-bottom: 1px solid var(--border, #cecece);\r\n }\r\n\r\n .cellNo {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n font-size: 12px;\r\n border-top: none;\r\n border-bottom: none;\r\n margin: 0px 0px 0px 1px;\r\n position: relative;\r\n color: var(--text-primary, #333333);\r\n padding: 0 8px;\r\n\r\n &:first-child {\r\n border-left: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:not(:last-child) {\r\n border-right: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:last-child {\r\n border-right: 1px solid var(--border, #cecece);\r\n }\r\n\r\n .no-cell-content {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n width: 100%;\r\n height: 100%;\r\n position: relative;\r\n }\r\n\r\n .no-left-section {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n flex: 1;\r\n min-width: 0;\r\n }\r\n\r\n .tree-lines {\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n bottom: 0;\r\n width: 100%;\r\n pointer-events: none;\r\n z-index: 0;\r\n }\r\n\r\n .tree-line-vertical {\r\n position: absolute;\r\n width: 1px;\r\n background: var(--border, #d0d0d0);\r\n \r\n // 祖先贯穿线(从顶部到底部)\r\n &.ancestor {\r\n top: 0;\r\n bottom: 0;\r\n }\r\n \r\n &.current {\r\n top: 0;\r\n bottom: 0; // 默认贯穿整行,连接兄弟节点\r\n \r\n // 如果是最后一个子节点,垂直线只到中间(└ 形状)\r\n &.is-last-child {\r\n bottom: 50%;\r\n }\r\n }\r\n \r\n // 父节点到子节点的连接线(从中间向下)\r\n &.parent-to-child {\r\n top: 50%;\r\n bottom: 0;\r\n }\r\n }\r\n\r\n .tree-line-horizontal {\r\n position: absolute;\r\n top: 50%;\r\n height: 1px;\r\n background: var(--border, #d0d0d0);\r\n }\r\n\r\n .collapse-btn {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 22px;\r\n height: 22px;\r\n padding: 0;\r\n border: none;\r\n background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);\r\n color: #6c757d;\r\n cursor: pointer;\r\n border-radius: 6px;\r\n transition: all 0.2s ease;\r\n flex-shrink: 0;\r\n position: relative;\r\n z-index: 1;\r\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.8);\r\n\r\n svg {\r\n width: 16px;\r\n height: 16px;\r\n transition: all 0.2s ease;\r\n }\r\n\r\n // 箭头旋转动画 - 展开状态向下\r\n .arrow {\r\n transform-origin: center;\r\n transition: transform 0.2s ease;\r\n transform: rotate(90deg);\r\n }\r\n\r\n // 折叠状态:箭头向右\r\n &.collapsed .arrow {\r\n transform: rotate(0deg);\r\n }\r\n\r\n // 悬停效果\r\n &:hover {\r\n background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%);\r\n color: #495057;\r\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.9);\r\n \r\n svg {\r\n transform: scale(1.1);\r\n }\r\n }\r\n\r\n // 激活状态\r\n &:active {\r\n background: linear-gradient(135deg, #dee2e6 0%, #ced4da 100%);\r\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), inset 0 1px 2px rgba(0, 0, 0, 0.1);\r\n \r\n svg {\r\n transform: scale(0.95);\r\n }\r\n }\r\n\r\n // 聚焦状态\r\n &:focus-visible {\r\n outline: 2px solid var(--primary, #3370ff);\r\n outline-offset: 2px;\r\n }\r\n }\r\n\r\n .collapse-placeholder {\r\n width: 22px;\r\n height: 22px;\r\n flex-shrink: 0;\r\n position: relative;\r\n z-index: 1;\r\n // 透明背景,不遮挡横线\r\n }\r\n\r\n .no-text {\r\n flex: 1;\r\n min-width: 0;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n font-size: 12px;\r\n font-weight: 500;\r\n color: var(--text-primary, #333333);\r\n position: relative;\r\n z-index: 1;\r\n }\r\n\r\n .action-buttons {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n opacity: 0;\r\n transition: opacity 0.2s ease;\r\n }\r\n\r\n &:hover .action-buttons {\r\n opacity: 1;\r\n }\r\n\r\n .action-btn {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 22px;\r\n height: 22px;\r\n padding: 0;\r\n border: none;\r\n background: transparent;\r\n color: var(--text-secondary, #888);\r\n cursor: pointer;\r\n border-radius: 4px;\r\n transition: all 0.2s ease;\r\n flex-shrink: 0;\r\n\r\n svg {\r\n width: 14px;\r\n height: 14px;\r\n }\r\n\r\n &:hover {\r\n background: var(--hover-bg, rgba(0, 0, 0, 0.06));\r\n }\r\n\r\n &:active {\r\n transform: scale(0.95);\r\n }\r\n\r\n &.add-btn:hover {\r\n color: var(--success, #52c41a);\r\n background: rgba(82, 196, 26, 0.1);\r\n }\r\n\r\n &.delete-btn:hover {\r\n color: var(--danger, #ff4d4f);\r\n background: rgba(255, 77, 79, 0.1);\r\n }\r\n }\r\n }\r\n\r\n .cell {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 12px;\r\n border-top: none;\r\n border-bottom: none;\r\n position: relative;\r\n color: var(--text-primary, #333333);\r\n\r\n &::before {\r\n content: '';\r\n position: absolute;\r\n left: -1px;\r\n top: 0;\r\n bottom: 0;\r\n width: 1px;\r\n background: var(--border, #cecece);\r\n }\r\n\r\n &:first-child {\r\n border-left: 1px solid var(--border, #cecece);\r\n\r\n &::before {\r\n display: none;\r\n }\r\n }\r\n\r\n &:not(:last-child) {\r\n border-right: 1px solid var(--border, #cecece);\r\n }\r\n\r\n &:last-child {\r\n border-right: 1px solid var(--border, #cecece);\r\n }\r\n }\r\n}\r\n</style>","<template>\r\n <div>\r\n <template v-for=\"item in filterTask\" :key=\"item.id + '_taskrow'\">\r\n <template v-if=\"headers\">\r\n <TaskRow \r\n :headers=\"headers\" \r\n :rowHeight=\"rowHeight\" \r\n :row=\"item\" \r\n />\r\n </template>\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed, watch } from 'vue';\r\nimport { store, mutations } from '../Store';\r\nimport TaskRow from './TaskRow.vue';\r\n\r\nexport default defineComponent({\r\n props: {\r\n headers: Array as () => any[],\r\n rowHeight: Number as () => number,\r\n tasks: Array as () => any[]\r\n },\r\n components: {\r\n TaskRow\r\n },\r\n setup(props) {\r\n const hiddenTask = ref<Array<any>>([]);\r\n const mapFields = computed(() => store.mapFields);\r\n const collapsedTasks = computed(() => store.collapsedTasks);\r\n \r\n // 获取所有被折叠的子任务\r\n const getAllCollapsedChildren = (parentId: any): Set<any> => {\r\n const collapsedChildren = new Set<any>();\r\n const tasks = props.tasks || store.tasks;\r\n \r\n const collectChildren = (pid: any) => {\r\n const children = tasks.filter(task => task[mapFields.value['parentId']] === pid);\r\n children.forEach(child => {\r\n const childId = child[mapFields.value['id']];\r\n collapsedChildren.add(childId);\r\n // 递归收集所有子孙任务\r\n collectChildren(childId);\r\n });\r\n };\r\n \r\n collectChildren(parentId);\r\n return collapsedChildren;\r\n };\r\n \r\n // 优化:使用Set提高查找性能\r\n const hiddenTaskIds = computed(() => {\r\n return new Set(hiddenTask.value.map(obj => obj[mapFields.value['id']]));\r\n });\r\n\r\n const filterTask = computed(() => {\r\n const hiddenIds = hiddenTaskIds.value;\r\n const tasks = store.tasks.filter(task => !hiddenIds.has(task[mapFields.value['id']]));\r\n \r\n // 过滤折叠的子任务\r\n const allCollapsedIds = new Set<any>();\r\n collapsedTasks.value.forEach(collapsedId => {\r\n const children = getAllCollapsedChildren(collapsedId);\r\n children.forEach(childId => allCollapsedIds.add(childId));\r\n });\r\n \r\n return tasks.filter(task => !allCollapsedIds.has(task[mapFields.value['id']]));\r\n });\r\n\r\n const expandRow = computed({\r\n get: () => store.expandRow,\r\n set: (newValue) => {\r\n mutations.setExpandRow(newValue);\r\n }\r\n });\r\n\r\n watch(expandRow, (newVal) => {\r\n hiddenTask.value = [];\r\n recursionRow(newVal.pid);\r\n });\r\n\r\n const recursionRow = (id: any) => {\r\n // 检查 props.tasks 是否存在,如果存在则进行过滤,否则返回空数组\r\n let findRows = props.tasks ? props.tasks.filter(obj => obj[mapFields.value['parentId']] === id) : [];\r\n if (findRows && findRows.length > 0) {\r\n for (let i = 0; i < findRows.length; i++) {\r\n if (expandRow.value.expand === false) {\r\n hiddenTask.value.push(findRows[i]);\r\n }\r\n recursionRow(findRows[i][mapFields.value['id']]);\r\n }\r\n }\r\n };\r\n\r\n return {\r\n filterTask,\r\n expandRow,\r\n recursionRow,\r\n mapFields\r\n };\r\n }\r\n});\r\n</script>","<template>\r\n <div>\r\n <template v-for=\"item in filterTask\" :key=\"item.id + '_taskrow'\">\r\n <template v-if=\"headers\">\r\n <TaskRow \r\n :headers=\"headers\" \r\n :rowHeight=\"rowHeight\" \r\n :row=\"item\" \r\n />\r\n </template>\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed, watch } from 'vue';\r\nimport { store, mutations } from '../Store';\r\nimport TaskRow from './TaskRow.vue';\r\n\r\nexport default defineComponent({\r\n props: {\r\n headers: Array as () => any[],\r\n rowHeight: Number as () => number,\r\n tasks: Array as () => any[]\r\n },\r\n components: {\r\n TaskRow\r\n },\r\n setup(props) {\r\n const hiddenTask = ref<Array<any>>([]);\r\n const mapFields = computed(() => store.mapFields);\r\n const collapsedTasks = computed(() => store.collapsedTasks);\r\n \r\n // 获取所有被折叠的子任务\r\n const getAllCollapsedChildren = (parentId: any): Set<any> => {\r\n const collapsedChildren = new Set<any>();\r\n const tasks = props.tasks || store.tasks;\r\n \r\n const collectChildren = (pid: any) => {\r\n const children = tasks.filter(task => task[mapFields.value['parentId']] === pid);\r\n children.forEach(child => {\r\n const childId = child[mapFields.value['id']];\r\n collapsedChildren.add(childId);\r\n // 递归收集所有子孙任务\r\n collectChildren(childId);\r\n });\r\n };\r\n \r\n collectChildren(parentId);\r\n return collapsedChildren;\r\n };\r\n \r\n // 优化:使用Set提高查找性能\r\n const hiddenTaskIds = computed(() => {\r\n return new Set(hiddenTask.value.map(obj => obj[mapFields.value['id']]));\r\n });\r\n\r\n const filterTask = computed(() => {\r\n const hiddenIds = hiddenTaskIds.value;\r\n const tasks = store.tasks.filter(task => !hiddenIds.has(task[mapFields.value['id']]));\r\n \r\n // 过滤折叠的子任务\r\n const allCollapsedIds = new Set<any>();\r\n collapsedTasks.value.forEach(collapsedId => {\r\n const children = getAllCollapsedChildren(collapsedId);\r\n children.forEach(childId => allCollapsedIds.add(childId));\r\n });\r\n \r\n return tasks.filter(task => !allCollapsedIds.has(task[mapFields.value['id']]));\r\n });\r\n\r\n const expandRow = computed({\r\n get: () => store.expandRow,\r\n set: (newValue) => {\r\n mutations.setExpandRow(newValue);\r\n }\r\n });\r\n\r\n watch(expandRow, (newVal) => {\r\n hiddenTask.value = [];\r\n recursionRow(newVal.pid);\r\n });\r\n\r\n const recursionRow = (id: any) => {\r\n // 检查 props.tasks 是否存在,如果存在则进行过滤,否则返回空数组\r\n let findRows = props.tasks ? props.tasks.filter(obj => obj[mapFields.value['parentId']] === id) : [];\r\n if (findRows && findRows.length > 0) {\r\n for (let i = 0; i < findRows.length; i++) {\r\n if (expandRow.value.expand === false) {\r\n hiddenTask.value.push(findRows[i]);\r\n }\r\n recursionRow(findRows[i][mapFields.value['id']]);\r\n }\r\n }\r\n };\r\n\r\n return {\r\n filterTask,\r\n expandRow,\r\n recursionRow,\r\n mapFields\r\n };\r\n }\r\n});\r\n</script>","<template>\r\n <div ref=\"taskContent\" class=\"content\" @scroll=\"scroll()\" @mouseover=\"mouseover()\">\r\n <div class=\"content-inner\" :style=\"{ minHeight: contentHeight + 'px' }\">\r\n <TaskRecursionRow :headers='headers' :rowHeight='rowHeight' :tasks='tasks'></TaskRecursionRow>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, watch, computed, onMounted, onUnmounted } from 'vue';\r\nimport { store } from '../Store';\r\nimport { useScrollState } from '../ShareState';\r\nimport TaskRecursionRow from './TaskRecursionRow.vue';\r\n\r\nexport default defineComponent({\r\n props: {\r\n headers: {\r\n type: Array as () => any[],\r\n default: () => []\r\n },\r\n rowHeight: {\r\n type: Number,\r\n default: 0\r\n }\r\n },\r\n components: {\r\n TaskRecursionRow\r\n },\r\n setup(props) {\r\n const tasks = computed(() => store.tasks);\r\n const { scrollTop, scrollFlag, setScrollTop, setScrollFlag } = useScrollState();\r\n const taskContent = ref<HTMLDivElement | null>(null);\r\n const mapFields = computed(() => store.mapFields);\r\n \r\n // 计算内容高度,与右侧保持一致\r\n const contentHeight = computed(() => {\r\n return tasks.value.length * props.rowHeight;\r\n });\r\n \r\n const getRootNode = () => {\r\n return tasks.value.filter((obj: any) => obj[mapFields.value.parentId] === '0');\r\n };\r\n\r\n watch(scrollTop, (newValue) => {\r\n if (!scrollFlag.value && taskContent.value) {\r\n taskContent.value.scrollTop = newValue;\r\n }\r\n });\r\n\r\n // 优化:使用requestAnimationFrame优化滚动性能\r\n let rafId: number | null = null;\r\n const scroll = () => {\r\n if (rafId) {\r\n cancelAnimationFrame(rafId);\r\n }\r\n rafId = requestAnimationFrame(() => {\r\n if (taskContent.value) {\r\n setScrollFlag(true); // 标记当前面板为主动滚动\r\n setScrollTop(taskContent.value.scrollTop);\r\n }\r\n rafId = null;\r\n });\r\n };\r\n\r\n const mouseover = () => {\r\n // 鼠标悬停时不改变滚动标志,让滚动事件处理\r\n };\r\n\r\n // 动态同步滚动区域高度\r\n const syncScrollHeight = () => {\r\n if (taskContent.value) {\r\n // 查找右侧的滚动容器\r\n const rightContent = document.querySelector('.table .content') as HTMLElement;\r\n if (rightContent) {\r\n // 检测右侧是否有水平滚动条\r\n const hasHorizontalScrollbar = rightContent.scrollWidth > rightContent.clientWidth;\r\n \r\n // 动态调整左侧的padding-bottom\r\n if (hasHorizontalScrollbar) {\r\n // 如果右侧有水平滚动条,给左侧添加相应的padding\r\n taskContent.value.style.paddingBottom = '20px';\r\n } else {\r\n // 如果右侧没有水平滚动条,移除左侧的padding\r\n taskContent.value.style.paddingBottom = '0px';\r\n }\r\n }\r\n }\r\n };\r\n\r\n // 监听任务变化,重新同步高度\r\n watch(tasks, () => {\r\n setTimeout(syncScrollHeight, 50);\r\n });\r\n \r\n // 监听窗口大小变化,重新同步高度\r\n const handleResize = () => {\r\n setTimeout(syncScrollHeight, 50);\r\n };\r\n \r\n onMounted(() => {\r\n if (taskContent.value) {\r\n // 监听滚动位置的变化 \r\n taskContent.value.scrollTop = scrollTop.value;\r\n \r\n // 延迟同步高度,确保DOM已渲染完成\r\n setTimeout(syncScrollHeight, 100);\r\n \r\n // 监听窗口大小变化\r\n window.addEventListener('resize', handleResize);\r\n }\r\n });\r\n \r\n onUnmounted(() => {\r\n window.removeEventListener('resize', handleResize);\r\n });\r\n\r\n return {\r\n tasks,\r\n taskContent,\r\n scrollFlag,\r\n mapFields,\r\n setScrollFlag,\r\n getRootNode,\r\n scroll,\r\n mouseover,\r\n contentHeight\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.content {\r\n height: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n overflow-y: auto;\r\n overflow-x: hidden;\r\n position: relative;\r\n box-sizing: border-box;\r\n \r\n .content-inner {\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n }\r\n\r\n .moveToBar {\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n }\r\n\r\n .expandBar {\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n }\r\n}\r\n</style>","<template>\r\n <div ref=\"taskContent\" class=\"content\" @scroll=\"scroll()\" @mouseover=\"mouseover()\">\r\n <div class=\"content-inner\" :style=\"{ minHeight: contentHeight + 'px' }\">\r\n <TaskRecursionRow :headers='headers' :rowHeight='rowHeight' :tasks='tasks'></TaskRecursionRow>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, watch, computed, onMounted, onUnmounted } from 'vue';\r\nimport { store } from '../Store';\r\nimport { useScrollState } from '../ShareState';\r\nimport TaskRecursionRow from './TaskRecursionRow.vue';\r\n\r\nexport default defineComponent({\r\n props: {\r\n headers: {\r\n type: Array as () => any[],\r\n default: () => []\r\n },\r\n rowHeight: {\r\n type: Number,\r\n default: 0\r\n }\r\n },\r\n components: {\r\n TaskRecursionRow\r\n },\r\n setup(props) {\r\n const tasks = computed(() => store.tasks);\r\n const { scrollTop, scrollFlag, setScrollTop, setScrollFlag } = useScrollState();\r\n const taskContent = ref<HTMLDivElement | null>(null);\r\n const mapFields = computed(() => store.mapFields);\r\n \r\n // 计算内容高度,与右侧保持一致\r\n const contentHeight = computed(() => {\r\n return tasks.value.length * props.rowHeight;\r\n });\r\n \r\n const getRootNode = () => {\r\n return tasks.value.filter((obj: any) => obj[mapFields.value.parentId] === '0');\r\n };\r\n\r\n watch(scrollTop, (newValue) => {\r\n if (!scrollFlag.value && taskContent.value) {\r\n taskContent.value.scrollTop = newValue;\r\n }\r\n });\r\n\r\n // 优化:使用requestAnimationFrame优化滚动性能\r\n let rafId: number | null = null;\r\n const scroll = () => {\r\n if (rafId) {\r\n cancelAnimationFrame(rafId);\r\n }\r\n rafId = requestAnimationFrame(() => {\r\n if (taskContent.value) {\r\n setScrollFlag(true); // 标记当前面板为主动滚动\r\n setScrollTop(taskContent.value.scrollTop);\r\n }\r\n rafId = null;\r\n });\r\n };\r\n\r\n const mouseover = () => {\r\n // 鼠标悬停时不改变滚动标志,让滚动事件处理\r\n };\r\n\r\n // 动态同步滚动区域高度\r\n const syncScrollHeight = () => {\r\n if (taskContent.value) {\r\n // 查找右侧的滚动容器\r\n const rightContent = document.querySelector('.table .content') as HTMLElement;\r\n if (rightContent) {\r\n // 检测右侧是否有水平滚动条\r\n const hasHorizontalScrollbar = rightContent.scrollWidth > rightContent.clientWidth;\r\n \r\n // 动态调整左侧的padding-bottom\r\n if (hasHorizontalScrollbar) {\r\n // 如果右侧有水平滚动条,给左侧添加相应的padding\r\n taskContent.value.style.paddingBottom = '20px';\r\n } else {\r\n // 如果右侧没有水平滚动条,移除左侧的padding\r\n taskContent.value.style.paddingBottom = '0px';\r\n }\r\n }\r\n }\r\n };\r\n\r\n // 监听任务变化,重新同步高度\r\n watch(tasks, () => {\r\n setTimeout(syncScrollHeight, 50);\r\n });\r\n \r\n // 监听窗口大小变化,重新同步高度\r\n const handleResize = () => {\r\n setTimeout(syncScrollHeight, 50);\r\n };\r\n \r\n onMounted(() => {\r\n if (taskContent.value) {\r\n // 监听滚动位置的变化 \r\n taskContent.value.scrollTop = scrollTop.value;\r\n \r\n // 延迟同步高度,确保DOM已渲染完成\r\n setTimeout(syncScrollHeight, 100);\r\n \r\n // 监听窗口大小变化\r\n window.addEventListener('resize', handleResize);\r\n }\r\n });\r\n \r\n onUnmounted(() => {\r\n window.removeEventListener('resize', handleResize);\r\n });\r\n\r\n return {\r\n tasks,\r\n taskContent,\r\n scrollFlag,\r\n mapFields,\r\n setScrollFlag,\r\n getRootNode,\r\n scroll,\r\n mouseover,\r\n contentHeight\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.content {\r\n height: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n overflow-y: auto;\r\n overflow-x: hidden;\r\n position: relative;\r\n box-sizing: border-box;\r\n \r\n .content-inner {\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n }\r\n\r\n .moveToBar {\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n }\r\n\r\n .expandBar {\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n }\r\n}\r\n</style>","!function(e,i){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=i():\"function\"==typeof define&&define.amd?define(i):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_plugin_isBetween=i()}(this,(function(){\"use strict\";return function(e,i,t){i.prototype.isBetween=function(e,i,s,f){var n=t(e),o=t(i),r=\"(\"===(f=f||\"()\")[0],u=\")\"===f[1];return(r?this.isAfter(n,s):!this.isBefore(n,s))&&(u?this.isBefore(o,s):!this.isAfter(o,s))||(r?this.isBefore(n,s):!this.isAfter(n,s))&&(u?this.isAfter(o,s):!this.isBefore(o,s))}}}));","<template>\r\n <div class=\"table\">\r\n <div class=\"header\" :style=\"{ height: `${headersHeight}px` }\">\r\n <svg ref=\"addTaskSvg\" t=\"1647915776075\" @click=\"setRootTask({})\" class=\"addRootTask\" viewBox=\"0 0 1024 1024\"\r\n version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"3147\" width=\"200\" height=\"200\">\r\n <path\r\n d=\"M864 0H160C70.4 0 0 70.4 0 160v704c0 89.6 70.4 160 160 160h704c89.6 0 160-70.4 160-160V160c0-89.6-70.4-160-160-160z m96 864c0 54.4-41.6 96-96 96H160c-54.4 0-96-41.6-96-96V160c0-54.4 41.6-96 96-96h704c54.4 0 96 41.6 96 96v704z\"\r\n fill=\"currentColor\" p-id=\"3148\"></path>\r\n <path\r\n d=\"M768 480h-224V256c0-19.2-12.8-32-32-32s-32 12.8-32 32v224H256c-19.2 0-32 12.8-32 32s12.8 32 32 32h224v224c0 19.2 12.8 32 32 32s32-12.8 32-32v-224h224c19.2 0 32-12.8 32-32s-12.8-32-32-32z\"\r\n p-id=\"3149\" fill=\"currentColor\"></path>\r\n </svg>\r\n <svg ref=\"jumpTodaySvg\" t=\"1647262391689\" @click=\"scrollToToday()\" class=\"jumpToToday\"\r\n viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"4965\" width=\"200\"\r\n height=\"200\">\r\n <path\r\n d=\"M753.6 222.4h24c19.2 0 33.6-14.4 33.6-32V57.6c0-19.2-14.4-33.6-33.6-33.6h-24c-19.2 0-33.6 14.4-33.6 33.6v131.2c0 19.2 14.4 33.6 33.6 33.6zM251.2 222.4h24c19.2 0 33.6-14.4 33.6-32V57.6c0-19.2-14.4-33.6-33.6-33.6h-24c-19.2 0-33.6 14.4-33.6 33.6v131.2c0 19.2 14.4 33.6 33.6 33.6z\"\r\n fill=\"currentColor\" p-id=\"4966\"></path>\r\n <path\r\n d=\"M928 134.4h-68.8v56c0 41.6-33.6 76.8-80 76.8h-24c-43.2 0-80-33.6-80-76.8V134.4h-320v56c0 41.6-33.6 76.8-80 76.8h-24c-43.2 0-80-33.6-80-76.8V134.4H105.6c-38.4 0-68.8 28.8-68.8 67.2v731.2c0 38.4 30.4 67.2 68.8 67.2h820.8c38.4 0 68.8-28.8 70.4-67.2V201.6c0-38.4-30.4-67.2-68.8-67.2zM105.6 932.8V355.2h820.8s0 577.6 1.6 577.6H105.6z\"\r\n fill=\"currentColor\" p-id=\"4967\"></path>\r\n <path d=\"M500.8 548.8l-49.6 33.6c14.4 16 33.6 41.6 60.8 75.2l54.4-35.2c-19.2-22.4-40-46.4-65.6-73.6z\"\r\n fill=\"currentColor\" p-id=\"4968\"></path>\r\n <path\r\n d=\"M553.6 451.2l14.4-14.4v-1.6H480c-51.2 68.8-118.4 121.6-196.8 155.2 11.2 12.8 25.6 28.8 41.6 54.4 80-40 142.4-89.6 188.8-148.8 43.2 59.2 102.4 107.2 180.8 144 14.4-19.2 27.2-35.2 41.6-52.8-76.8-30.4-137.6-76.8-182.4-136zM339.2 716.8h246.4c-30.4 43.2-62.4 81.6-94.4 116.8l60.8 33.6c49.6-56 89.6-108.8 123.2-155.2v-54.4h-336v59.2z\"\r\n fill=\"currentColor\" p-id=\"4969\"></path>\r\n </svg>\r\n <TaskHeader :headers='taskHeaders' />\r\n </div>\r\n <div :style=\"{ height: `calc(100% - ${headersHeight}px)` }\">\r\n <TaskContent v-if='Array.isArray(tasks) && tasks.length > 0' :headers='taskHeaders' :rowHeight='rowHeight'>\r\n </TaskContent>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, computed } from 'vue';\r\nimport TaskHeader from './TaskHeader.vue';\r\nimport TaskContent from './TaskContent.vue';\r\nimport { store, mutations } from '../Store';\r\nimport dayjs from 'dayjs';\r\nimport isBetween from 'dayjs/plugin/isBetween';\r\ndayjs.extend(isBetween);\r\nimport sharedState from '../ShareState';\r\n\r\nexport default defineComponent({\r\n props: {\r\n headersHeight: {\r\n type: Number as () => number,\r\n default: 50\r\n },\r\n rowHeight: {\r\n type: Number as () => number,\r\n default: 0\r\n }\r\n },\r\n components: {\r\n TaskHeader,\r\n TaskContent\r\n },\r\n setup() {\r\n const tasks = computed(() => store.tasks);\r\n const taskHeaders = computed(() => store.taskHeaders);\r\n const rootTask = computed({\r\n get: () => store.rootTask,\r\n set: (newValue) => {\r\n mutations.setRootTask(newValue);\r\n }\r\n });\r\n const startGanttDate = computed(() => store.startGanttDate);\r\n const endGanttDate = computed(() => store.endGanttDate);\r\n\r\n const setRootTask = mutations.setRootTask;\r\n const scrollToToday = () => {\r\n // 判断今天在选择的时间范围内\r\n let isBetween = dayjs().isBetween(startGanttDate.value, endGanttDate.value);\r\n if (isBetween) {\r\n sharedState.triggerScrollToToday();\r\n }\r\n };\r\n\r\n return {\r\n tasks,\r\n taskHeaders,\r\n rootTask,\r\n startGanttDate,\r\n endGanttDate,\r\n setRootTask,\r\n scrollToToday,\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.table {\r\n height: 100%;\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n overflow-y: hidden;\r\n overflow-x: hidden;\r\n background: var(--bg-content, #ffffff);\r\n border: 1px solid var(--border, #d0d0d0);\r\n\r\n .header {\r\n height: 100%;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n position: relative;\r\n border-bottom: 1px solid var(--border, #d0d0d0);\r\n box-shadow: var(--shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.8));\r\n\r\n .addRootTask {\r\n position: absolute;\r\n z-index: 10;\r\n bottom: 4px;\r\n right: 4px;\r\n height: 20px;\r\n width: 20px;\r\n cursor: pointer;\r\n color: var(--text-secondary, #666666);\r\n transition: all var(--transition-fast, 0.15s ease);\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n padding: 2px;\r\n\r\n &:hover {\r\n color: var(--primary, #0078d4);\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n transform: scale(1.1);\r\n }\r\n\r\n &:active {\r\n background: var(--bg-metal-pressed, linear-gradient(145deg, #e0e0e0, #f8f8f8));\r\n }\r\n }\r\n\r\n .jumpToToday {\r\n position: absolute;\r\n z-index: 10;\r\n top: 4px;\r\n right: 4px;\r\n height: 20px;\r\n width: 20px;\r\n cursor: pointer;\r\n color: var(--text-secondary, #666666);\r\n transition: all var(--transition-fast, 0.15s ease);\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n padding: 2px;\r\n\r\n &:hover {\r\n color: var(--primary, #0078d4);\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n transform: scale(1.1);\r\n }\r\n\r\n &:active {\r\n background: var(--bg-metal-pressed, linear-gradient(145deg, #e0e0e0, #f8f8f8));\r\n }\r\n }\r\n }\r\n\r\n .nodata {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n text-align: center;\r\n width: 100%;\r\n height: 100%;\r\n color: var(--text-muted, #999999);\r\n font-size: 14px;\r\n font-weight: 500;\r\n background: var(--bg-content, #ffffff);\r\n }\r\n}\r\n</style>","<template>\r\n <div class=\"table\">\r\n <div class=\"header\" :style=\"{ height: `${headersHeight}px` }\">\r\n <svg ref=\"addTaskSvg\" t=\"1647915776075\" @click=\"setRootTask({})\" class=\"addRootTask\" viewBox=\"0 0 1024 1024\"\r\n version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"3147\" width=\"200\" height=\"200\">\r\n <path\r\n d=\"M864 0H160C70.4 0 0 70.4 0 160v704c0 89.6 70.4 160 160 160h704c89.6 0 160-70.4 160-160V160c0-89.6-70.4-160-160-160z m96 864c0 54.4-41.6 96-96 96H160c-54.4 0-96-41.6-96-96V160c0-54.4 41.6-96 96-96h704c54.4 0 96 41.6 96 96v704z\"\r\n fill=\"currentColor\" p-id=\"3148\"></path>\r\n <path\r\n d=\"M768 480h-224V256c0-19.2-12.8-32-32-32s-32 12.8-32 32v224H256c-19.2 0-32 12.8-32 32s12.8 32 32 32h224v224c0 19.2 12.8 32 32 32s32-12.8 32-32v-224h224c19.2 0 32-12.8 32-32s-12.8-32-32-32z\"\r\n p-id=\"3149\" fill=\"currentColor\"></path>\r\n </svg>\r\n <svg ref=\"jumpTodaySvg\" t=\"1647262391689\" @click=\"scrollToToday()\" class=\"jumpToToday\"\r\n viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"4965\" width=\"200\"\r\n height=\"200\">\r\n <path\r\n d=\"M753.6 222.4h24c19.2 0 33.6-14.4 33.6-32V57.6c0-19.2-14.4-33.6-33.6-33.6h-24c-19.2 0-33.6 14.4-33.6 33.6v131.2c0 19.2 14.4 33.6 33.6 33.6zM251.2 222.4h24c19.2 0 33.6-14.4 33.6-32V57.6c0-19.2-14.4-33.6-33.6-33.6h-24c-19.2 0-33.6 14.4-33.6 33.6v131.2c0 19.2 14.4 33.6 33.6 33.6z\"\r\n fill=\"currentColor\" p-id=\"4966\"></path>\r\n <path\r\n d=\"M928 134.4h-68.8v56c0 41.6-33.6 76.8-80 76.8h-24c-43.2 0-80-33.6-80-76.8V134.4h-320v56c0 41.6-33.6 76.8-80 76.8h-24c-43.2 0-80-33.6-80-76.8V134.4H105.6c-38.4 0-68.8 28.8-68.8 67.2v731.2c0 38.4 30.4 67.2 68.8 67.2h820.8c38.4 0 68.8-28.8 70.4-67.2V201.6c0-38.4-30.4-67.2-68.8-67.2zM105.6 932.8V355.2h820.8s0 577.6 1.6 577.6H105.6z\"\r\n fill=\"currentColor\" p-id=\"4967\"></path>\r\n <path d=\"M500.8 548.8l-49.6 33.6c14.4 16 33.6 41.6 60.8 75.2l54.4-35.2c-19.2-22.4-40-46.4-65.6-73.6z\"\r\n fill=\"currentColor\" p-id=\"4968\"></path>\r\n <path\r\n d=\"M553.6 451.2l14.4-14.4v-1.6H480c-51.2 68.8-118.4 121.6-196.8 155.2 11.2 12.8 25.6 28.8 41.6 54.4 80-40 142.4-89.6 188.8-148.8 43.2 59.2 102.4 107.2 180.8 144 14.4-19.2 27.2-35.2 41.6-52.8-76.8-30.4-137.6-76.8-182.4-136zM339.2 716.8h246.4c-30.4 43.2-62.4 81.6-94.4 116.8l60.8 33.6c49.6-56 89.6-108.8 123.2-155.2v-54.4h-336v59.2z\"\r\n fill=\"currentColor\" p-id=\"4969\"></path>\r\n </svg>\r\n <TaskHeader :headers='taskHeaders' />\r\n </div>\r\n <div :style=\"{ height: `calc(100% - ${headersHeight}px)` }\">\r\n <TaskContent v-if='Array.isArray(tasks) && tasks.length > 0' :headers='taskHeaders' :rowHeight='rowHeight'>\r\n </TaskContent>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, computed } from 'vue';\r\nimport TaskHeader from './TaskHeader.vue';\r\nimport TaskContent from './TaskContent.vue';\r\nimport { store, mutations } from '../Store';\r\nimport dayjs from 'dayjs';\r\nimport isBetween from 'dayjs/plugin/isBetween';\r\ndayjs.extend(isBetween);\r\nimport sharedState from '../ShareState';\r\n\r\nexport default defineComponent({\r\n props: {\r\n headersHeight: {\r\n type: Number as () => number,\r\n default: 50\r\n },\r\n rowHeight: {\r\n type: Number as () => number,\r\n default: 0\r\n }\r\n },\r\n components: {\r\n TaskHeader,\r\n TaskContent\r\n },\r\n setup() {\r\n const tasks = computed(() => store.tasks);\r\n const taskHeaders = computed(() => store.taskHeaders);\r\n const rootTask = computed({\r\n get: () => store.rootTask,\r\n set: (newValue) => {\r\n mutations.setRootTask(newValue);\r\n }\r\n });\r\n const startGanttDate = computed(() => store.startGanttDate);\r\n const endGanttDate = computed(() => store.endGanttDate);\r\n\r\n const setRootTask = mutations.setRootTask;\r\n const scrollToToday = () => {\r\n // 判断今天在选择的时间范围内\r\n let isBetween = dayjs().isBetween(startGanttDate.value, endGanttDate.value);\r\n if (isBetween) {\r\n sharedState.triggerScrollToToday();\r\n }\r\n };\r\n\r\n return {\r\n tasks,\r\n taskHeaders,\r\n rootTask,\r\n startGanttDate,\r\n endGanttDate,\r\n setRootTask,\r\n scrollToToday,\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.table {\r\n height: 100%;\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n overflow-y: hidden;\r\n overflow-x: hidden;\r\n background: var(--bg-content, #ffffff);\r\n border: 1px solid var(--border, #d0d0d0);\r\n\r\n .header {\r\n height: 100%;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n position: relative;\r\n border-bottom: 1px solid var(--border, #d0d0d0);\r\n box-shadow: var(--shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.8));\r\n\r\n .addRootTask {\r\n position: absolute;\r\n z-index: 10;\r\n bottom: 4px;\r\n right: 4px;\r\n height: 20px;\r\n width: 20px;\r\n cursor: pointer;\r\n color: var(--text-secondary, #666666);\r\n transition: all var(--transition-fast, 0.15s ease);\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n padding: 2px;\r\n\r\n &:hover {\r\n color: var(--primary, #0078d4);\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n transform: scale(1.1);\r\n }\r\n\r\n &:active {\r\n background: var(--bg-metal-pressed, linear-gradient(145deg, #e0e0e0, #f8f8f8));\r\n }\r\n }\r\n\r\n .jumpToToday {\r\n position: absolute;\r\n z-index: 10;\r\n top: 4px;\r\n right: 4px;\r\n height: 20px;\r\n width: 20px;\r\n cursor: pointer;\r\n color: var(--text-secondary, #666666);\r\n transition: all var(--transition-fast, 0.15s ease);\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n padding: 2px;\r\n\r\n &:hover {\r\n color: var(--primary, #0078d4);\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n transform: scale(1.1);\r\n }\r\n\r\n &:active {\r\n background: var(--bg-metal-pressed, linear-gradient(145deg, #e0e0e0, #f8f8f8));\r\n }\r\n }\r\n }\r\n\r\n .nodata {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n text-align: center;\r\n width: 100%;\r\n height: 100%;\r\n color: var(--text-muted, #999999);\r\n font-size: 14px;\r\n font-weight: 500;\r\n background: var(--bg-content, #ffffff);\r\n }\r\n}\r\n</style>","<template>\r\n <div class=\"headerContainer\">\r\n <div v-if=\"monthHeaders && monthHeaders.length > 0\" class=\"header\">\r\n <template v-for='item in monthHeaders' :key=\"item.title\">\r\n <div class=\"headerCaption\" style=\"border-bottom:0px\" :style=\"{ width: item.width + 'px' }\"><span :style=\"{ width: item.width + 'px' }\">{{item.title}}</span></div>\r\n </template>\r\n </div>\r\n <div v-if=\"weekHeaders && weekHeaders.length > 0\" class=\"header\">\r\n <template v-for='item in weekHeaders' :key=\"item.title\">\r\n <div class=\"headerCaption\" style=\"border-top:1px\" :style=\"{ width: item.width + 'px' }\"><span :style=\"{ width: item.width + 'px' }\">{{item.title}}</span>\r\n </div>\r\n </template>\r\n </div>\r\n <div v-if=\"dayHeaders && dayHeaders.length > 0\" class=\"header\">\r\n <!-- 移除未使用的索引变量 -->\r\n <template v-for='item in dayHeaders' :key=\"item.title\">\r\n <div class=\"headerCaption\" :style=\"{ width: item.width + 'px' }\"><span :style=\"{ width: item.width + 'px' }\">{{item.title}}</span>\r\n <svg t=\"1647262391689\" v-if=\"isToday(item.fulldate)\" class=\"today\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"4965\" width=\"200\" height=\"200\"><path d=\"M753.6 222.4h24c19.2 0 33.6-14.4 33.6-32V57.6c0-19.2-14.4-33.6-33.6-33.6h-24c-19.2 0-33.6 14.4-33.6 33.6v131.2c0 19.2 14.4 33.6 33.6 33.6zM251.2 222.4h24c19.2 0 33.6-14.4 33.6-32V57.6c0-19.2-14.4-33.6-33.6-33.6h-24c-19.2 0-33.6 14.4-33.6 33.6v131.2c0 19.2 14.4 33.6 33.6 33.6z\" fill=\"#707070\" p-id=\"4966\"></path><path d=\"M928 134.4h-68.8v56c0 41.6-33.6 76.8-80 76.8h-24c-43.2 0-80-33.6-80-76.8V134.4h-320v56c0 41.6-33.6 76.8-80 76.8h-24c-43.2 0-80-33.6-80-76.8V134.4H105.6c-38.4 0-68.8 28.8-68.8 67.2v731.2c0 38.4 30.4 67.2 68.8 67.2h820.8c38.4 0 68.8-28.8 70.4-67.2V201.6c0-38.4-30.4-67.2-68.8-67.2zM105.6 932.8V355.2h820.8s0 577.6 1.6 577.6H105.6z\" fill=\"#707070\" p-id=\"4967\"></path><path d=\"M500.8 548.8l-49.6 33.6c14.4 16 33.6 41.6 60.8 75.2l54.4-35.2c-19.2-22.4-40-46.4-65.6-73.6z\" fill=\"#707070\" p-id=\"4968\"></path><path d=\"M553.6 451.2l14.4-14.4v-1.6H480c-51.2 68.8-118.4 121.6-196.8 155.2 11.2 12.8 25.6 28.8 41.6 54.4 80-40 142.4-89.6 188.8-148.8 43.2 59.2 102.4 107.2 180.8 144 14.4-19.2 27.2-35.2 41.6-52.8-76.8-30.4-137.6-76.8-182.4-136zM339.2 716.8h246.4c-30.4 43.2-62.4 81.6-94.4 116.8l60.8 33.6c49.6-56 89.6-108.8 123.2-155.2v-54.4h-336v59.2z\" fill=\"#707070\" p-id=\"4969\"></path></svg>\r\n </div>\r\n </template>\r\n </div>\r\n <div v-if=\"hourHeaders && hourHeaders.length > 0\" class=\"header\">\r\n <template v-for='item in hourHeaders' :key=\"item.title\">\r\n <div class=\"headerCaption\" :style=\"{ width: item.width + 'px',marginTop: '-2px' }\"><span :style=\"{ width: item.width + 'px' }\">{{item.title}}</span></div>\r\n </template>\r\n </div>\r\n </div>\r\n </template>\r\n <script lang=\"ts\">\r\n import { defineComponent, toRefs } from 'vue';\r\n import dayjs from 'dayjs';\r\n import { useI18n } from './i18n';\r\n\r\n export default defineComponent({\r\n props: {\r\n weekHeaders: {\r\n type: Array as () => Array<{ title: string; width: number }>,\r\n default: () => []\r\n },\r\n dayHeaders: {\r\n type: Array as () => Array<{ title: string; width: number; fulldate: string }>,\r\n default: () => []\r\n },\r\n monthHeaders: {\r\n type: Array as () => Array<{ title: string; width: number }>,\r\n default: () => []\r\n },\r\n hourHeaders: {\r\n type: Array as () => Array<{ title: string; width: number }>,\r\n default: () => []\r\n }\r\n },\r\n setup(props) {\r\n const { weekHeaders, dayHeaders, monthHeaders, hourHeaders } = toRefs(props);\r\n const { locale } = useI18n();\r\n\r\n const isToday = (title: string) => {\r\n const localeMap: Record<string, string> = {\r\n 'zh-CN': 'zh-cn',\r\n 'en-US': 'en',\r\n 'ja-JP': 'ja',\r\n 'ko-KR': 'ko',\r\n 'fr-FR': 'fr',\r\n 'de-DE': 'de',\r\n 'es-ES': 'es',\r\n 'ru-RU': 'ru'\r\n };\r\n const dayjsLocale = localeMap[locale.value] || 'en';\r\n return title === dayjs().locale(dayjsLocale).format('YYYY-MM-DD');\r\n };\r\n\r\n return {\r\n weekHeaders,\r\n dayHeaders,\r\n monthHeaders,\r\n hourHeaders,\r\n isToday\r\n };\r\n }\r\n });\r\n </script>\r\n <style lang=\"scss\" scoped>\r\n .headerContainer {\r\n width: 100%;\r\n height: 100%;\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n font-size: 12px;\r\n font-weight: 600;\r\n font-family: var(--font-family, 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif);\r\n }\r\n\r\n .header {\r\n width: 100%;\r\n height: 100%;\r\n display: flex;\r\n flex-flow: row nowrap;\r\n justify-content: flex-start;\r\n border-bottom: 1px solid var(--border, #cecece);\r\n }\r\n\r\n .headerCaption {\r\n text-align: center;\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: center;\r\n color: var(--text-primary, #333333);\r\n font-size: 12px;\r\n font-weight: 600;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n position: relative;\r\n letter-spacing: 0.5px;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n \r\n &::before {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n bottom: 0;\r\n left: 0;\r\n border-top: 1px solid var(--border, #cecece);\r\n border-right: 1px solid var(--border, #cecece);\r\n pointer-events: none;\r\n }\r\n\r\n &:hover {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n color: var(--primary, #0078d4);\r\n }\r\n}\r\n\r\n .today {\r\n position: absolute;\r\n z-index: 10;\r\n top: 2px;\r\n left: 2px;\r\n height: 20px;\r\n width: 25px;\r\n fill: var(--text-secondary, #707070);\r\n transition: fill var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n .today:hover {\r\n fill: var(--primary, #3A8EE6);\r\n }\r\n </style>","<template>\r\n <div class=\"headerContainer\">\r\n <div v-if=\"monthHeaders && monthHeaders.length > 0\" class=\"header\">\r\n <template v-for='item in monthHeaders' :key=\"item.title\">\r\n <div class=\"headerCaption\" style=\"border-bottom:0px\" :style=\"{ width: item.width + 'px' }\"><span :style=\"{ width: item.width + 'px' }\">{{item.title}}</span></div>\r\n </template>\r\n </div>\r\n <div v-if=\"weekHeaders && weekHeaders.length > 0\" class=\"header\">\r\n <template v-for='item in weekHeaders' :key=\"item.title\">\r\n <div class=\"headerCaption\" style=\"border-top:1px\" :style=\"{ width: item.width + 'px' }\"><span :style=\"{ width: item.width + 'px' }\">{{item.title}}</span>\r\n </div>\r\n </template>\r\n </div>\r\n <div v-if=\"dayHeaders && dayHeaders.length > 0\" class=\"header\">\r\n <!-- 移除未使用的索引变量 -->\r\n <template v-for='item in dayHeaders' :key=\"item.title\">\r\n <div class=\"headerCaption\" :style=\"{ width: item.width + 'px' }\"><span :style=\"{ width: item.width + 'px' }\">{{item.title}}</span>\r\n <svg t=\"1647262391689\" v-if=\"isToday(item.fulldate)\" class=\"today\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"4965\" width=\"200\" height=\"200\"><path d=\"M753.6 222.4h24c19.2 0 33.6-14.4 33.6-32V57.6c0-19.2-14.4-33.6-33.6-33.6h-24c-19.2 0-33.6 14.4-33.6 33.6v131.2c0 19.2 14.4 33.6 33.6 33.6zM251.2 222.4h24c19.2 0 33.6-14.4 33.6-32V57.6c0-19.2-14.4-33.6-33.6-33.6h-24c-19.2 0-33.6 14.4-33.6 33.6v131.2c0 19.2 14.4 33.6 33.6 33.6z\" fill=\"#707070\" p-id=\"4966\"></path><path d=\"M928 134.4h-68.8v56c0 41.6-33.6 76.8-80 76.8h-24c-43.2 0-80-33.6-80-76.8V134.4h-320v56c0 41.6-33.6 76.8-80 76.8h-24c-43.2 0-80-33.6-80-76.8V134.4H105.6c-38.4 0-68.8 28.8-68.8 67.2v731.2c0 38.4 30.4 67.2 68.8 67.2h820.8c38.4 0 68.8-28.8 70.4-67.2V201.6c0-38.4-30.4-67.2-68.8-67.2zM105.6 932.8V355.2h820.8s0 577.6 1.6 577.6H105.6z\" fill=\"#707070\" p-id=\"4967\"></path><path d=\"M500.8 548.8l-49.6 33.6c14.4 16 33.6 41.6 60.8 75.2l54.4-35.2c-19.2-22.4-40-46.4-65.6-73.6z\" fill=\"#707070\" p-id=\"4968\"></path><path d=\"M553.6 451.2l14.4-14.4v-1.6H480c-51.2 68.8-118.4 121.6-196.8 155.2 11.2 12.8 25.6 28.8 41.6 54.4 80-40 142.4-89.6 188.8-148.8 43.2 59.2 102.4 107.2 180.8 144 14.4-19.2 27.2-35.2 41.6-52.8-76.8-30.4-137.6-76.8-182.4-136zM339.2 716.8h246.4c-30.4 43.2-62.4 81.6-94.4 116.8l60.8 33.6c49.6-56 89.6-108.8 123.2-155.2v-54.4h-336v59.2z\" fill=\"#707070\" p-id=\"4969\"></path></svg>\r\n </div>\r\n </template>\r\n </div>\r\n <div v-if=\"hourHeaders && hourHeaders.length > 0\" class=\"header\">\r\n <template v-for='item in hourHeaders' :key=\"item.title\">\r\n <div class=\"headerCaption\" :style=\"{ width: item.width + 'px',marginTop: '-2px' }\"><span :style=\"{ width: item.width + 'px' }\">{{item.title}}</span></div>\r\n </template>\r\n </div>\r\n </div>\r\n </template>\r\n <script lang=\"ts\">\r\n import { defineComponent, toRefs } from 'vue';\r\n import dayjs from 'dayjs';\r\n import { useI18n } from './i18n';\r\n\r\n export default defineComponent({\r\n props: {\r\n weekHeaders: {\r\n type: Array as () => Array<{ title: string; width: number }>,\r\n default: () => []\r\n },\r\n dayHeaders: {\r\n type: Array as () => Array<{ title: string; width: number; fulldate: string }>,\r\n default: () => []\r\n },\r\n monthHeaders: {\r\n type: Array as () => Array<{ title: string; width: number }>,\r\n default: () => []\r\n },\r\n hourHeaders: {\r\n type: Array as () => Array<{ title: string; width: number }>,\r\n default: () => []\r\n }\r\n },\r\n setup(props) {\r\n const { weekHeaders, dayHeaders, monthHeaders, hourHeaders } = toRefs(props);\r\n const { locale } = useI18n();\r\n\r\n const isToday = (title: string) => {\r\n const localeMap: Record<string, string> = {\r\n 'zh-CN': 'zh-cn',\r\n 'en-US': 'en',\r\n 'ja-JP': 'ja',\r\n 'ko-KR': 'ko',\r\n 'fr-FR': 'fr',\r\n 'de-DE': 'de',\r\n 'es-ES': 'es',\r\n 'ru-RU': 'ru'\r\n };\r\n const dayjsLocale = localeMap[locale.value] || 'en';\r\n return title === dayjs().locale(dayjsLocale).format('YYYY-MM-DD');\r\n };\r\n\r\n return {\r\n weekHeaders,\r\n dayHeaders,\r\n monthHeaders,\r\n hourHeaders,\r\n isToday\r\n };\r\n }\r\n });\r\n </script>\r\n <style lang=\"scss\" scoped>\r\n .headerContainer {\r\n width: 100%;\r\n height: 100%;\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n font-size: 12px;\r\n font-weight: 600;\r\n font-family: var(--font-family, 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif);\r\n }\r\n\r\n .header {\r\n width: 100%;\r\n height: 100%;\r\n display: flex;\r\n flex-flow: row nowrap;\r\n justify-content: flex-start;\r\n border-bottom: 1px solid var(--border, #cecece);\r\n }\r\n\r\n .headerCaption {\r\n text-align: center;\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: center;\r\n color: var(--text-primary, #333333);\r\n font-size: 12px;\r\n font-weight: 600;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n position: relative;\r\n letter-spacing: 0.5px;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n \r\n &::before {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n bottom: 0;\r\n left: 0;\r\n border-top: 1px solid var(--border, #cecece);\r\n border-right: 1px solid var(--border, #cecece);\r\n pointer-events: none;\r\n }\r\n\r\n &:hover {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n color: var(--primary, #0078d4);\r\n }\r\n}\r\n\r\n .today {\r\n position: absolute;\r\n z-index: 10;\r\n top: 2px;\r\n left: 2px;\r\n height: 20px;\r\n width: 25px;\r\n fill: var(--text-secondary, #707070);\r\n transition: fill var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n .today:hover {\r\n fill: var(--primary, #3A8EE6);\r\n }\r\n </style>","!function(e,t){\"object\"==typeof exports&&\"undefined\"!=typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define(t):(e=\"undefined\"!=typeof globalThis?globalThis:e||self).dayjs_plugin_isoWeek=t()}(this,(function(){\"use strict\";var e=\"day\";return function(t,i,s){var a=function(t){return t.add(4-t.isoWeekday(),e)},d=i.prototype;d.isoWeekYear=function(){return a(this).year()},d.isoWeek=function(t){if(!this.$utils().u(t))return this.add(7*(t-this.isoWeek()),e);var i,d,n,o,r=a(this),u=(i=this.isoWeekYear(),d=this.$u,n=(d?s.utc:s)().year(i).startOf(\"year\"),o=4-n.isoWeekday(),n.isoWeekday()>4&&(o+=7),n.add(o,e));return r.diff(u,\"week\")+1},d.isoWeekday=function(e){return this.$utils().u(e)?this.day()||7:this.day(this.day()%7?e:e-7)};var n=d.startOf;d.startOf=function(e,t){var i=this.$utils(),s=!!i.u(t)||t;return\"isoweek\"===i.p(e)?s?this.date(this.date()-(this.isoWeekday()-1)).startOf(\"day\"):this.date(this.date()-1-(this.isoWeekday()-1)+7).endOf(\"day\"):n.bind(this)(e,t)}}}));","<template>\r\n <div v-if='showRow' class=\"barRow\" :style=\"{ height: rowHeight + 'px' }\" @mouseover=\"hoverActive()\"\r\n @mouseleave=\"hoverInactive()\" :class=\"{ active: hover }\" :data-task-id=\"row[mapFields.id]\">\r\n <svg key=\"row.no\" v-if='showRow' ref='bar' class=\"bar\" :height=\"barHeight + 'px'\"\r\n :class=\"{ active: hover }\" style=\"overflow: visible;\"></svg>\r\n <template v-for='(count) in timelineCellCount'\r\n :key=\"count + row.id + timelineCellCount + showRow + '_template'\">\r\n <div class=\"cell\"\r\n :style=\"{ width: scale + 'px', minWidth: scale + 'px', maxWidth: scale + 'px', height: rowHeight + 'px', background: WeekEndColor(count) }\">\r\n </div>\r\n </template>\r\n </div>\r\n</template>\r\n<script lang=\"ts\">\r\nimport { defineComponent, watch, ref, computed, onMounted, onDeactivated, onBeforeUnmount, inject } from 'vue';\r\nimport SVG from 'svg.js';\r\nimport interact from 'interactjs';\r\nimport dayjs from 'dayjs';\r\nimport isoWeek from 'dayjs/plugin/isoWeek';\r\ndayjs.extend(isoWeek);\r\nimport { store, mutations } from './Store';\r\nimport sharedState from '../gantt/ShareState';\r\nimport { Symbols } from './Symbols';\r\n\r\nexport default defineComponent({\r\n name: 'Bar',\r\n emits: ['progress-update'],\r\n props: {\r\n rowHeight: { type: Number as () => number, default: 0 },\r\n row: { type: Object as () => Record<string, any>, default: () => ({}) },\r\n startGanttDate: { type: String as () => string },\r\n endGanttDate: { type: String as () => string }\r\n },\r\n setup(props, { emit }) {\r\n const bar = ref<SVGSVGElement | null>(null);\r\n const barHeight = ref(props.rowHeight * 0.7);\r\n const direction = ref<string | null>(null);\r\n const oldBarDataX = ref(0);\r\n const oldBarWidth = ref(0);\r\n const showRow = ref(true);\r\n const hover = ref(false);\r\n const barColor = ref('');\r\n const isBarInteracted = ref(false);\r\n const themeVersion = ref(0);\r\n const isProgressDragging = ref(false);\r\n\r\n const timelineCellCount = computed(() => store.timelineCellCount);\r\n const scale = computed(() => store.scale);\r\n const mode = computed(() => store.mode);\r\n const mapFields = computed(() => store.mapFields);\r\n const progress = computed(() => {\r\n const progressValue = Number(props.row[mapFields.value.progress]);\r\n if (isNaN(progressValue)) return '0.00%';\r\n return (progressValue * 100).toFixed(2) + '%';\r\n });\r\n\r\n const setBarColor = inject(Symbols.SetBarColorSymbol) as ((row: any) => string) | undefined;\r\n\r\n // 进度更新事件\r\n const emitProgressUpdate = (newProgress: number) => {\r\n const detail = {\r\n taskId: props.row[mapFields.value.id],\r\n oldProgress: Number(props.row[mapFields.value.progress]) || 0,\r\n newProgress: newProgress,\r\n task: props.row\r\n };\r\n emit('progress-update', detail);\r\n window.dispatchEvent(new CustomEvent('taskProgressUpdate', { detail }));\r\n console.log('Task progress updated:', detail);\r\n };\r\n\r\n watch(() => sharedState.highlightedId, (newId) => {\r\n hover.value = props.row[mapFields.value['id']] === newId;\r\n });\r\n\r\n const hoverActive = () => sharedState.triggerHighlight(props.row[mapFields.value.id] as number | null);\r\n const hoverInactive = () => sharedState.triggerHighlight(null);\r\n\r\n const WeekEndColor = (count: number) => {\r\n themeVersion.value;\r\n let bgContent = '#ffffff', bgSecondary = '#f8f8f8';\r\n if (bar.value) {\r\n let element = bar.value.parentElement;\r\n while (element) {\r\n if (element.hasAttribute('data-gantt-theme')) {\r\n bgContent = getComputedStyle(element).getPropertyValue('--bg-content').trim() || '#ffffff';\r\n bgSecondary = getComputedStyle(element).getPropertyValue('--bg-secondary').trim() || '#f8f8f8';\r\n break;\r\n }\r\n element = element.parentElement;\r\n }\r\n }\r\n switch (mode.value) {\r\n case '月': case '日': {\r\n let currentDate = dayjs(props.startGanttDate).add(count, 'days');\r\n return (currentDate.isoWeekday() === 7 || currentDate.isoWeekday() === 1) ? bgSecondary : bgContent;\r\n }\r\n case '周': case '时': return bgContent;\r\n }\r\n };\r\n\r\n const setBarDate = mutations.setBarDate;\r\n const setAllowChangeTaskDate = mutations.setAllowChangeTaskDate;\r\n\r\n const drowBar = (barElement: SVGSVGElement) => {\r\n let dataX = 0;\r\n switch (mode.value) {\r\n case '月': case '日': {\r\n let fromPlanStartDays = dayjs(props.row[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'days');\r\n dataX = scale.value * fromPlanStartDays;\r\n let spendDays = dayjs(props.row[mapFields.value.enddate]).diff(dayjs(props.row[mapFields.value.startdate]), 'days') + 1;\r\n oldBarWidth.value = spendDays * scale.value;\r\n props.row[mapFields.value.takestime] = spendDays + '天';\r\n break;\r\n }\r\n case '周': {\r\n const startGanttWeek = dayjs(props.startGanttDate).startOf('isoWeek');\r\n const taskStartWeek = dayjs(props.row[mapFields.value.startdate]).startOf('isoWeek');\r\n let fromPlanStartWeeks = taskStartWeek.diff(startGanttWeek, 'week');\r\n dataX = scale.value * fromPlanStartWeeks;\r\n const taskEndWeek = dayjs(props.row[mapFields.value.enddate]).startOf('isoWeek');\r\n let spendWeeks = taskEndWeek.diff(taskStartWeek, 'week') + 1;\r\n oldBarWidth.value = spendWeeks * scale.value;\r\n props.row[mapFields.value.takestime] = spendWeeks + '周';\r\n break;\r\n }\r\n case '时': {\r\n let fromPlanStartHours = dayjs(props.row[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'hours');\r\n dataX = scale.value * fromPlanStartHours;\r\n let spendHours = dayjs(props.row[mapFields.value.enddate]).diff(dayjs(props.row[mapFields.value.startdate]), 'hours') + 1;\r\n oldBarWidth.value = spendHours * scale.value;\r\n props.row[mapFields.value.takestime] = spendHours + '小时';\r\n break;\r\n }\r\n }\r\n oldBarDataX.value = dataX;\r\n let svg = SVG(barElement as unknown as HTMLElement);\r\n const borderColor = getComputedStyle(barElement).getPropertyValue('--border') || '#cecece';\r\n barElement.setAttribute('data-x', dataX.toString());\r\n barElement.setAttribute('width', oldBarWidth.value.toString());\r\n barElement.setAttribute('stroke', borderColor);\r\n barElement.setAttribute('stroke-width', '1px');\r\n barElement.style.transform = `translate(${dataX}px, 0px)`;\r\n\r\n let p = svg.select('pattern').first();\r\n let g = (svg.children().filter((child) => child.type === 'g')[0] as any) || svg.group();\r\n let innerRect = svg.select('.innerRect').first();\r\n let outerRect = svg.select('rect:not(.innerRect):not(.progressHandle)').first();\r\n let text = svg.select('text').first();\r\n let progressHandle = svg.select('.progressHandle').first();\r\n\r\n if (!p) {\r\n p = svg.pattern(10, 10, (add) => {\r\n (add as any).path('M10 -5 -10,15M15,0,0,15M0 -5 -20,15').fill('none').stroke({ color: 'gray', opacity: 0.4, width: 5 });\r\n });\r\n }\r\n if (!g) g = svg.group();\r\n\r\n let innerRectWidth = props.row[mapFields.value.progress] \r\n ? Number(oldBarWidth.value) * Number(props.row[mapFields.value.progress]) \r\n : Number(oldBarWidth.value);\r\n \r\n if (!innerRect) {\r\n innerRect = svg.rect(innerRectWidth, barHeight.value).radius(10);\r\n innerRect.addClass('innerRect');\r\n g.add(innerRect);\r\n } else {\r\n innerRect.fill({ color: barColor.value, opacity: 0.4 });\r\n innerRect.width(innerRectWidth);\r\n }\r\n\r\n if (!outerRect) {\r\n outerRect = svg.rect(oldBarWidth.value, barHeight.value).radius(10).fill(p).stroke({ color: borderColor, width: 1 });\r\n outerRect.on('mouseover', () => outerRect.animate(200).attr({ stroke: '#000', strokeWidth: 2, opacity: 1 }));\r\n outerRect.on('mouseleave', () => outerRect.animate(200).attr({ stroke: '#0066ff', strokeWidth: 10, opacity: 0.4 }));\r\n } else {\r\n outerRect.width(oldBarWidth.value);\r\n }\r\n\r\n if (!text) {\r\n text = svg.text(progress.value).stroke('#faf7ec');\r\n } else {\r\n (text as any).text(progress.value);\r\n }\r\n const textBBox = text.bbox();\r\n (text as any).font({ size: 15, anchor: 'middle', leading: '1em' })\r\n .fill('#000').attr('opacity', 1).attr('dominant-baseline', 'middle')\r\n .center(innerRect.width() / 2 + textBBox.width / 2, innerRect.height() / 2);\r\n\r\n // 进度调节滑块 - 三角形拖拽手柄 + 对齐虚线\r\n const handleWidth = 12;\r\n const handleHeight = 8;\r\n const handleX = innerRectWidth - handleWidth / 2;\r\n // 三角形位置:Bar底部边缘穿过三角形中心\r\n const handleY = barHeight.value - handleHeight / 2;\r\n const lineX = innerRectWidth;\r\n \r\n // 获取主题颜色的辅助函数\r\n const getThemeColors = () => {\r\n let primary = '#f59e0b', primaryDark = '#d97706', primaryLight = '#fbbf24';\r\n let element = barElement.parentElement;\r\n while (element) {\r\n if (element.hasAttribute('data-gantt-theme')) {\r\n primary = getComputedStyle(element).getPropertyValue('--primary').trim() || primary;\r\n primaryDark = getComputedStyle(element).getPropertyValue('--primary-dark').trim() || primaryDark;\r\n primaryLight = getComputedStyle(element).getPropertyValue('--primary-light').trim() || primaryLight;\r\n break;\r\n }\r\n element = element.parentElement;\r\n }\r\n return { primary, primaryDark, primaryLight };\r\n };\r\n \r\n // 查找或创建对齐虚线\r\n let guideLineEl = barElement.querySelector('.progressGuideLine') as SVGLineElement | null;\r\n const themeColors = getThemeColors();\r\n \r\n if (!guideLineEl) {\r\n // 创建对齐虚线\r\n const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');\r\n line.setAttribute('class', 'progressGuideLine');\r\n line.setAttribute('x1', String(lineX));\r\n line.setAttribute('y1', '0');\r\n line.setAttribute('x2', String(lineX));\r\n line.setAttribute('y2', String(handleY));\r\n line.setAttribute('stroke', themeColors.primaryDark);\r\n line.setAttribute('stroke-width', '2');\r\n line.setAttribute('stroke-dasharray', '4,3');\r\n line.setAttribute('opacity', '0.8');\r\n barElement.appendChild(line);\r\n guideLineEl = line;\r\n }\r\n // 始终更新位置和可见性\r\n guideLineEl.setAttribute('x1', String(lineX));\r\n guideLineEl.setAttribute('x2', String(lineX));\r\n guideLineEl.setAttribute('y2', String(handleY));\r\n guideLineEl.setAttribute('stroke', themeColors.primaryDark);\r\n guideLineEl.setAttribute('opacity', '0.8');\r\n \r\n if (!progressHandle) {\r\n // 创建三角形手柄\r\n const trianglePoints = `${handleWidth/2},0 0,${handleHeight} ${handleWidth},${handleHeight}`;\r\n progressHandle = svg.polygon(trianglePoints)\r\n .fill(themeColors.primary)\r\n .stroke({ color: themeColors.primaryDark, width: 1 })\r\n .addClass('progressHandle');\r\n \r\n const handleElement = progressHandle.node as unknown as SVGPolygonElement;\r\n handleElement.style.cursor = 'ew-resize';\r\n handleElement.style.pointerEvents = 'auto';\r\n progressHandle.move(handleX, handleY);\r\n \r\n // 用于记录当前X位置\r\n let currentHandleX = handleX;\r\n \r\n // 悬停效果 - 高亮显示\r\n handleElement.addEventListener('mouseenter', () => {\r\n if (!isProgressDragging.value) {\r\n const colors = getThemeColors();\r\n handleElement.setAttribute('fill', colors.primaryLight);\r\n handleElement.setAttribute('stroke', colors.primary);\r\n handleElement.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('stroke', colors.primaryLight);\r\n guideLineEl!.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('opacity', '1');\r\n }\r\n });\r\n handleElement.addEventListener('mouseleave', () => {\r\n if (!isProgressDragging.value) {\r\n const colors = getThemeColors();\r\n handleElement.setAttribute('fill', colors.primary);\r\n handleElement.setAttribute('stroke', colors.primaryDark);\r\n handleElement.setAttribute('stroke-width', '1');\r\n guideLineEl!.setAttribute('stroke', colors.primaryDark);\r\n guideLineEl!.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('opacity', '0.8');\r\n }\r\n });\r\n \r\n // 拖拽交互\r\n interact(handleElement).draggable({\r\n inertia: false,\r\n listeners: {\r\n start: () => { \r\n isProgressDragging.value = true;\r\n const colors = getThemeColors();\r\n handleElement.setAttribute('fill', colors.primaryDark);\r\n handleElement.setAttribute('stroke', colors.primaryDark);\r\n handleElement.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('stroke', colors.primaryDark);\r\n guideLineEl!.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('opacity', '1');\r\n },\r\n move: (event) => {\r\n currentHandleX += event.dx;\r\n currentHandleX = Math.max(-handleWidth / 2, Math.min(currentHandleX, oldBarWidth.value - handleWidth / 2));\r\n \r\n progressHandle.move(currentHandleX, handleY);\r\n \r\n // 更新虚线位置\r\n const newLineX = currentHandleX + handleWidth / 2;\r\n guideLineEl!.setAttribute('x1', String(newLineX));\r\n guideLineEl!.setAttribute('x2', String(newLineX));\r\n \r\n // 更新进度\r\n const newProgress = Math.min(1, Math.max(0, (currentHandleX + handleWidth / 2) / oldBarWidth.value));\r\n innerRect.width(newProgress * oldBarWidth.value);\r\n (text as any).text((newProgress * 100).toFixed(2) + '%');\r\n (text as any).center(innerRect.width() / 2 + textBBox.width / 2, innerRect.height() / 2);\r\n },\r\n end: () => {\r\n isProgressDragging.value = false;\r\n const colors = getThemeColors();\r\n handleElement.setAttribute('fill', colors.primary);\r\n handleElement.setAttribute('stroke', colors.primaryDark);\r\n handleElement.setAttribute('stroke-width', '1');\r\n guideLineEl!.setAttribute('stroke', colors.primaryDark);\r\n guideLineEl!.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('opacity', '0.8');\r\n \r\n const newProgress = Math.min(1, Math.max(0, (currentHandleX + handleWidth / 2) / oldBarWidth.value));\r\n props.row[mapFields.value.progress] = newProgress;\r\n emitProgressUpdate(newProgress);\r\n }\r\n }\r\n });\r\n } else {\r\n progressHandle.move(handleX, handleY);\r\n // 更新已存在的三角形颜色以响应主题变化\r\n const handleElement = progressHandle.node as unknown as SVGPolygonElement;\r\n handleElement.setAttribute('fill', themeColors.primary);\r\n handleElement.setAttribute('stroke', themeColors.primaryDark);\r\n }\r\n\r\n setBarDate({ id: props.row[mapFields.value.id], startDate: props.row[mapFields.value.startdate], endDate: props.row[mapFields.value.enddate] });\r\n\r\n // 拖拽功能\r\n interact(barElement).draggable({\r\n inertia: false,\r\n modifiers: [interact.modifiers.restrictRect({ restriction: 'parent', endOnly: true })],\r\n autoScroll: true,\r\n listeners: {\r\n start: (event: { target: SVGSVGElement }) => {\r\n if (isProgressDragging.value) return;\r\n oldBarDataX.value = Number(event.target.getAttribute('data-x'));\r\n oldBarWidth.value = event.target.width.baseVal.value;\r\n },\r\n move: (event: { target: SVGSVGElement; dx: number; rect: { width: number; height: number } }) => {\r\n if (isProgressDragging.value) return;\r\n let x = ((parseFloat(event.target.getAttribute('data-x') || '0') || 0) + event.dx).toString();\r\n Object.assign(event.target.style, { width: `${event.rect.width}px`, height: `${event.rect.height}px`, transform: `translate(${x}px, 0px)` });\r\n event.target.setAttribute('data-x', x);\r\n event.target.setAttribute('data-y', '0');\r\n },\r\n end: (event: { target: SVGSVGElement }) => {\r\n if (isProgressDragging.value) return;\r\n let target = event.target;\r\n let currentX = parseFloat(target.getAttribute('data-x') || '0') || 0;\r\n let multiple = Math.round(currentX / scale.value);\r\n let alignedX = multiple * scale.value;\r\n if (alignedX < 0) alignedX = 0;\r\n if (alignedX > timelineCellCount.value * scale.value) alignedX = timelineCellCount.value * scale.value;\r\n \r\n const parentIdField = mapFields.value.parentId || 'pid';\r\n const currentParentId = props.row[parentIdField];\r\n if (currentParentId && currentParentId !== '0') {\r\n const parentTask = store.tasks.find(t => String(t[mapFields.value.id]) === String(currentParentId));\r\n if (parentTask) {\r\n let parentStartX = 0;\r\n if (mode.value === '月' || mode.value === '日') {\r\n parentStartX = dayjs(parentTask[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'days') * scale.value;\r\n } else if (mode.value === '周') {\r\n const ganttStartWeek = dayjs(props.startGanttDate).startOf('isoWeek');\r\n const parentStartWeek = dayjs(parentTask[mapFields.value.startdate]).startOf('isoWeek');\r\n parentStartX = parentStartWeek.diff(ganttStartWeek, 'week') * scale.value;\r\n } else if (mode.value === '时') {\r\n parentStartX = dayjs(parentTask[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'hours') * scale.value;\r\n }\r\n if (alignedX < parentStartX) alignedX = parentStartX;\r\n }\r\n }\r\n \r\n target.style.transform = `translate(${alignedX}px, 0px)`;\r\n target.setAttribute('data-x', alignedX.toString());\r\n \r\n const cellsMoved = Math.round((alignedX - oldBarDataX.value) / scale.value);\r\n let daysOffset = 0, hoursOffset = 0;\r\n if (mode.value === '月' || mode.value === '日') daysOffset = cellsMoved;\r\n else if (mode.value === '周') daysOffset = cellsMoved * 7;\r\n else if (mode.value === '时') hoursOffset = cellsMoved;\r\n \r\n if (mode.value === '时') {\r\n props.row[mapFields.value.startdate] = dayjs(props.row[mapFields.value.startdate]).add(hoursOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.enddate] = dayjs(props.row[mapFields.value.enddate]).add(hoursOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.takestime] = (dayjs(props.row[mapFields.value.enddate]).diff(dayjs(props.row[mapFields.value.startdate]), 'hours') + 1) + '小时';\r\n } else {\r\n props.row[mapFields.value.startdate] = dayjs(props.row[mapFields.value.startdate]).add(daysOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.enddate] = dayjs(props.row[mapFields.value.enddate]).add(daysOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n if (mode.value === '月' || mode.value === '日') {\r\n props.row[mapFields.value.takestime] = (dayjs(props.row[mapFields.value.enddate]).diff(dayjs(props.row[mapFields.value.startdate]), 'days') + 1) + '天';\r\n } else if (mode.value === '周') {\r\n const startWeek = dayjs(props.row[mapFields.value.startdate]).startOf('isoWeek');\r\n const endWeek = dayjs(props.row[mapFields.value.enddate]).startOf('isoWeek');\r\n props.row[mapFields.value.takestime] = (endWeek.diff(startWeek, 'week') + 1) + '周';\r\n }\r\n }\r\n \r\n // 联动子任务\r\n const newParentStartDate = dayjs(props.row[mapFields.value.startdate]);\r\n const currentTaskId = props.row[mapFields.value.id];\r\n const getAllChildren = (parentId: any, tasks: any[]): any[] => {\r\n const children: any[] = [];\r\n for (const task of tasks) {\r\n if (String(task[parentIdField]) === String(parentId)) {\r\n children.push(task);\r\n children.push(...getAllChildren(task[mapFields.value.id], tasks));\r\n }\r\n }\r\n return children;\r\n };\r\n const childTasks = getAllChildren(currentTaskId, store.tasks);\r\n const actualOffset = mode.value === '时' ? hoursOffset : daysOffset;\r\n if (actualOffset > 0) {\r\n for (const child of childTasks) {\r\n if (dayjs(child[mapFields.value.startdate]).isBefore(newParentStartDate)) {\r\n if (mode.value === '时') {\r\n child[mapFields.value.startdate] = dayjs(child[mapFields.value.startdate]).add(hoursOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n child[mapFields.value.enddate] = dayjs(child[mapFields.value.enddate]).add(hoursOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n } else {\r\n child[mapFields.value.startdate] = dayjs(child[mapFields.value.startdate]).add(daysOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n child[mapFields.value.enddate] = dayjs(child[mapFields.value.enddate]).add(daysOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n }\r\n setBarDate({ id: child[mapFields.value.id], startDate: child[mapFields.value.startdate], endDate: child[mapFields.value.enddate] });\r\n }\r\n }\r\n }\r\n setBarDate({ id: props.row[mapFields.value.id], startDate: props.row[mapFields.value.startdate], endDate: props.row[mapFields.value.enddate] });\r\n }\r\n }\r\n });\r\n\r\n // 调整大小功能\r\n interact(barElement).resizable({\r\n edges: { left: true, right: true, bottom: false, top: false },\r\n listeners: {\r\n start: (event: { target: SVGSVGElement }) => {\r\n oldBarDataX.value = Number(event.target.getAttribute('data-x'));\r\n oldBarWidth.value = Number(event.target.getAttribute('width'));\r\n },\r\n end: (event: { target: SVGSVGElement; rect: { width: number }; edges: { left: boolean; right: boolean } }) => {\r\n setAllowChangeTaskDate(props.row);\r\n let target = event.target;\r\n let newWidth = event.rect.width;\r\n let widthCells = Math.round(newWidth / scale.value);\r\n if (widthCells < 1) widthCells = 1;\r\n newWidth = widthCells * scale.value;\r\n let currentX = oldBarDataX.value;\r\n \r\n if (event.edges && event.edges.left) {\r\n currentX = oldBarDataX.value + (oldBarWidth.value - newWidth);\r\n currentX = Math.round(currentX / scale.value) * scale.value;\r\n if (currentX < 0) currentX = 0;\r\n \r\n const parentIdField = mapFields.value.parentId || 'pid';\r\n const currentParentId = props.row[parentIdField];\r\n if (currentParentId && currentParentId !== '0') {\r\n const parentTask = store.tasks.find(t => String(t[mapFields.value.id]) === String(currentParentId));\r\n if (parentTask) {\r\n let parentStartX = 0;\r\n if (mode.value === '月' || mode.value === '日') {\r\n parentStartX = dayjs(parentTask[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'days') * scale.value;\r\n } else if (mode.value === '周') {\r\n const ganttStartWeek = dayjs(props.startGanttDate).startOf('isoWeek');\r\n const parentStartWeek = dayjs(parentTask[mapFields.value.startdate]).startOf('isoWeek');\r\n parentStartX = parentStartWeek.diff(ganttStartWeek, 'week') * scale.value;\r\n } else if (mode.value === '时') {\r\n parentStartX = dayjs(parentTask[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'hours') * scale.value;\r\n }\r\n if (currentX < parentStartX) {\r\n currentX = parentStartX;\r\n newWidth = oldBarDataX.value + oldBarWidth.value - currentX;\r\n widthCells = Math.round(newWidth / scale.value);\r\n if (widthCells < 1) widthCells = 1;\r\n newWidth = widthCells * scale.value;\r\n }\r\n }\r\n }\r\n }\r\n \r\n target.setAttribute('width', newWidth.toString());\r\n target.style.width = newWidth + 'px';\r\n target.style.transform = `translate(${currentX}px, 0px)`;\r\n target.setAttribute('data-x', currentX.toString());\r\n \r\n const startCellIndex = Math.round(currentX / scale.value);\r\n const endCellIndex = startCellIndex + widthCells - 1;\r\n let newStartDate: string, newEndDate: string;\r\n \r\n if (mode.value === '月' || mode.value === '日') {\r\n newStartDate = dayjs(props.startGanttDate).add(startCellIndex, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n newEndDate = dayjs(props.startGanttDate).add(endCellIndex, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.takestime] = widthCells + '天';\r\n } else if (mode.value === '周') {\r\n const ganttStartWeek = dayjs(props.startGanttDate).startOf('isoWeek');\r\n newStartDate = ganttStartWeek.add(startCellIndex, 'weeks').format('YYYY-MM-DD HH:mm:ss');\r\n newEndDate = ganttStartWeek.add(endCellIndex, 'weeks').endOf('isoWeek').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.takestime] = widthCells + '周';\r\n } else {\r\n newStartDate = dayjs(props.startGanttDate).add(startCellIndex, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n newEndDate = dayjs(props.startGanttDate).add(endCellIndex, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.takestime] = widthCells + '小时';\r\n }\r\n \r\n props.row[mapFields.value.startdate] = newStartDate;\r\n props.row[mapFields.value.enddate] = newEndDate;\r\n \r\n let svg = SVG(barElement as unknown as HTMLElement);\r\n let innerRect = svg.select('.innerRect').first();\r\n let outerRect = svg.select('rect:not(.innerRect):not(.progressHandle)').first();\r\n if (innerRect) {\r\n let innerRectWidth = props.row[mapFields.value.progress] ? newWidth * Number(props.row[mapFields.value.progress]) : newWidth;\r\n innerRect.width(innerRectWidth);\r\n }\r\n if (outerRect) outerRect.width(newWidth);\r\n \r\n // 联动子任务\r\n if (event.edges && event.edges.left) {\r\n const newParentStartDate = dayjs(newStartDate);\r\n const currentTaskId = props.row[mapFields.value.id];\r\n const parentIdField = mapFields.value.parentId || 'pid';\r\n const getAllChildren = (parentId: any, tasks: any[]): any[] => {\r\n const children: any[] = [];\r\n for (const task of tasks) {\r\n if (String(task[parentIdField]) === String(parentId)) {\r\n children.push(task);\r\n children.push(...getAllChildren(task[mapFields.value.id], tasks));\r\n }\r\n }\r\n return children;\r\n };\r\n const childTasks = getAllChildren(currentTaskId, store.tasks);\r\n for (const child of childTasks) {\r\n if (dayjs(child[mapFields.value.startdate]).isBefore(newParentStartDate)) {\r\n const childOffset = newParentStartDate.diff(dayjs(child[mapFields.value.startdate]), mode.value === '时' ? 'hours' : 'days');\r\n if (mode.value === '时') {\r\n child[mapFields.value.startdate] = dayjs(child[mapFields.value.startdate]).add(childOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n child[mapFields.value.enddate] = dayjs(child[mapFields.value.enddate]).add(childOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n } else {\r\n child[mapFields.value.startdate] = dayjs(child[mapFields.value.startdate]).add(childOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n child[mapFields.value.enddate] = dayjs(child[mapFields.value.enddate]).add(childOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n }\r\n setBarDate({ id: child[mapFields.value.id], startDate: child[mapFields.value.startdate], endDate: child[mapFields.value.enddate] });\r\n }\r\n }\r\n }\r\n setBarDate({ id: props.row[mapFields.value.id], startDate: newStartDate, endDate: newEndDate });\r\n }\r\n },\r\n modifiers: [\r\n interact.modifiers.restrictEdges({ outer: 'parent' }),\r\n interact.modifiers.restrictSize({ min: { width: scale.value, height: barHeight.value } })\r\n ],\r\n inertia: false, hold: 1\r\n });\r\n };\r\n\r\n watch(() => [props.row[mapFields.value.startdate], props.row[mapFields.value.enddate]], () => {\r\n if (bar.value && isBarInteracted.value) drowBar(bar.value);\r\n }, { deep: false });\r\n\r\n onMounted(() => {\r\n console.log(`[Bar] Component mounted, task: ${props.row[mapFields.value.id]}, mode: ${store.mode}`);\r\n if (bar.value && !isBarInteracted.value) {\r\n drowBar(bar.value);\r\n isBarInteracted.value = true;\r\n }\r\n if (setBarColor) {\r\n barColor.value = setBarColor(props.row);\r\n if (bar.value) drowBar(bar.value);\r\n }\r\n // 监听主题变化\r\n if (bar.value) {\r\n let ganttContainer = bar.value.parentElement;\r\n while (ganttContainer && !ganttContainer.hasAttribute('data-gantt-theme')) {\r\n ganttContainer = ganttContainer.parentElement;\r\n }\r\n if (ganttContainer) {\r\n const observer = new MutationObserver(() => { themeVersion.value++; });\r\n observer.observe(ganttContainer, { attributes: true, attributeFilter: ['data-gantt-theme', 'style'] });\r\n onBeforeUnmount(() => observer.disconnect());\r\n }\r\n }\r\n });\r\n\r\n onDeactivated(() => {\r\n if (bar.value) { try { interact(bar.value).unset(); } catch (e) {} }\r\n showRow.value = false;\r\n });\r\n\r\n onBeforeUnmount(() => {\r\n if (bar.value) { try { interact(bar.value).unset(); } catch (e) {} }\r\n showRow.value = false;\r\n });\r\n\r\n return {\r\n bar, barHeight, direction, oldBarDataX, oldBarWidth, showRow, hover, barColor,\r\n timelineCellCount, scale, mode, mapFields, hoverActive, hoverInactive, WeekEndColor\r\n };\r\n },\r\n})\r\n</script>\r\n<style lang=\"scss\" scoped>\r\n.barRow.active { background: var(--row-hover, #FFF3A1) !important; .cell { background: var(--row-hover, #FFF3A1) !important; } }\r\n.barRow {\r\n display: flex; flex-flow: row nowrap; align-items: center; justify-content: flex-start;\r\n width: fit-content; position: relative; overflow: visible;\r\n .bar { position: absolute; z-index: 100; background-color: #faf7ec; border-radius: 10px; overflow: visible; }\r\n &:first-child .cell {\r\n border-top: none; display: flex; align-items: center; justify-content: center; font-size: 10px;\r\n position: relative; margin: 0; box-sizing: border-box;\r\n &:first-child { border-left: 1px solid var(--border, #cecece); }\r\n &:not(:last-child) { border-right: 1px solid var(--border, #cecece); }\r\n &:last-child { border-right: 1px solid var(--border, #cecece); }\r\n }\r\n &:not(:first-child) .cell {\r\n border-top: 1px solid var(--border, #cecece); display: flex; align-items: center; justify-content: center;\r\n font-size: 10px; position: relative; margin: 0; box-sizing: border-box;\r\n &:first-child { border-left: 1px solid var(--border, #cecece); }\r\n &:not(:last-child) { border-right: 1px solid var(--border, #cecece); }\r\n &:last-child { border-right: 1px solid var(--border, #cecece); }\r\n }\r\n &:last-child .cell { border-bottom: 1px solid var(--border, #cecece); }\r\n}\r\n.progressHandle { \r\n pointer-events: auto !important; \r\n cursor: ew-resize !important;\r\n}\r\n</style>","<template>\r\n <div v-if='showRow' class=\"barRow\" :style=\"{ height: rowHeight + 'px' }\" @mouseover=\"hoverActive()\"\r\n @mouseleave=\"hoverInactive()\" :class=\"{ active: hover }\" :data-task-id=\"row[mapFields.id]\">\r\n <svg key=\"row.no\" v-if='showRow' ref='bar' class=\"bar\" :height=\"barHeight + 'px'\"\r\n :class=\"{ active: hover }\" style=\"overflow: visible;\"></svg>\r\n <template v-for='(count) in timelineCellCount'\r\n :key=\"count + row.id + timelineCellCount + showRow + '_template'\">\r\n <div class=\"cell\"\r\n :style=\"{ width: scale + 'px', minWidth: scale + 'px', maxWidth: scale + 'px', height: rowHeight + 'px', background: WeekEndColor(count) }\">\r\n </div>\r\n </template>\r\n </div>\r\n</template>\r\n<script lang=\"ts\">\r\nimport { defineComponent, watch, ref, computed, onMounted, onDeactivated, onBeforeUnmount, inject } from 'vue';\r\nimport SVG from 'svg.js';\r\nimport interact from 'interactjs';\r\nimport dayjs from 'dayjs';\r\nimport isoWeek from 'dayjs/plugin/isoWeek';\r\ndayjs.extend(isoWeek);\r\nimport { store, mutations } from './Store';\r\nimport sharedState from '../gantt/ShareState';\r\nimport { Symbols } from './Symbols';\r\n\r\nexport default defineComponent({\r\n name: 'Bar',\r\n emits: ['progress-update'],\r\n props: {\r\n rowHeight: { type: Number as () => number, default: 0 },\r\n row: { type: Object as () => Record<string, any>, default: () => ({}) },\r\n startGanttDate: { type: String as () => string },\r\n endGanttDate: { type: String as () => string }\r\n },\r\n setup(props, { emit }) {\r\n const bar = ref<SVGSVGElement | null>(null);\r\n const barHeight = ref(props.rowHeight * 0.7);\r\n const direction = ref<string | null>(null);\r\n const oldBarDataX = ref(0);\r\n const oldBarWidth = ref(0);\r\n const showRow = ref(true);\r\n const hover = ref(false);\r\n const barColor = ref('');\r\n const isBarInteracted = ref(false);\r\n const themeVersion = ref(0);\r\n const isProgressDragging = ref(false);\r\n\r\n const timelineCellCount = computed(() => store.timelineCellCount);\r\n const scale = computed(() => store.scale);\r\n const mode = computed(() => store.mode);\r\n const mapFields = computed(() => store.mapFields);\r\n const progress = computed(() => {\r\n const progressValue = Number(props.row[mapFields.value.progress]);\r\n if (isNaN(progressValue)) return '0.00%';\r\n return (progressValue * 100).toFixed(2) + '%';\r\n });\r\n\r\n const setBarColor = inject(Symbols.SetBarColorSymbol) as ((row: any) => string) | undefined;\r\n\r\n // 进度更新事件\r\n const emitProgressUpdate = (newProgress: number) => {\r\n const detail = {\r\n taskId: props.row[mapFields.value.id],\r\n oldProgress: Number(props.row[mapFields.value.progress]) || 0,\r\n newProgress: newProgress,\r\n task: props.row\r\n };\r\n emit('progress-update', detail);\r\n window.dispatchEvent(new CustomEvent('taskProgressUpdate', { detail }));\r\n console.log('Task progress updated:', detail);\r\n };\r\n\r\n watch(() => sharedState.highlightedId, (newId) => {\r\n hover.value = props.row[mapFields.value['id']] === newId;\r\n });\r\n\r\n const hoverActive = () => sharedState.triggerHighlight(props.row[mapFields.value.id] as number | null);\r\n const hoverInactive = () => sharedState.triggerHighlight(null);\r\n\r\n const WeekEndColor = (count: number) => {\r\n themeVersion.value;\r\n let bgContent = '#ffffff', bgSecondary = '#f8f8f8';\r\n if (bar.value) {\r\n let element = bar.value.parentElement;\r\n while (element) {\r\n if (element.hasAttribute('data-gantt-theme')) {\r\n bgContent = getComputedStyle(element).getPropertyValue('--bg-content').trim() || '#ffffff';\r\n bgSecondary = getComputedStyle(element).getPropertyValue('--bg-secondary').trim() || '#f8f8f8';\r\n break;\r\n }\r\n element = element.parentElement;\r\n }\r\n }\r\n switch (mode.value) {\r\n case '月': case '日': {\r\n let currentDate = dayjs(props.startGanttDate).add(count, 'days');\r\n return (currentDate.isoWeekday() === 7 || currentDate.isoWeekday() === 1) ? bgSecondary : bgContent;\r\n }\r\n case '周': case '时': return bgContent;\r\n }\r\n };\r\n\r\n const setBarDate = mutations.setBarDate;\r\n const setAllowChangeTaskDate = mutations.setAllowChangeTaskDate;\r\n\r\n const drowBar = (barElement: SVGSVGElement) => {\r\n let dataX = 0;\r\n switch (mode.value) {\r\n case '月': case '日': {\r\n let fromPlanStartDays = dayjs(props.row[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'days');\r\n dataX = scale.value * fromPlanStartDays;\r\n let spendDays = dayjs(props.row[mapFields.value.enddate]).diff(dayjs(props.row[mapFields.value.startdate]), 'days') + 1;\r\n oldBarWidth.value = spendDays * scale.value;\r\n props.row[mapFields.value.takestime] = spendDays + '天';\r\n break;\r\n }\r\n case '周': {\r\n const startGanttWeek = dayjs(props.startGanttDate).startOf('isoWeek');\r\n const taskStartWeek = dayjs(props.row[mapFields.value.startdate]).startOf('isoWeek');\r\n let fromPlanStartWeeks = taskStartWeek.diff(startGanttWeek, 'week');\r\n dataX = scale.value * fromPlanStartWeeks;\r\n const taskEndWeek = dayjs(props.row[mapFields.value.enddate]).startOf('isoWeek');\r\n let spendWeeks = taskEndWeek.diff(taskStartWeek, 'week') + 1;\r\n oldBarWidth.value = spendWeeks * scale.value;\r\n props.row[mapFields.value.takestime] = spendWeeks + '周';\r\n break;\r\n }\r\n case '时': {\r\n let fromPlanStartHours = dayjs(props.row[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'hours');\r\n dataX = scale.value * fromPlanStartHours;\r\n let spendHours = dayjs(props.row[mapFields.value.enddate]).diff(dayjs(props.row[mapFields.value.startdate]), 'hours') + 1;\r\n oldBarWidth.value = spendHours * scale.value;\r\n props.row[mapFields.value.takestime] = spendHours + '小时';\r\n break;\r\n }\r\n }\r\n oldBarDataX.value = dataX;\r\n let svg = SVG(barElement as unknown as HTMLElement);\r\n const borderColor = getComputedStyle(barElement).getPropertyValue('--border') || '#cecece';\r\n barElement.setAttribute('data-x', dataX.toString());\r\n barElement.setAttribute('width', oldBarWidth.value.toString());\r\n barElement.setAttribute('stroke', borderColor);\r\n barElement.setAttribute('stroke-width', '1px');\r\n barElement.style.transform = `translate(${dataX}px, 0px)`;\r\n\r\n let p = svg.select('pattern').first();\r\n let g = (svg.children().filter((child) => child.type === 'g')[0] as any) || svg.group();\r\n let innerRect = svg.select('.innerRect').first();\r\n let outerRect = svg.select('rect:not(.innerRect):not(.progressHandle)').first();\r\n let text = svg.select('text').first();\r\n let progressHandle = svg.select('.progressHandle').first();\r\n\r\n if (!p) {\r\n p = svg.pattern(10, 10, (add) => {\r\n (add as any).path('M10 -5 -10,15M15,0,0,15M0 -5 -20,15').fill('none').stroke({ color: 'gray', opacity: 0.4, width: 5 });\r\n });\r\n }\r\n if (!g) g = svg.group();\r\n\r\n let innerRectWidth = props.row[mapFields.value.progress] \r\n ? Number(oldBarWidth.value) * Number(props.row[mapFields.value.progress]) \r\n : Number(oldBarWidth.value);\r\n \r\n if (!innerRect) {\r\n innerRect = svg.rect(innerRectWidth, barHeight.value).radius(10);\r\n innerRect.addClass('innerRect');\r\n g.add(innerRect);\r\n } else {\r\n innerRect.fill({ color: barColor.value, opacity: 0.4 });\r\n innerRect.width(innerRectWidth);\r\n }\r\n\r\n if (!outerRect) {\r\n outerRect = svg.rect(oldBarWidth.value, barHeight.value).radius(10).fill(p).stroke({ color: borderColor, width: 1 });\r\n outerRect.on('mouseover', () => outerRect.animate(200).attr({ stroke: '#000', strokeWidth: 2, opacity: 1 }));\r\n outerRect.on('mouseleave', () => outerRect.animate(200).attr({ stroke: '#0066ff', strokeWidth: 10, opacity: 0.4 }));\r\n } else {\r\n outerRect.width(oldBarWidth.value);\r\n }\r\n\r\n if (!text) {\r\n text = svg.text(progress.value).stroke('#faf7ec');\r\n } else {\r\n (text as any).text(progress.value);\r\n }\r\n const textBBox = text.bbox();\r\n (text as any).font({ size: 15, anchor: 'middle', leading: '1em' })\r\n .fill('#000').attr('opacity', 1).attr('dominant-baseline', 'middle')\r\n .center(innerRect.width() / 2 + textBBox.width / 2, innerRect.height() / 2);\r\n\r\n // 进度调节滑块 - 三角形拖拽手柄 + 对齐虚线\r\n const handleWidth = 12;\r\n const handleHeight = 8;\r\n const handleX = innerRectWidth - handleWidth / 2;\r\n // 三角形位置:Bar底部边缘穿过三角形中心\r\n const handleY = barHeight.value - handleHeight / 2;\r\n const lineX = innerRectWidth;\r\n \r\n // 获取主题颜色的辅助函数\r\n const getThemeColors = () => {\r\n let primary = '#f59e0b', primaryDark = '#d97706', primaryLight = '#fbbf24';\r\n let element = barElement.parentElement;\r\n while (element) {\r\n if (element.hasAttribute('data-gantt-theme')) {\r\n primary = getComputedStyle(element).getPropertyValue('--primary').trim() || primary;\r\n primaryDark = getComputedStyle(element).getPropertyValue('--primary-dark').trim() || primaryDark;\r\n primaryLight = getComputedStyle(element).getPropertyValue('--primary-light').trim() || primaryLight;\r\n break;\r\n }\r\n element = element.parentElement;\r\n }\r\n return { primary, primaryDark, primaryLight };\r\n };\r\n \r\n // 查找或创建对齐虚线\r\n let guideLineEl = barElement.querySelector('.progressGuideLine') as SVGLineElement | null;\r\n const themeColors = getThemeColors();\r\n \r\n if (!guideLineEl) {\r\n // 创建对齐虚线\r\n const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');\r\n line.setAttribute('class', 'progressGuideLine');\r\n line.setAttribute('x1', String(lineX));\r\n line.setAttribute('y1', '0');\r\n line.setAttribute('x2', String(lineX));\r\n line.setAttribute('y2', String(handleY));\r\n line.setAttribute('stroke', themeColors.primaryDark);\r\n line.setAttribute('stroke-width', '2');\r\n line.setAttribute('stroke-dasharray', '4,3');\r\n line.setAttribute('opacity', '0.8');\r\n barElement.appendChild(line);\r\n guideLineEl = line;\r\n }\r\n // 始终更新位置和可见性\r\n guideLineEl.setAttribute('x1', String(lineX));\r\n guideLineEl.setAttribute('x2', String(lineX));\r\n guideLineEl.setAttribute('y2', String(handleY));\r\n guideLineEl.setAttribute('stroke', themeColors.primaryDark);\r\n guideLineEl.setAttribute('opacity', '0.8');\r\n \r\n if (!progressHandle) {\r\n // 创建三角形手柄\r\n const trianglePoints = `${handleWidth/2},0 0,${handleHeight} ${handleWidth},${handleHeight}`;\r\n progressHandle = svg.polygon(trianglePoints)\r\n .fill(themeColors.primary)\r\n .stroke({ color: themeColors.primaryDark, width: 1 })\r\n .addClass('progressHandle');\r\n \r\n const handleElement = progressHandle.node as unknown as SVGPolygonElement;\r\n handleElement.style.cursor = 'ew-resize';\r\n handleElement.style.pointerEvents = 'auto';\r\n progressHandle.move(handleX, handleY);\r\n \r\n // 用于记录当前X位置\r\n let currentHandleX = handleX;\r\n \r\n // 悬停效果 - 高亮显示\r\n handleElement.addEventListener('mouseenter', () => {\r\n if (!isProgressDragging.value) {\r\n const colors = getThemeColors();\r\n handleElement.setAttribute('fill', colors.primaryLight);\r\n handleElement.setAttribute('stroke', colors.primary);\r\n handleElement.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('stroke', colors.primaryLight);\r\n guideLineEl!.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('opacity', '1');\r\n }\r\n });\r\n handleElement.addEventListener('mouseleave', () => {\r\n if (!isProgressDragging.value) {\r\n const colors = getThemeColors();\r\n handleElement.setAttribute('fill', colors.primary);\r\n handleElement.setAttribute('stroke', colors.primaryDark);\r\n handleElement.setAttribute('stroke-width', '1');\r\n guideLineEl!.setAttribute('stroke', colors.primaryDark);\r\n guideLineEl!.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('opacity', '0.8');\r\n }\r\n });\r\n \r\n // 拖拽交互\r\n interact(handleElement).draggable({\r\n inertia: false,\r\n listeners: {\r\n start: () => { \r\n isProgressDragging.value = true;\r\n const colors = getThemeColors();\r\n handleElement.setAttribute('fill', colors.primaryDark);\r\n handleElement.setAttribute('stroke', colors.primaryDark);\r\n handleElement.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('stroke', colors.primaryDark);\r\n guideLineEl!.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('opacity', '1');\r\n },\r\n move: (event) => {\r\n currentHandleX += event.dx;\r\n currentHandleX = Math.max(-handleWidth / 2, Math.min(currentHandleX, oldBarWidth.value - handleWidth / 2));\r\n \r\n progressHandle.move(currentHandleX, handleY);\r\n \r\n // 更新虚线位置\r\n const newLineX = currentHandleX + handleWidth / 2;\r\n guideLineEl!.setAttribute('x1', String(newLineX));\r\n guideLineEl!.setAttribute('x2', String(newLineX));\r\n \r\n // 更新进度\r\n const newProgress = Math.min(1, Math.max(0, (currentHandleX + handleWidth / 2) / oldBarWidth.value));\r\n innerRect.width(newProgress * oldBarWidth.value);\r\n (text as any).text((newProgress * 100).toFixed(2) + '%');\r\n (text as any).center(innerRect.width() / 2 + textBBox.width / 2, innerRect.height() / 2);\r\n },\r\n end: () => {\r\n isProgressDragging.value = false;\r\n const colors = getThemeColors();\r\n handleElement.setAttribute('fill', colors.primary);\r\n handleElement.setAttribute('stroke', colors.primaryDark);\r\n handleElement.setAttribute('stroke-width', '1');\r\n guideLineEl!.setAttribute('stroke', colors.primaryDark);\r\n guideLineEl!.setAttribute('stroke-width', '2');\r\n guideLineEl!.setAttribute('opacity', '0.8');\r\n \r\n const newProgress = Math.min(1, Math.max(0, (currentHandleX + handleWidth / 2) / oldBarWidth.value));\r\n props.row[mapFields.value.progress] = newProgress;\r\n emitProgressUpdate(newProgress);\r\n }\r\n }\r\n });\r\n } else {\r\n progressHandle.move(handleX, handleY);\r\n // 更新已存在的三角形颜色以响应主题变化\r\n const handleElement = progressHandle.node as unknown as SVGPolygonElement;\r\n handleElement.setAttribute('fill', themeColors.primary);\r\n handleElement.setAttribute('stroke', themeColors.primaryDark);\r\n }\r\n\r\n setBarDate({ id: props.row[mapFields.value.id], startDate: props.row[mapFields.value.startdate], endDate: props.row[mapFields.value.enddate] });\r\n\r\n // 拖拽功能\r\n interact(barElement).draggable({\r\n inertia: false,\r\n modifiers: [interact.modifiers.restrictRect({ restriction: 'parent', endOnly: true })],\r\n autoScroll: true,\r\n listeners: {\r\n start: (event: { target: SVGSVGElement }) => {\r\n if (isProgressDragging.value) return;\r\n oldBarDataX.value = Number(event.target.getAttribute('data-x'));\r\n oldBarWidth.value = event.target.width.baseVal.value;\r\n },\r\n move: (event: { target: SVGSVGElement; dx: number; rect: { width: number; height: number } }) => {\r\n if (isProgressDragging.value) return;\r\n let x = ((parseFloat(event.target.getAttribute('data-x') || '0') || 0) + event.dx).toString();\r\n Object.assign(event.target.style, { width: `${event.rect.width}px`, height: `${event.rect.height}px`, transform: `translate(${x}px, 0px)` });\r\n event.target.setAttribute('data-x', x);\r\n event.target.setAttribute('data-y', '0');\r\n },\r\n end: (event: { target: SVGSVGElement }) => {\r\n if (isProgressDragging.value) return;\r\n let target = event.target;\r\n let currentX = parseFloat(target.getAttribute('data-x') || '0') || 0;\r\n let multiple = Math.round(currentX / scale.value);\r\n let alignedX = multiple * scale.value;\r\n if (alignedX < 0) alignedX = 0;\r\n if (alignedX > timelineCellCount.value * scale.value) alignedX = timelineCellCount.value * scale.value;\r\n \r\n const parentIdField = mapFields.value.parentId || 'pid';\r\n const currentParentId = props.row[parentIdField];\r\n if (currentParentId && currentParentId !== '0') {\r\n const parentTask = store.tasks.find(t => String(t[mapFields.value.id]) === String(currentParentId));\r\n if (parentTask) {\r\n let parentStartX = 0;\r\n if (mode.value === '月' || mode.value === '日') {\r\n parentStartX = dayjs(parentTask[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'days') * scale.value;\r\n } else if (mode.value === '周') {\r\n const ganttStartWeek = dayjs(props.startGanttDate).startOf('isoWeek');\r\n const parentStartWeek = dayjs(parentTask[mapFields.value.startdate]).startOf('isoWeek');\r\n parentStartX = parentStartWeek.diff(ganttStartWeek, 'week') * scale.value;\r\n } else if (mode.value === '时') {\r\n parentStartX = dayjs(parentTask[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'hours') * scale.value;\r\n }\r\n if (alignedX < parentStartX) alignedX = parentStartX;\r\n }\r\n }\r\n \r\n target.style.transform = `translate(${alignedX}px, 0px)`;\r\n target.setAttribute('data-x', alignedX.toString());\r\n \r\n const cellsMoved = Math.round((alignedX - oldBarDataX.value) / scale.value);\r\n let daysOffset = 0, hoursOffset = 0;\r\n if (mode.value === '月' || mode.value === '日') daysOffset = cellsMoved;\r\n else if (mode.value === '周') daysOffset = cellsMoved * 7;\r\n else if (mode.value === '时') hoursOffset = cellsMoved;\r\n \r\n if (mode.value === '时') {\r\n props.row[mapFields.value.startdate] = dayjs(props.row[mapFields.value.startdate]).add(hoursOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.enddate] = dayjs(props.row[mapFields.value.enddate]).add(hoursOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.takestime] = (dayjs(props.row[mapFields.value.enddate]).diff(dayjs(props.row[mapFields.value.startdate]), 'hours') + 1) + '小时';\r\n } else {\r\n props.row[mapFields.value.startdate] = dayjs(props.row[mapFields.value.startdate]).add(daysOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.enddate] = dayjs(props.row[mapFields.value.enddate]).add(daysOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n if (mode.value === '月' || mode.value === '日') {\r\n props.row[mapFields.value.takestime] = (dayjs(props.row[mapFields.value.enddate]).diff(dayjs(props.row[mapFields.value.startdate]), 'days') + 1) + '天';\r\n } else if (mode.value === '周') {\r\n const startWeek = dayjs(props.row[mapFields.value.startdate]).startOf('isoWeek');\r\n const endWeek = dayjs(props.row[mapFields.value.enddate]).startOf('isoWeek');\r\n props.row[mapFields.value.takestime] = (endWeek.diff(startWeek, 'week') + 1) + '周';\r\n }\r\n }\r\n \r\n // 联动子任务\r\n const newParentStartDate = dayjs(props.row[mapFields.value.startdate]);\r\n const currentTaskId = props.row[mapFields.value.id];\r\n const getAllChildren = (parentId: any, tasks: any[]): any[] => {\r\n const children: any[] = [];\r\n for (const task of tasks) {\r\n if (String(task[parentIdField]) === String(parentId)) {\r\n children.push(task);\r\n children.push(...getAllChildren(task[mapFields.value.id], tasks));\r\n }\r\n }\r\n return children;\r\n };\r\n const childTasks = getAllChildren(currentTaskId, store.tasks);\r\n const actualOffset = mode.value === '时' ? hoursOffset : daysOffset;\r\n if (actualOffset > 0) {\r\n for (const child of childTasks) {\r\n if (dayjs(child[mapFields.value.startdate]).isBefore(newParentStartDate)) {\r\n if (mode.value === '时') {\r\n child[mapFields.value.startdate] = dayjs(child[mapFields.value.startdate]).add(hoursOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n child[mapFields.value.enddate] = dayjs(child[mapFields.value.enddate]).add(hoursOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n } else {\r\n child[mapFields.value.startdate] = dayjs(child[mapFields.value.startdate]).add(daysOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n child[mapFields.value.enddate] = dayjs(child[mapFields.value.enddate]).add(daysOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n }\r\n setBarDate({ id: child[mapFields.value.id], startDate: child[mapFields.value.startdate], endDate: child[mapFields.value.enddate] });\r\n }\r\n }\r\n }\r\n setBarDate({ id: props.row[mapFields.value.id], startDate: props.row[mapFields.value.startdate], endDate: props.row[mapFields.value.enddate] });\r\n }\r\n }\r\n });\r\n\r\n // 调整大小功能\r\n interact(barElement).resizable({\r\n edges: { left: true, right: true, bottom: false, top: false },\r\n listeners: {\r\n start: (event: { target: SVGSVGElement }) => {\r\n oldBarDataX.value = Number(event.target.getAttribute('data-x'));\r\n oldBarWidth.value = Number(event.target.getAttribute('width'));\r\n },\r\n end: (event: { target: SVGSVGElement; rect: { width: number }; edges: { left: boolean; right: boolean } }) => {\r\n setAllowChangeTaskDate(props.row);\r\n let target = event.target;\r\n let newWidth = event.rect.width;\r\n let widthCells = Math.round(newWidth / scale.value);\r\n if (widthCells < 1) widthCells = 1;\r\n newWidth = widthCells * scale.value;\r\n let currentX = oldBarDataX.value;\r\n \r\n if (event.edges && event.edges.left) {\r\n currentX = oldBarDataX.value + (oldBarWidth.value - newWidth);\r\n currentX = Math.round(currentX / scale.value) * scale.value;\r\n if (currentX < 0) currentX = 0;\r\n \r\n const parentIdField = mapFields.value.parentId || 'pid';\r\n const currentParentId = props.row[parentIdField];\r\n if (currentParentId && currentParentId !== '0') {\r\n const parentTask = store.tasks.find(t => String(t[mapFields.value.id]) === String(currentParentId));\r\n if (parentTask) {\r\n let parentStartX = 0;\r\n if (mode.value === '月' || mode.value === '日') {\r\n parentStartX = dayjs(parentTask[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'days') * scale.value;\r\n } else if (mode.value === '周') {\r\n const ganttStartWeek = dayjs(props.startGanttDate).startOf('isoWeek');\r\n const parentStartWeek = dayjs(parentTask[mapFields.value.startdate]).startOf('isoWeek');\r\n parentStartX = parentStartWeek.diff(ganttStartWeek, 'week') * scale.value;\r\n } else if (mode.value === '时') {\r\n parentStartX = dayjs(parentTask[mapFields.value.startdate]).diff(dayjs(props.startGanttDate), 'hours') * scale.value;\r\n }\r\n if (currentX < parentStartX) {\r\n currentX = parentStartX;\r\n newWidth = oldBarDataX.value + oldBarWidth.value - currentX;\r\n widthCells = Math.round(newWidth / scale.value);\r\n if (widthCells < 1) widthCells = 1;\r\n newWidth = widthCells * scale.value;\r\n }\r\n }\r\n }\r\n }\r\n \r\n target.setAttribute('width', newWidth.toString());\r\n target.style.width = newWidth + 'px';\r\n target.style.transform = `translate(${currentX}px, 0px)`;\r\n target.setAttribute('data-x', currentX.toString());\r\n \r\n const startCellIndex = Math.round(currentX / scale.value);\r\n const endCellIndex = startCellIndex + widthCells - 1;\r\n let newStartDate: string, newEndDate: string;\r\n \r\n if (mode.value === '月' || mode.value === '日') {\r\n newStartDate = dayjs(props.startGanttDate).add(startCellIndex, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n newEndDate = dayjs(props.startGanttDate).add(endCellIndex, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.takestime] = widthCells + '天';\r\n } else if (mode.value === '周') {\r\n const ganttStartWeek = dayjs(props.startGanttDate).startOf('isoWeek');\r\n newStartDate = ganttStartWeek.add(startCellIndex, 'weeks').format('YYYY-MM-DD HH:mm:ss');\r\n newEndDate = ganttStartWeek.add(endCellIndex, 'weeks').endOf('isoWeek').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.takestime] = widthCells + '周';\r\n } else {\r\n newStartDate = dayjs(props.startGanttDate).add(startCellIndex, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n newEndDate = dayjs(props.startGanttDate).add(endCellIndex, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n props.row[mapFields.value.takestime] = widthCells + '小时';\r\n }\r\n \r\n props.row[mapFields.value.startdate] = newStartDate;\r\n props.row[mapFields.value.enddate] = newEndDate;\r\n \r\n let svg = SVG(barElement as unknown as HTMLElement);\r\n let innerRect = svg.select('.innerRect').first();\r\n let outerRect = svg.select('rect:not(.innerRect):not(.progressHandle)').first();\r\n if (innerRect) {\r\n let innerRectWidth = props.row[mapFields.value.progress] ? newWidth * Number(props.row[mapFields.value.progress]) : newWidth;\r\n innerRect.width(innerRectWidth);\r\n }\r\n if (outerRect) outerRect.width(newWidth);\r\n \r\n // 联动子任务\r\n if (event.edges && event.edges.left) {\r\n const newParentStartDate = dayjs(newStartDate);\r\n const currentTaskId = props.row[mapFields.value.id];\r\n const parentIdField = mapFields.value.parentId || 'pid';\r\n const getAllChildren = (parentId: any, tasks: any[]): any[] => {\r\n const children: any[] = [];\r\n for (const task of tasks) {\r\n if (String(task[parentIdField]) === String(parentId)) {\r\n children.push(task);\r\n children.push(...getAllChildren(task[mapFields.value.id], tasks));\r\n }\r\n }\r\n return children;\r\n };\r\n const childTasks = getAllChildren(currentTaskId, store.tasks);\r\n for (const child of childTasks) {\r\n if (dayjs(child[mapFields.value.startdate]).isBefore(newParentStartDate)) {\r\n const childOffset = newParentStartDate.diff(dayjs(child[mapFields.value.startdate]), mode.value === '时' ? 'hours' : 'days');\r\n if (mode.value === '时') {\r\n child[mapFields.value.startdate] = dayjs(child[mapFields.value.startdate]).add(childOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n child[mapFields.value.enddate] = dayjs(child[mapFields.value.enddate]).add(childOffset, 'hours').format('YYYY-MM-DD HH:mm:ss');\r\n } else {\r\n child[mapFields.value.startdate] = dayjs(child[mapFields.value.startdate]).add(childOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n child[mapFields.value.enddate] = dayjs(child[mapFields.value.enddate]).add(childOffset, 'days').format('YYYY-MM-DD HH:mm:ss');\r\n }\r\n setBarDate({ id: child[mapFields.value.id], startDate: child[mapFields.value.startdate], endDate: child[mapFields.value.enddate] });\r\n }\r\n }\r\n }\r\n setBarDate({ id: props.row[mapFields.value.id], startDate: newStartDate, endDate: newEndDate });\r\n }\r\n },\r\n modifiers: [\r\n interact.modifiers.restrictEdges({ outer: 'parent' }),\r\n interact.modifiers.restrictSize({ min: { width: scale.value, height: barHeight.value } })\r\n ],\r\n inertia: false, hold: 1\r\n });\r\n };\r\n\r\n watch(() => [props.row[mapFields.value.startdate], props.row[mapFields.value.enddate]], () => {\r\n if (bar.value && isBarInteracted.value) drowBar(bar.value);\r\n }, { deep: false });\r\n\r\n onMounted(() => {\r\n console.log(`[Bar] Component mounted, task: ${props.row[mapFields.value.id]}, mode: ${store.mode}`);\r\n if (bar.value && !isBarInteracted.value) {\r\n drowBar(bar.value);\r\n isBarInteracted.value = true;\r\n }\r\n if (setBarColor) {\r\n barColor.value = setBarColor(props.row);\r\n if (bar.value) drowBar(bar.value);\r\n }\r\n // 监听主题变化\r\n if (bar.value) {\r\n let ganttContainer = bar.value.parentElement;\r\n while (ganttContainer && !ganttContainer.hasAttribute('data-gantt-theme')) {\r\n ganttContainer = ganttContainer.parentElement;\r\n }\r\n if (ganttContainer) {\r\n const observer = new MutationObserver(() => { themeVersion.value++; });\r\n observer.observe(ganttContainer, { attributes: true, attributeFilter: ['data-gantt-theme', 'style'] });\r\n onBeforeUnmount(() => observer.disconnect());\r\n }\r\n }\r\n });\r\n\r\n onDeactivated(() => {\r\n if (bar.value) { try { interact(bar.value).unset(); } catch (e) {} }\r\n showRow.value = false;\r\n });\r\n\r\n onBeforeUnmount(() => {\r\n if (bar.value) { try { interact(bar.value).unset(); } catch (e) {} }\r\n showRow.value = false;\r\n });\r\n\r\n return {\r\n bar, barHeight, direction, oldBarDataX, oldBarWidth, showRow, hover, barColor,\r\n timelineCellCount, scale, mode, mapFields, hoverActive, hoverInactive, WeekEndColor\r\n };\r\n },\r\n})\r\n</script>\r\n<style lang=\"scss\" scoped>\r\n.barRow.active { background: var(--row-hover, #FFF3A1) !important; .cell { background: var(--row-hover, #FFF3A1) !important; } }\r\n.barRow {\r\n display: flex; flex-flow: row nowrap; align-items: center; justify-content: flex-start;\r\n width: fit-content; position: relative; overflow: visible;\r\n .bar { position: absolute; z-index: 100; background-color: #faf7ec; border-radius: 10px; overflow: visible; }\r\n &:first-child .cell {\r\n border-top: none; display: flex; align-items: center; justify-content: center; font-size: 10px;\r\n position: relative; margin: 0; box-sizing: border-box;\r\n &:first-child { border-left: 1px solid var(--border, #cecece); }\r\n &:not(:last-child) { border-right: 1px solid var(--border, #cecece); }\r\n &:last-child { border-right: 1px solid var(--border, #cecece); }\r\n }\r\n &:not(:first-child) .cell {\r\n border-top: 1px solid var(--border, #cecece); display: flex; align-items: center; justify-content: center;\r\n font-size: 10px; position: relative; margin: 0; box-sizing: border-box;\r\n &:first-child { border-left: 1px solid var(--border, #cecece); }\r\n &:not(:last-child) { border-right: 1px solid var(--border, #cecece); }\r\n &:last-child { border-right: 1px solid var(--border, #cecece); }\r\n }\r\n &:last-child .cell { border-bottom: 1px solid var(--border, #cecece); }\r\n}\r\n.progressHandle { \r\n pointer-events: auto !important; \r\n cursor: ew-resize !important;\r\n}\r\n</style>","<template>\r\n <div>\r\n <template v-for=\"(item) in filterTask\" :key=\"item.id\">\r\n <Bar \r\n :startGanttDate=\"startGanttDate\" \r\n :endGanttDate=\"endGanttDate\" \r\n :row=\"item\" \r\n :rowHeight=\"rowHeight\" \r\n />\r\n </template>\r\n </div>\r\n </template>\r\n \r\n <script lang=\"ts\">\r\n import { defineComponent, ref, computed, watch } from 'vue';\r\n import { store, mutations } from '../gantt/Store';\r\n import Bar from '../gantt/Bar.vue';\r\n \r\n export default defineComponent({\r\n name: 'BarRecursionRow',\r\n props: {\r\n rowHeight: {\r\n type: Number as () => number,\r\n default: 0\r\n },\r\n },\r\n setup() {\r\n \r\n const hiddenTask = ref<any[]>([]);\r\n const componentKey = ref(0);\r\n \r\n const allTask = computed(() => store.tasks);\r\n const timelineCellCount = computed(() => store.timelineCellCount);\r\n const scale = computed(() => store.scale);\r\n const mode = computed(() => store.mode);\r\n const startGanttDate = computed(() => store.startGanttDate ? store.startGanttDate.toISOString() : undefined);\r\n const endGanttDate = computed(() => store.endGanttDate ? store.endGanttDate.toISOString() : undefined);\r\n const mapFields = computed(() => store.mapFields);\r\n const collapsedTasks = computed(() => store.collapsedTasks);\r\n \r\n // 获取所有被折叠的子任务\r\n const getAllCollapsedChildren = (parentId: any): Set<any> => {\r\n const collapsedChildren = new Set<any>();\r\n \r\n const collectChildren = (pid: any) => {\r\n const children = allTask.value.filter(task => task[mapFields.value['parentId']] === pid);\r\n children.forEach(child => {\r\n const childId = child[mapFields.value['id']];\r\n collapsedChildren.add(childId);\r\n // 递归收集所有子孙任务\r\n collectChildren(childId);\r\n });\r\n };\r\n \r\n collectChildren(parentId);\r\n return collapsedChildren;\r\n };\r\n \r\n // 优化:使用Set提高查找性能\r\n const hiddenTaskIds = computed(() => {\r\n return new Set(hiddenTask.value.map(obj => obj[mapFields.value.id]));\r\n });\r\n\r\n const filterTask = computed(() => {\r\n const hiddenIds = hiddenTaskIds.value;\r\n const tasks = store.tasks.filter(task => !hiddenIds.has(task[mapFields.value.id]));\r\n \r\n // 过滤折叠的子任务\r\n const allCollapsedIds = new Set<any>();\r\n collapsedTasks.value.forEach(collapsedId => {\r\n const children = getAllCollapsedChildren(collapsedId);\r\n children.forEach(childId => allCollapsedIds.add(childId));\r\n });\r\n \r\n return tasks.filter(task => !allCollapsedIds.has(task[mapFields.value.id]));\r\n });\r\n \r\n const expandRow = computed({\r\n get: () => store.expandRow,\r\n set: (newValue) => {\r\n mutations.setExpandRow(newValue);\r\n }\r\n });\r\n \r\n watch(expandRow, (newVal) => {\r\n hiddenTask.value = [];\r\n recursionRow(newVal.pid);\r\n });\r\n \r\n const recursionRow = (id: any) => {\r\n let findRows = allTask.value.filter(obj => obj[mapFields.value['parentId']] === id);\r\n if (findRows && findRows.length > 0) {\r\n for (let i = 0; i < findRows.length; i++) {\r\n if (expandRow.value.expand === false) {\r\n hiddenTask.value.push(findRows[i]);\r\n }\r\n recursionRow(findRows[i][mapFields.value['id']]);\r\n }\r\n }\r\n };\r\n \r\n const setExpandRow = mutations.setExpandRow;\r\n \r\n return {\r\n hiddenTask,\r\n componentKey,\r\n allTask,\r\n timelineCellCount,\r\n scale,\r\n mode,\r\n startGanttDate,\r\n endGanttDate,\r\n mapFields,\r\n filterTask,\r\n expandRow,\r\n setExpandRow,\r\n recursionRow\r\n };\r\n },\r\n components: { Bar },\r\n mounted() {\r\n this.$nextTick(() => {\r\n // 可以在这里添加挂载后的逻辑\r\n });\r\n },\r\n activated() {\r\n this.componentKey++;\r\n }\r\n });\r\n </script>","<template>\r\n <div>\r\n <template v-for=\"(item) in filterTask\" :key=\"item.id\">\r\n <Bar \r\n :startGanttDate=\"startGanttDate\" \r\n :endGanttDate=\"endGanttDate\" \r\n :row=\"item\" \r\n :rowHeight=\"rowHeight\" \r\n />\r\n </template>\r\n </div>\r\n </template>\r\n \r\n <script lang=\"ts\">\r\n import { defineComponent, ref, computed, watch } from 'vue';\r\n import { store, mutations } from '../gantt/Store';\r\n import Bar from '../gantt/Bar.vue';\r\n \r\n export default defineComponent({\r\n name: 'BarRecursionRow',\r\n props: {\r\n rowHeight: {\r\n type: Number as () => number,\r\n default: 0\r\n },\r\n },\r\n setup() {\r\n \r\n const hiddenTask = ref<any[]>([]);\r\n const componentKey = ref(0);\r\n \r\n const allTask = computed(() => store.tasks);\r\n const timelineCellCount = computed(() => store.timelineCellCount);\r\n const scale = computed(() => store.scale);\r\n const mode = computed(() => store.mode);\r\n const startGanttDate = computed(() => store.startGanttDate ? store.startGanttDate.toISOString() : undefined);\r\n const endGanttDate = computed(() => store.endGanttDate ? store.endGanttDate.toISOString() : undefined);\r\n const mapFields = computed(() => store.mapFields);\r\n const collapsedTasks = computed(() => store.collapsedTasks);\r\n \r\n // 获取所有被折叠的子任务\r\n const getAllCollapsedChildren = (parentId: any): Set<any> => {\r\n const collapsedChildren = new Set<any>();\r\n \r\n const collectChildren = (pid: any) => {\r\n const children = allTask.value.filter(task => task[mapFields.value['parentId']] === pid);\r\n children.forEach(child => {\r\n const childId = child[mapFields.value['id']];\r\n collapsedChildren.add(childId);\r\n // 递归收集所有子孙任务\r\n collectChildren(childId);\r\n });\r\n };\r\n \r\n collectChildren(parentId);\r\n return collapsedChildren;\r\n };\r\n \r\n // 优化:使用Set提高查找性能\r\n const hiddenTaskIds = computed(() => {\r\n return new Set(hiddenTask.value.map(obj => obj[mapFields.value.id]));\r\n });\r\n\r\n const filterTask = computed(() => {\r\n const hiddenIds = hiddenTaskIds.value;\r\n const tasks = store.tasks.filter(task => !hiddenIds.has(task[mapFields.value.id]));\r\n \r\n // 过滤折叠的子任务\r\n const allCollapsedIds = new Set<any>();\r\n collapsedTasks.value.forEach(collapsedId => {\r\n const children = getAllCollapsedChildren(collapsedId);\r\n children.forEach(childId => allCollapsedIds.add(childId));\r\n });\r\n \r\n return tasks.filter(task => !allCollapsedIds.has(task[mapFields.value.id]));\r\n });\r\n \r\n const expandRow = computed({\r\n get: () => store.expandRow,\r\n set: (newValue) => {\r\n mutations.setExpandRow(newValue);\r\n }\r\n });\r\n \r\n watch(expandRow, (newVal) => {\r\n hiddenTask.value = [];\r\n recursionRow(newVal.pid);\r\n });\r\n \r\n const recursionRow = (id: any) => {\r\n let findRows = allTask.value.filter(obj => obj[mapFields.value['parentId']] === id);\r\n if (findRows && findRows.length > 0) {\r\n for (let i = 0; i < findRows.length; i++) {\r\n if (expandRow.value.expand === false) {\r\n hiddenTask.value.push(findRows[i]);\r\n }\r\n recursionRow(findRows[i][mapFields.value['id']]);\r\n }\r\n }\r\n };\r\n \r\n const setExpandRow = mutations.setExpandRow;\r\n \r\n return {\r\n hiddenTask,\r\n componentKey,\r\n allTask,\r\n timelineCellCount,\r\n scale,\r\n mode,\r\n startGanttDate,\r\n endGanttDate,\r\n mapFields,\r\n filterTask,\r\n expandRow,\r\n setExpandRow,\r\n recursionRow\r\n };\r\n },\r\n components: { Bar },\r\n mounted() {\r\n this.$nextTick(() => {\r\n // 可以在这里添加挂载后的逻辑\r\n });\r\n },\r\n activated() {\r\n this.componentKey++;\r\n }\r\n });\r\n </script>","<template>\r\n <svg \r\n class=\"task-links-layer\" \r\n :width=\"containerWidth\" \r\n :height=\"containerHeight\"\r\n :style=\"{ \r\n position: 'absolute', \r\n top: '0px', \r\n left: '0px', \r\n pointerEvents: 'none',\r\n zIndex: 50,\r\n overflow: 'visible'\r\n }\"\r\n >\r\n <!-- 渲染所有连线 -->\r\n <g v-for=\"link in links\" :key=\"link.id\">\r\n <!-- 连线路径 -->\r\n <path\r\n :d=\"link.path\"\r\n :stroke=\"getLinkStyle(link.type).color\"\r\n :stroke-width=\"getLinkStyle(link.type).width\"\r\n :stroke-dasharray=\"getLinkStyle(link.type).dashArray\"\r\n fill=\"none\"\r\n :class=\"['task-link', link.type, { \r\n 'dash-animated': isDashedLine(link.type) && linkConfig.enableDashAnimation \r\n }]\"\r\n :style=\"getDashAnimationStyle(link)\"\r\n />\r\n \r\n <!-- 箭头 -->\r\n <polygon\r\n v-if=\"linkConfig.showArrow && link.arrowPoints && link.arrowPoints.length > 0\"\r\n :points=\"link.arrowPoints\"\r\n :fill=\"getLinkStyle(link.type).color\"\r\n :stroke=\"getLinkStyle(link.type).color\"\r\n :stroke-width=\"0.5\"\r\n class=\"task-link-arrow\"\r\n />\r\n \r\n <!-- 连线标签(可选) -->\r\n <text\r\n v-if=\"link.label && linkConfig.showLabels\"\r\n :x=\"link.labelX\"\r\n :y=\"link.labelY\"\r\n :fill=\"linkConfig.labelColor\"\r\n :font-size=\"linkConfig.labelFontSize\"\r\n text-anchor=\"middle\"\r\n class=\"task-link-label\"\r\n >\r\n {{ link.label }}\r\n </text>\r\n </g>\r\n </svg>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, watch, ref, onMounted, onUnmounted } from 'vue';\r\nimport { store } from './Store';\r\nimport { LinkType, LinkPathType, type LinkConfig, type TaskLink } from './Types';\r\nimport { linkDataManager } from './LinkConfig';\r\n\r\n\r\n\r\nexport default defineComponent({\r\n name: 'TaskLinks',\r\n props: {\r\n containerWidth: {\r\n type: Number,\r\n required: true\r\n },\r\n containerHeight: {\r\n type: Number,\r\n required: true\r\n },\r\n linkConfig: {\r\n type: Object as () => LinkConfig,\r\n default: () => ({\r\n color: '#3498db',\r\n width: 2,\r\n dashArray: undefined,\r\n showArrow: true,\r\n arrowColor: undefined,\r\n arrowSize: 8,\r\n showLabels: false,\r\n labelColor: '#666',\r\n labelFontSize: 12,\r\n cornerRadius: 5,\r\n pathType: LinkPathType.BEZIER,\r\n bezierCurvature: 0.4,\r\n rightAngleOffset: 30,\r\n smoothCorners: true,\r\n enableDashAnimation: true,\r\n dashAnimationSpeed: 0.8,\r\n parentChildStyle: {\r\n color: '#95a5a6',\r\n width: 1,\r\n dashArray: '3,3'\r\n }\r\n })\r\n }\r\n },\r\n setup(props) {\r\n const links = ref<TaskLink[]>([]);\r\n \r\n // 获取任务位置信息\r\n const getTaskPosition = (taskId: string) => {\r\n const task = store.tasks.find(t => t[store.mapFields.id] === taskId);\r\n if (!task) return null;\r\n \r\n // 查找对应的DOM元素 - 查找barRow而不是bar\r\n const barElement = document.querySelector(`[data-task-id=\"${taskId}\"]`) as HTMLElement;\r\n if (!barElement) return null;\r\n \r\n // 查找SVG bar元素获取实际位置\r\n const svgBar = barElement.querySelector('.bar') as SVGSVGElement;\r\n if (!svgBar) return null;\r\n \r\n // 获取容器 - 使用更精确的选择器\r\n const rightTableContent = barElement.closest('.table .content') as HTMLElement;\r\n if (!rightTableContent) return null;\r\n \r\n // 获取SVG的transform属性\r\n const dataX = parseFloat(svgBar.getAttribute('data-x') || '0');\r\n const barWidth = svgBar.width.baseVal.value;\r\n \r\n // 获取任务在当前容器中的位置\r\n const barRowRect = barElement.getBoundingClientRect();\r\n const containerRect = rightTableContent.getBoundingClientRect();\r\n \r\n // 计算任务相对于容器的位置\r\n const relativeY = barRowRect.top - containerRect.top;\r\n \r\n return {\r\n x: dataX,\r\n y: relativeY,\r\n width: barWidth,\r\n height: barRowRect.height,\r\n centerX: dataX + barWidth / 2,\r\n centerY: relativeY + barRowRect.height / 2,\r\n rightX: dataX + barWidth,\r\n leftX: dataX,\r\n topY: relativeY,\r\n bottomY: relativeY + barRowRect.height\r\n };\r\n };\r\n \r\n // 获取父任务的子任务索引(用于计算偏移)\r\n const getChildIndex = (parentId: string, childId: string): number => {\r\n const siblings = store.tasks.filter(task => \r\n task[store.mapFields.parentId] === parentId && \r\n task[store.mapFields.parentId] !== '0'\r\n );\r\n return siblings.findIndex(task => task[store.mapFields.id] === childId);\r\n };\r\n \r\n\r\n \r\n // 获取行高(从DOM或props中获取)\r\n const getRowHeight = (): number => {\r\n // 尝试从第一个barRow元素获取高度\r\n const firstBarRow = document.querySelector('.barRow') as HTMLElement;\r\n if (firstBarRow) {\r\n return firstBarRow.offsetHeight;\r\n }\r\n // 默认行高\r\n return 50;\r\n };\r\n \r\n // 将Y坐标对齐到最近的单元格中心线\r\n const alignToGridCenter = (y: number): number => {\r\n const rowHeight = getRowHeight();\r\n const rowIndex = Math.floor(y / rowHeight);\r\n return rowIndex * rowHeight + rowHeight / 2;\r\n };\r\n \r\n // 根据子任务索引获取对应行的中心线位置(只能向下)\r\n const getChildRowCenter = (parentY: number, childIndex: number): number => {\r\n const rowHeight = getRowHeight();\r\n // 从父任务下方开始,第一个子任务在第一行,第二个在第二行,以此类推\r\n const parentRowIndex = Math.floor(parentY / rowHeight);\r\n const targetRowIndex = parentRowIndex + 1 + childIndex;\r\n return targetRowIndex * rowHeight + rowHeight / 2;\r\n };\r\n \r\n // 确保绕行路径只能向下(不能高过父任务)\r\n const getSafeBypassY = (parentY: number, childY: number, gap: number): number => {\r\n const rowHeight = getRowHeight();\r\n const parentBottomY = Math.floor(parentY / rowHeight) * rowHeight + rowHeight;\r\n const minBypassY = parentBottomY + gap;\r\n \r\n // 如果子任务在父任务下方很远,可以选择一个中间位置\r\n if (childY > minBypassY + rowHeight) {\r\n return alignToGridCenter(minBypassY + rowHeight / 2);\r\n }\r\n \r\n return alignToGridCenter(minBypassY);\r\n };\r\n \r\n // 获取连线类型对应的颜色(从配置中读取)\r\n const getLinkTypeColor = (linkType: LinkType): string => {\r\n const colors = props.linkConfig.linkTypeColors;\r\n if (!colors) {\r\n // 默认颜色\r\n const defaultColors: Record<LinkType, string> = {\r\n [LinkType.FINISH_TO_START]: '#3498db',\r\n [LinkType.START_TO_START]: '#2ecc71',\r\n [LinkType.FINISH_TO_FINISH]: '#e74c3c',\r\n [LinkType.START_TO_FINISH]: '#f39c12',\r\n [LinkType.PARENT_CHILD]: '#95a5a6'\r\n };\r\n return defaultColors[linkType] || props.linkConfig.color;\r\n }\r\n \r\n switch (linkType) {\r\n case LinkType.FINISH_TO_START:\r\n return colors.finishToStart || '#3498db';\r\n case LinkType.START_TO_START:\r\n return colors.startToStart || '#2ecc71';\r\n case LinkType.FINISH_TO_FINISH:\r\n return colors.finishToFinish || '#e74c3c';\r\n case LinkType.START_TO_FINISH:\r\n return colors.startToFinish || '#f39c12';\r\n default:\r\n return props.linkConfig.color;\r\n }\r\n };\r\n\r\n // 获取特定连线类型的样式\r\n const getLinkStyle = (linkType: LinkType) => {\r\n if (linkType === LinkType.PARENT_CHILD) {\r\n return {\r\n color: props.linkConfig.parentChildStyle.color || '#95a5a6',\r\n width: props.linkConfig.parentChildStyle.width,\r\n dashArray: props.linkConfig.parentChildStyle.dashArray\r\n };\r\n }\r\n \r\n // 任务依赖连线使用对应类型的颜色\r\n return {\r\n color: getLinkTypeColor(linkType),\r\n width: props.linkConfig.width,\r\n dashArray: props.linkConfig.dashArray\r\n };\r\n };\r\n \r\n // 生成连线路径\r\n const generateLinkPath = (source: any, target: any, linkType: LinkType, linkId: string = ''): string => {\r\n if (!source || !target) return '';\r\n \r\n const { pathType } = props.linkConfig;\r\n \r\n switch (linkType) {\r\n case LinkType.PARENT_CHILD:\r\n return generateParentChildPath(source, target, pathType, linkId);\r\n case LinkType.FINISH_TO_START:\r\n return generateFinishToStartPath(source, target, pathType);\r\n case LinkType.START_TO_START:\r\n return generateStartToStartPath(source, target, pathType);\r\n case LinkType.FINISH_TO_FINISH:\r\n return generateFinishToFinishPath(source, target, pathType);\r\n case LinkType.START_TO_FINISH:\r\n return generateStartToFinishPath(source, target, pathType);\r\n default:\r\n return generateFinishToStartPath(source, target, pathType);\r\n }\r\n };\r\n \r\n // 父子关系连线路径(从父任务左边缘到子任务左边缘)\r\n const generateParentChildPath = (parent: any, child: any, pathType: LinkPathType, _linkId: string): string => {\r\n const parentId = parent.id || parent.taskId;\r\n const childId = child.id || child.taskId;\r\n \r\n // 获取子任务在兄弟任务中的索引\r\n const childIndex = getChildIndex(parentId, childId);\r\n \r\n // 起点:父任务左边缘中心\r\n const startX = parent.leftX;\r\n const startY = parent.centerY;\r\n \r\n // 终点:子任务左边缘减去箭头大小(连线终点在箭头底边)\r\n // 箭头尖端在 child.leftX, child.centerY,所以连线终点在箭头底边\r\n const arrowSize = props.linkConfig.arrowSize || 8;\r\n const endX = child.leftX - arrowSize;\r\n const endY = child.centerY; // 直接使用中心Y,与箭头位置一致\r\n \r\n // 根据路径类型生成不同的路径\r\n return generateParentToChildPath(startX, startY, endX, endY, childIndex, pathType);\r\n };\r\n \r\n // 生成从父任务到子任务的连线路径(支持不同路径类型)\r\n const generateParentToChildPath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n childIndex: number,\r\n pathType: LinkPathType\r\n ): string => {\r\n const deltaX = endX - startX;\r\n const deltaY = endY - startY;\r\n \r\n // 如果距离很近,直接连线\r\n if (Math.abs(deltaX) < 30 && Math.abs(deltaY) < 15) {\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n \r\n switch (pathType) {\r\n case LinkPathType.STRAIGHT:\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n \r\n case LinkPathType.BEZIER:\r\n return generateBezierPath(startX, startY, endX, endY, childIndex);\r\n \r\n case LinkPathType.RIGHT_ANGLE:\r\n default:\r\n return generateRightAnglePath(startX, startY, endX, endY, childIndex);\r\n }\r\n };\r\n // 生成贝塞尔曲线路径\r\n const generateBezierPath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n _childIndex: number\r\n ): string => {\r\n const deltaX = endX - startX;\r\n const deltaY = endY - startY;\r\n const { bezierCurvature } = props.linkConfig;\r\n \r\n // 如果子任务在父任务的右侧(正常情况)\r\n if (deltaX > 0) {\r\n // 使用简单的S曲线,直接连接起点和终点\r\n const curvature = Math.min(Math.abs(deltaX) * bezierCurvature, 60);\r\n const cp1X = startX + curvature;\r\n const cp2X = endX - curvature;\r\n return `M ${startX} ${startY} C ${cp1X} ${startY} ${cp2X} ${endY} ${endX} ${endY}`;\r\n } else {\r\n // 子任务在父任务的左侧,需要绕行\r\n const gap = props.linkConfig.rightAngleOffset;\r\n const bypassY = getSafeBypassY(startY, endY, gap);\r\n const curvature = gap * bezierCurvature;\r\n \r\n return `M ${startX} ${startY} \r\n C ${startX + curvature} ${startY} ${startX + curvature} ${bypassY} ${startX + gap/2} ${bypassY}\r\n C ${endX - curvature} ${bypassY} ${endX - curvature} ${endY} ${endX} ${endY}`;\r\n }\r\n };\r\n \r\n // 生成直角路径\r\n const generateRightAnglePath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n childIndex: number\r\n ): string => {\r\n const deltaX = endX - startX;\r\n const { rightAngleOffset, smoothCorners, cornerRadius } = props.linkConfig;\r\n \r\n // 计算该子任务应该对齐的行中心位置\r\n const targetRowCenter = getChildRowCenter(startY, childIndex);\r\n \r\n // 如果子任务在父任务的右侧(正常情况)\r\n if (deltaX > 0) {\r\n const midX = startX + rightAngleOffset;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n // 使用圆角的直角路径 - 简化为L型\r\n const r = Math.min(cornerRadius, Math.abs(endY - startY) / 2, Math.abs(endX - midX) / 2);\r\n return `M ${startX} ${startY}\r\n L ${midX - r} ${startY}\r\n Q ${midX} ${startY} ${midX} ${startY + (endY > startY ? r : -r)}\r\n L ${midX} ${endY - (endY > startY ? r : -r)}\r\n Q ${midX} ${endY} ${midX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n } else {\r\n // 标准直角路径 - 简化为L型\r\n return `M ${startX} ${startY}\r\n L ${midX} ${startY}\r\n L ${midX} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n } else {\r\n // 子任务在父任务的左侧,需要绕行\r\n const gap = rightAngleOffset;\r\n const bypassY = getSafeBypassY(startY, endY, gap);\r\n const midX1 = startX + gap/2;\r\n const midX2 = endX - gap/2;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, gap / 4);\r\n return `M ${startX} ${startY}\r\n L ${midX1 - r} ${startY}\r\n Q ${midX1} ${startY} ${midX1} ${startY + r}\r\n L ${midX1} ${bypassY - r}\r\n Q ${midX1} ${bypassY} ${midX1 + r} ${bypassY}\r\n L ${midX2 - r} ${bypassY}\r\n Q ${midX2} ${bypassY} ${midX2} ${bypassY + r}\r\n L ${midX2} ${endY - r}\r\n Q ${midX2} ${endY} ${midX2 + r} ${endY}\r\n L ${endX} ${endY}`;\r\n } else {\r\n return `M ${startX} ${startY} \r\n L ${midX1} ${startY}\r\n L ${midX1} ${bypassY}\r\n L ${midX2} ${bypassY}\r\n L ${midX2} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n }\r\n };\r\n \r\n // 完成-开始连线路径(支持不同路径类型)\r\n const generateFinishToStartPath = (source: any, target: any, pathType: LinkPathType): string => {\r\n const arrowSize = props.linkConfig.arrowSize || 8;\r\n const startX = source.rightX;\r\n const startY = source.centerY;\r\n // 终点在箭头底边位置\r\n const endX = target.leftX - arrowSize;\r\n const endY = target.centerY;\r\n \r\n return generateConnectionPath(startX, startY, endX, endY, pathType, 'horizontal');\r\n };\r\n \r\n // 开始-开始连线路径(支持不同路径类型)\r\n const generateStartToStartPath = (source: any, target: any, pathType: LinkPathType): string => {\r\n const arrowSize = props.linkConfig.arrowSize || 8;\r\n const startX = source.leftX;\r\n const startY = source.centerY;\r\n // 终点在箭头底边位置\r\n const endX = target.leftX - arrowSize;\r\n const endY = target.centerY;\r\n \r\n return generateConnectionPath(startX, startY, endX, endY, pathType, 'left-u');\r\n };\r\n \r\n // 完成-完成连线路径(支持不同路径类型)\r\n const generateFinishToFinishPath = (source: any, target: any, pathType: LinkPathType): string => {\r\n const arrowSize = props.linkConfig.arrowSize || 8;\r\n const startX = source.rightX;\r\n const startY = source.centerY;\r\n // 终点在箭头底边位置(箭头指向左边)\r\n const endX = target.rightX + arrowSize;\r\n const endY = target.centerY;\r\n \r\n return generateConnectionPath(startX, startY, endX, endY, pathType, 'right-u');\r\n };\r\n \r\n // 开始-完成连线路径(支持不同路径类型)\r\n const generateStartToFinishPath = (source: any, target: any, pathType: LinkPathType): string => {\r\n const arrowSize = props.linkConfig.arrowSize || 8;\r\n const startX = source.leftX;\r\n const startY = source.centerY;\r\n // 终点在箭头底边位置(箭头指向左边)\r\n const endX = target.rightX + arrowSize;\r\n const endY = target.centerY;\r\n \r\n return generateConnectionPath(startX, startY, endX, endY, pathType, 'cross');\r\n };\r\n \r\n // 通用连接路径生成函数\r\n const generateConnectionPath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n pathType: LinkPathType, \r\n connectionType: 'horizontal' | 'left-u' | 'right-u' | 'cross'\r\n ): string => {\r\n const { bezierCurvature, rightAngleOffset, smoothCorners, cornerRadius } = props.linkConfig;\r\n \r\n switch (pathType) {\r\n case LinkPathType.STRAIGHT:\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n \r\n case LinkPathType.BEZIER:\r\n return generateBezierConnectionPath(startX, startY, endX, endY, connectionType, bezierCurvature);\r\n \r\n case LinkPathType.RIGHT_ANGLE:\r\n default:\r\n return generateRightAngleConnectionPath(startX, startY, endX, endY, connectionType, rightAngleOffset, smoothCorners, cornerRadius);\r\n }\r\n };\r\n \r\n // 生成贝塞尔连接路径\r\n const generateBezierConnectionPath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n connectionType: string,\r\n curvature: number\r\n ): string => {\r\n const deltaX = endX - startX;\r\n const deltaY = endY - startY;\r\n \r\n switch (connectionType) {\r\n case 'horizontal':\r\n // 水平连接(完成-开始)\r\n if (deltaX > 20 && Math.abs(deltaY) < 10) {\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n \r\n if (deltaX < 20) {\r\n // 需要绕行\r\n const gap = 30;\r\n const bypassY = getSafeBypassY(startY, endY, gap);\r\n const curvatureOffset = gap * curvature;\r\n \r\n return `M ${startX} ${startY} \r\n C ${startX + curvatureOffset} ${startY} ${startX + curvatureOffset} ${bypassY} ${startX + gap/2} ${bypassY}\r\n C ${endX - curvatureOffset} ${bypassY} ${endX - curvatureOffset} ${endY} ${endX} ${endY}`;\r\n }\r\n \r\n // 标准S曲线\r\n const curvatureOffset = Math.min(Math.abs(deltaX) * curvature, 60);\r\n const cp1X = startX + curvatureOffset;\r\n const cp2X = endX - curvatureOffset;\r\n \r\n return `M ${startX} ${startY} C ${cp1X} ${startY} ${cp2X} ${endY} ${endX} ${endY}`;\r\n \r\n case 'left-u':\r\n // 左侧U型连接(开始-开始)\r\n const leftGap = 25;\r\n const leftOffsetX = Math.min(startX, endX) - leftGap;\r\n const leftCurvature = leftGap * curvature;\r\n \r\n if (Math.abs(deltaY) > getRowHeight()) {\r\n const midY = alignToGridCenter((startY + endY) / 2);\r\n return `M ${startX} ${startY} \r\n C ${startX - leftCurvature} ${startY} ${leftOffsetX} ${startY + leftCurvature} ${leftOffsetX} ${midY}\r\n C ${leftOffsetX} ${endY - leftCurvature} ${endX - leftCurvature} ${endY} ${endX} ${endY}`;\r\n }\r\n \r\n return `M ${startX} ${startY} C ${leftOffsetX} ${startY} ${leftOffsetX} ${endY} ${endX} ${endY}`;\r\n \r\n case 'right-u':\r\n // 右侧U型连接(完成-完成)\r\n const rightGap = 25;\r\n const rightOffsetX = Math.max(startX, endX) + rightGap;\r\n const rightCurvature = rightGap * curvature;\r\n \r\n if (Math.abs(deltaY) > getRowHeight()) {\r\n const midY = alignToGridCenter((startY + endY) / 2);\r\n return `M ${startX} ${startY} \r\n C ${startX + rightCurvature} ${startY} ${rightOffsetX} ${startY + rightCurvature} ${rightOffsetX} ${midY}\r\n C ${rightOffsetX} ${endY - rightCurvature} ${endX + rightCurvature} ${endY} ${endX} ${endY}`;\r\n }\r\n \r\n return `M ${startX} ${startY} C ${rightOffsetX} ${startY} ${rightOffsetX} ${endY} ${endX} ${endY}`;\r\n \r\n case 'cross':\r\n // 交叉连接(开始-完成)\r\n if (deltaX > 20 && Math.abs(deltaY) < 10) {\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n \r\n const crossCurvature = Math.min(Math.abs(deltaX) * curvature, 60);\r\n const crossCp1X = startX - crossCurvature;\r\n const crossCp2X = endX + crossCurvature;\r\n \r\n return `M ${startX} ${startY} C ${crossCp1X} ${startY} ${crossCp2X} ${endY} ${endX} ${endY}`;\r\n \r\n default:\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n };\r\n \r\n // 生成直角连接路径\r\n const generateRightAngleConnectionPath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n connectionType: string,\r\n offset: number,\r\n smoothCorners: boolean,\r\n cornerRadius: number\r\n ): string => {\r\n const deltaX = endX - startX;\r\n const deltaY = endY - startY;\r\n \r\n switch (connectionType) {\r\n case 'horizontal':\r\n // 水平连接(完成-开始)\r\n if (deltaX > 20 && Math.abs(deltaY) < 10) {\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n \r\n if (deltaX < 20) {\r\n // 需要绕行\r\n const gap = offset;\r\n const bypassY = getSafeBypassY(startY, endY, gap);\r\n const midX1 = startX + gap/2;\r\n const midX2 = endX - gap/2;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, gap / 4);\r\n return `M ${startX} ${startY}\r\n L ${midX1 - r} ${startY}\r\n Q ${midX1} ${startY} ${midX1} ${startY + r}\r\n L ${midX1} ${bypassY - r}\r\n Q ${midX1} ${bypassY} ${midX1 + r} ${bypassY}\r\n L ${midX2 - r} ${bypassY}\r\n Q ${midX2} ${bypassY} ${midX2} ${bypassY + r}\r\n L ${midX2} ${endY - r}\r\n Q ${midX2} ${endY} ${midX2 + r} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n \r\n return `M ${startX} ${startY} \r\n L ${midX1} ${startY}\r\n L ${midX1} ${bypassY}\r\n L ${midX2} ${bypassY}\r\n L ${midX2} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n \r\n // 标准L型路径\r\n const midX = startX + Math.abs(deltaX) / 2;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, Math.abs(deltaX) / 4, Math.abs(deltaY) / 2);\r\n if (deltaY > 0) {\r\n return `M ${startX} ${startY}\r\n L ${midX - r} ${startY}\r\n Q ${midX} ${startY} ${midX} ${startY + r}\r\n L ${midX} ${endY - r}\r\n Q ${midX} ${endY} ${midX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n } else {\r\n return `M ${startX} ${startY}\r\n L ${midX - r} ${startY}\r\n Q ${midX} ${startY} ${midX} ${startY - r}\r\n L ${midX} ${endY + r}\r\n Q ${midX} ${endY} ${midX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n }\r\n \r\n return `M ${startX} ${startY} L ${midX} ${startY} L ${midX} ${endY} L ${endX} ${endY}`;\r\n \r\n case 'left-u':\r\n // 左侧U型连接(开始-开始)\r\n const leftGap = offset;\r\n const leftOffsetX = Math.min(startX, endX) - leftGap;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, leftGap / 2, Math.abs(deltaY) / 4);\r\n return `M ${startX} ${startY}\r\n L ${leftOffsetX + r} ${startY}\r\n Q ${leftOffsetX} ${startY} ${leftOffsetX} ${startY + (deltaY > 0 ? r : -r)}\r\n L ${leftOffsetX} ${endY - (deltaY > 0 ? r : -r)}\r\n Q ${leftOffsetX} ${endY} ${leftOffsetX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n \r\n return `M ${startX} ${startY} L ${leftOffsetX} ${startY} L ${leftOffsetX} ${endY} L ${endX} ${endY}`;\r\n \r\n case 'right-u':\r\n // 右侧U型连接(完成-完成)\r\n const rightGap = offset;\r\n const rightOffsetX = Math.max(startX, endX) + rightGap;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, rightGap / 2, Math.abs(deltaY) / 4);\r\n return `M ${startX} ${startY}\r\n L ${rightOffsetX - r} ${startY}\r\n Q ${rightOffsetX} ${startY} ${rightOffsetX} ${startY + (deltaY > 0 ? r : -r)}\r\n L ${rightOffsetX} ${endY - (deltaY > 0 ? r : -r)}\r\n Q ${rightOffsetX} ${endY} ${rightOffsetX - r} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n \r\n return `M ${startX} ${startY} L ${rightOffsetX} ${startY} L ${rightOffsetX} ${endY} L ${endX} ${endY}`;\r\n \r\n case 'cross':\r\n // 交叉连接(开始-完成)\r\n if (deltaX > 20 && Math.abs(deltaY) < 10) {\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n \r\n const crossMidX = startX + deltaX / 2;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, Math.abs(deltaX) / 4, Math.abs(deltaY) / 2);\r\n if (deltaY > 0) {\r\n return `M ${startX} ${startY}\r\n L ${crossMidX - r} ${startY}\r\n Q ${crossMidX} ${startY} ${crossMidX} ${startY + r}\r\n L ${crossMidX} ${endY - r}\r\n Q ${crossMidX} ${endY} ${crossMidX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n } else {\r\n return `M ${startX} ${startY}\r\n L ${crossMidX - r} ${startY}\r\n Q ${crossMidX} ${startY} ${crossMidX} ${startY - r}\r\n L ${crossMidX} ${endY + r}\r\n Q ${crossMidX} ${endY} ${crossMidX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n }\r\n \r\n return `M ${startX} ${startY} L ${crossMidX} ${startY} L ${crossMidX} ${endY} L ${endX} ${endY}`;\r\n \r\n default:\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n };\r\n \r\n // 生成箭头点(直接从子任务位置计算)- 用于父子关系连线\r\n const generateArrowPoints = (childPos: any, arrowSize: number, _linkType: LinkType = LinkType.FINISH_TO_START): string => {\r\n if (!childPos) {\r\n console.warn('子任务位置无效');\r\n return '';\r\n }\r\n \r\n try {\r\n // 箭头尖端:子任务左边缘中心\r\n const tipX = childPos.leftX;\r\n const tipY = childPos.centerY;\r\n \r\n // 父子关系连线:箭头指向右边(指向子任务)\r\n // 箭头底边的两个点\r\n const baseX = tipX - arrowSize;\r\n const baseY1 = tipY - arrowSize / 2;\r\n const baseY2 = tipY + arrowSize / 2;\r\n \r\n const result = `${tipX},${tipY} ${baseX},${baseY1} ${baseX},${baseY2}`;\r\n return result;\r\n } catch (e) {\r\n console.error('箭头生成失败:', e);\r\n return '';\r\n }\r\n };\r\n \r\n // 生成依赖连线的箭头点\r\n const generateDependencyArrowPoints = (\r\n sourcePos: any, \r\n targetPos: any, \r\n linkType: LinkType, \r\n arrowSize: number\r\n ): string => {\r\n if (!sourcePos || !targetPos) return '';\r\n \r\n try {\r\n let endX: number, endY: number;\r\n let direction: 'left' | 'right' | 'up' | 'down' = 'right';\r\n \r\n switch (linkType) {\r\n case LinkType.FINISH_TO_START:\r\n // 箭头指向目标任务的左边缘\r\n endX = targetPos.leftX;\r\n endY = targetPos.centerY;\r\n direction = 'right';\r\n break;\r\n \r\n case LinkType.START_TO_START:\r\n // 箭头指向目标任务的左边缘\r\n endX = targetPos.leftX;\r\n endY = targetPos.centerY;\r\n direction = 'right';\r\n break;\r\n \r\n case LinkType.FINISH_TO_FINISH:\r\n // 箭头指向目标任务的右边缘\r\n endX = targetPos.rightX;\r\n endY = targetPos.centerY;\r\n direction = 'left';\r\n break;\r\n \r\n case LinkType.START_TO_FINISH:\r\n // 箭头指向目标任务的右边缘\r\n endX = targetPos.rightX;\r\n endY = targetPos.centerY;\r\n direction = 'left';\r\n break;\r\n \r\n default:\r\n endX = targetPos.leftX;\r\n endY = targetPos.centerY;\r\n direction = 'right';\r\n }\r\n \r\n // 根据方向生成箭头\r\n let arrowPoint1X: number, arrowPoint1Y: number;\r\n let arrowPoint2X: number, arrowPoint2Y: number;\r\n \r\n if (direction === 'right') {\r\n // 箭头指向右边\r\n arrowPoint1X = endX - arrowSize;\r\n arrowPoint1Y = endY - arrowSize / 2;\r\n arrowPoint2X = endX - arrowSize;\r\n arrowPoint2Y = endY + arrowSize / 2;\r\n } else {\r\n // 箭头指向左边\r\n arrowPoint1X = endX + arrowSize;\r\n arrowPoint1Y = endY - arrowSize / 2;\r\n arrowPoint2X = endX + arrowSize;\r\n arrowPoint2Y = endY + arrowSize / 2;\r\n }\r\n \r\n return `${endX},${endY} ${arrowPoint1X},${arrowPoint1Y} ${arrowPoint2X},${arrowPoint2Y}`;\r\n } catch (e) {\r\n console.error('依赖箭头生成失败:', e);\r\n return '';\r\n }\r\n };\r\n \r\n // 更新连线\r\n // 获取所有被折叠的子任务ID集合(递归)\r\n const getAllCollapsedChildren = (parentId: any): Set<any> => {\r\n const collapsedChildren = new Set<any>();\r\n \r\n const collectChildren = (pid: any) => {\r\n const children = store.tasks.filter(task => task[store.mapFields.parentId] === pid);\r\n children.forEach(child => {\r\n const childId = child[store.mapFields.id];\r\n collapsedChildren.add(childId);\r\n // 递归收集所有子孙任务\r\n collectChildren(childId);\r\n });\r\n };\r\n \r\n collectChildren(parentId);\r\n return collapsedChildren;\r\n };\r\n \r\n // 检查任务是否被折叠(任务本身或其任何祖先被折叠)\r\n const isTaskCollapsed = (taskId: any): boolean => {\r\n // 检查所有已折叠的任务\r\n for (const collapsedId of store.collapsedTasks) {\r\n const collapsedChildren = getAllCollapsedChildren(collapsedId);\r\n if (collapsedChildren.has(taskId)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n };\r\n \r\n const updateLinks = () => {\r\n console.log('updateLinks called');\r\n const newLinks: TaskLink[] = [];\r\n \r\n // 获取连线类型显示配置\r\n const visibility = props.linkConfig.linkTypeVisibility || {\r\n finishToStart: true,\r\n startToStart: true,\r\n finishToFinish: true,\r\n startToFinish: true,\r\n parentChild: true\r\n };\r\n \r\n // 生成父子关系连线(根据 visibility 控制)\r\n if (visibility.parentChild) {\r\n store.tasks.forEach(task => {\r\n const parentId = task[store.mapFields.parentId];\r\n const childId = task[store.mapFields.id];\r\n \r\n if (parentId && parentId !== '0') {\r\n // 检查子任务是否被折叠,如果被折叠则不显示连线\r\n if (isTaskCollapsed(childId)) {\r\n return; // 跳过该连线\r\n }\r\n \r\n const parentPos = getTaskPosition(parentId);\r\n const childPos = getTaskPosition(childId);\r\n \r\n if (parentPos && childPos) {\r\n const linkId = `parent-child-${parentId}-${childId}`;\r\n \r\n // 为位置信息添加任务ID\r\n const parentPosWithId = { ...parentPos, id: parentId, taskId: parentId };\r\n const childPosWithId = { ...childPos, id: childId, taskId: childId };\r\n \r\n const path = generateLinkPath(parentPosWithId, childPosWithId, LinkType.PARENT_CHILD, linkId);\r\n const arrowPoints = props.linkConfig.showArrow ? \r\n generateArrowPoints(childPos, props.linkConfig.arrowSize, LinkType.PARENT_CHILD) : '';\r\n \r\n newLinks.push({\r\n id: linkId,\r\n sourceId: parentId,\r\n targetId: childId,\r\n type: LinkType.PARENT_CHILD,\r\n path,\r\n arrowPoints,\r\n labelX: childPos.centerX,\r\n labelY: childPos.centerY - 10\r\n });\r\n }\r\n }\r\n });\r\n }\r\n \r\n // 生成任务依赖连线\r\n const dependencies = linkDataManager.getDependencies();\r\n console.log('Dependencies:', dependencies);\r\n \r\n // 根据连线类型检查是否显示\r\n const shouldShowLinkType = (linkType: LinkType): boolean => {\r\n switch (linkType) {\r\n case LinkType.FINISH_TO_START:\r\n return visibility.finishToStart;\r\n case LinkType.START_TO_START:\r\n return visibility.startToStart;\r\n case LinkType.FINISH_TO_FINISH:\r\n return visibility.finishToFinish;\r\n case LinkType.START_TO_FINISH:\r\n return visibility.startToFinish;\r\n case LinkType.PARENT_CHILD:\r\n return visibility.parentChild;\r\n default:\r\n return true;\r\n }\r\n };\r\n \r\n dependencies.forEach(dep => {\r\n // 根据 visibility 过滤连线类型\r\n if (!shouldShowLinkType(dep.type)) {\r\n return;\r\n }\r\n \r\n const sourcePos = getTaskPosition(dep.sourceTaskId);\r\n const targetPos = getTaskPosition(dep.targetTaskId);\r\n \r\n if (sourcePos && targetPos) {\r\n const linkId = `dependency-${dep.id}`;\r\n \r\n // 为位置信息添加任务ID\r\n const sourcePosWithId = { ...sourcePos, id: dep.sourceTaskId, taskId: dep.sourceTaskId };\r\n const targetPosWithId = { ...targetPos, id: dep.targetTaskId, taskId: dep.targetTaskId };\r\n \r\n const path = generateLinkPath(sourcePosWithId, targetPosWithId, dep.type, linkId);\r\n \r\n // 根据连线类型生成箭头\r\n const arrowPoints = props.linkConfig.showArrow ? \r\n generateDependencyArrowPoints(sourcePosWithId, targetPosWithId, dep.type, props.linkConfig.arrowSize) : '';\r\n \r\n // 获取连线类型的标签\r\n const labelMap: Record<LinkType, string> = {\r\n [LinkType.FINISH_TO_START]: 'FS',\r\n [LinkType.START_TO_START]: 'SS',\r\n [LinkType.FINISH_TO_FINISH]: 'FF',\r\n [LinkType.START_TO_FINISH]: 'SF',\r\n [LinkType.PARENT_CHILD]: ''\r\n };\r\n \r\n newLinks.push({\r\n id: linkId,\r\n sourceId: dep.sourceTaskId,\r\n targetId: dep.targetTaskId,\r\n type: dep.type,\r\n path,\r\n arrowPoints,\r\n label: labelMap[dep.type] || '',\r\n labelX: (sourcePos.centerX + targetPos.centerX) / 2,\r\n labelY: (sourcePos.centerY + targetPos.centerY) / 2 - 10\r\n });\r\n }\r\n });\r\n \r\n links.value = newLinks;\r\n };\r\n \r\n // 监听任务变化\r\n watch(() => store.tasks, () => {\r\n // 延迟更新,确保DOM已更新\r\n setTimeout(updateLinks, 50);\r\n }, { deep: true });\r\n \r\n watch(() => store.scale, () => {\r\n setTimeout(updateLinks, 50);\r\n });\r\n \r\n // 监听模式变化(月、日、时切换)\r\n watch(() => store.mode, () => {\r\n // 模式切换时需要重新计算bar位置,延迟更新确保bar重绘完成\r\n setTimeout(updateLinks, 200);\r\n });\r\n \r\n // 监听时间轴变化\r\n watch(() => store.timelineCellCount, () => {\r\n setTimeout(updateLinks, 100);\r\n });\r\n \r\n // 监听甘特图日期范围变化\r\n watch(() => [store.startGanttDate, store.endGanttDate], () => {\r\n setTimeout(updateLinks, 100);\r\n });\r\n \r\n // 监听barDate变化(拖拽和调整大小时会触发)\r\n watch(() => store.barDate, () => {\r\n requestAnimationFrame(updateLinks);\r\n }, { deep: true });\r\n \r\n // 监听连线类型显示配置变化\r\n watch(() => props.linkConfig.linkTypeVisibility, () => {\r\n setTimeout(updateLinks, 50);\r\n }, { deep: true });\r\n \r\n // 监听折叠状态变化\r\n watch(() => store.collapsedTasks, () => {\r\n setTimeout(updateLinks, 50);\r\n }, { deep: true });\r\n \r\n // 监听DOM变化(拖拽时重绘)\r\n let resizeObserver: ResizeObserver | null = null;\r\n let mutationObserver: MutationObserver | null = null;\r\n \r\n onMounted(() => {\r\n // 初始更新\r\n setTimeout(updateLinks, 100);\r\n \r\n // 监听容器大小变化\r\n const container = document.querySelector('.gantt');\r\n if (container) {\r\n resizeObserver = new ResizeObserver(updateLinks);\r\n resizeObserver.observe(container);\r\n \r\n\r\n \r\n // 监听DOM变化(任务条位置变化)\r\n mutationObserver = new MutationObserver((mutations) => {\r\n let shouldUpdate = false;\r\n mutations.forEach(mutation => {\r\n const target = mutation.target as HTMLElement;\r\n // 检查是否是SVG bar元素或其父元素\r\n if (mutation.type === 'attributes') {\r\n const attrName = mutation.attributeName;\r\n if (attrName === 'data-x' || \r\n attrName === 'width' || \r\n attrName === 'style' ||\r\n attrName === 'transform') {\r\n // 检查是否是bar元素\r\n if (target.classList?.contains('bar') || \r\n target.classList?.contains('barRow') ||\r\n target.tagName === 'svg') {\r\n shouldUpdate = true;\r\n }\r\n }\r\n }\r\n });\r\n if (shouldUpdate) {\r\n requestAnimationFrame(updateLinks);\r\n }\r\n });\r\n \r\n mutationObserver.observe(container, {\r\n attributes: true,\r\n subtree: true,\r\n attributeFilter: ['style', 'data-x', 'transform', 'width']\r\n });\r\n }\r\n });\r\n \r\n onUnmounted(() => {\r\n if (resizeObserver) {\r\n resizeObserver.disconnect();\r\n }\r\n if (mutationObserver) {\r\n mutationObserver.disconnect();\r\n }\r\n });\r\n \r\n // 虚线动画相关方法\r\n \r\n // 判断是否为虚线\r\n const isDashedLine = (linkType: LinkType): boolean => {\r\n const style = getLinkStyle(linkType);\r\n return !!(style.dashArray && style.dashArray.length > 0);\r\n };\r\n \r\n // 获取虚线流动动画样式\r\n const getDashAnimationStyle = (link: TaskLink) => {\r\n if (!isDashedLine(link.type) || !props.linkConfig.enableDashAnimation) {\r\n return {};\r\n }\r\n \r\n const style = getLinkStyle(link.type);\r\n const speed = props.linkConfig.dashAnimationSpeed || 0.8; // 更快的默认速度\r\n \r\n // 父子关系连线稍快一些\r\n const adjustedSpeed = link.type === LinkType.PARENT_CHILD ? speed * 0.6 : speed;\r\n \r\n // 计算虚线总长度用于动画\r\n const dashArray = style.dashArray || '5,5';\r\n const dashParts = dashArray.split(',').map(Number);\r\n const dashLength = dashParts.reduce((sum, part) => sum + part, 0);\r\n \r\n return {\r\n '--animation-duration': `${adjustedSpeed}s`,\r\n '--dash-length': `${dashLength}px`\r\n };\r\n };\r\n \r\n return {\r\n links,\r\n updateLinks,\r\n getLinkStyle,\r\n isDashedLine,\r\n getDashAnimationStyle\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.task-links-layer {\r\n pointer-events: none;\r\n \r\n .task-link {\r\n transition: stroke-width 0.2s ease;\r\n \r\n &:hover {\r\n stroke-width: 3;\r\n }\r\n \r\n &.parent-child {\r\n opacity: 0.7;\r\n }\r\n \r\n &.finish-to-start {\r\n opacity: 0.9;\r\n }\r\n \r\n // 虚线流动动画\r\n &.dash-animated {\r\n animation: dashFlow var(--animation-duration, 3s) linear infinite;\r\n }\r\n }\r\n \r\n // 虚线流动动画关键帧\r\n @keyframes dashFlow {\r\n 0% {\r\n stroke-dashoffset: 0;\r\n }\r\n 100% {\r\n stroke-dashoffset: calc(-1 * var(--dash-length, 20px));\r\n }\r\n }\r\n \r\n .task-link-arrow {\r\n transition: fill 0.2s ease;\r\n opacity: 1;\r\n pointer-events: none;\r\n }\r\n \r\n .task-link-label {\r\n font-family: Arial, sans-serif;\r\n user-select: none;\r\n }\r\n}\r\n</style>","<template>\r\n <svg \r\n class=\"task-links-layer\" \r\n :width=\"containerWidth\" \r\n :height=\"containerHeight\"\r\n :style=\"{ \r\n position: 'absolute', \r\n top: '0px', \r\n left: '0px', \r\n pointerEvents: 'none',\r\n zIndex: 50,\r\n overflow: 'visible'\r\n }\"\r\n >\r\n <!-- 渲染所有连线 -->\r\n <g v-for=\"link in links\" :key=\"link.id\">\r\n <!-- 连线路径 -->\r\n <path\r\n :d=\"link.path\"\r\n :stroke=\"getLinkStyle(link.type).color\"\r\n :stroke-width=\"getLinkStyle(link.type).width\"\r\n :stroke-dasharray=\"getLinkStyle(link.type).dashArray\"\r\n fill=\"none\"\r\n :class=\"['task-link', link.type, { \r\n 'dash-animated': isDashedLine(link.type) && linkConfig.enableDashAnimation \r\n }]\"\r\n :style=\"getDashAnimationStyle(link)\"\r\n />\r\n \r\n <!-- 箭头 -->\r\n <polygon\r\n v-if=\"linkConfig.showArrow && link.arrowPoints && link.arrowPoints.length > 0\"\r\n :points=\"link.arrowPoints\"\r\n :fill=\"getLinkStyle(link.type).color\"\r\n :stroke=\"getLinkStyle(link.type).color\"\r\n :stroke-width=\"0.5\"\r\n class=\"task-link-arrow\"\r\n />\r\n \r\n <!-- 连线标签(可选) -->\r\n <text\r\n v-if=\"link.label && linkConfig.showLabels\"\r\n :x=\"link.labelX\"\r\n :y=\"link.labelY\"\r\n :fill=\"linkConfig.labelColor\"\r\n :font-size=\"linkConfig.labelFontSize\"\r\n text-anchor=\"middle\"\r\n class=\"task-link-label\"\r\n >\r\n {{ link.label }}\r\n </text>\r\n </g>\r\n </svg>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, watch, ref, onMounted, onUnmounted } from 'vue';\r\nimport { store } from './Store';\r\nimport { LinkType, LinkPathType, type LinkConfig, type TaskLink } from './Types';\r\nimport { linkDataManager } from './LinkConfig';\r\n\r\n\r\n\r\nexport default defineComponent({\r\n name: 'TaskLinks',\r\n props: {\r\n containerWidth: {\r\n type: Number,\r\n required: true\r\n },\r\n containerHeight: {\r\n type: Number,\r\n required: true\r\n },\r\n linkConfig: {\r\n type: Object as () => LinkConfig,\r\n default: () => ({\r\n color: '#3498db',\r\n width: 2,\r\n dashArray: undefined,\r\n showArrow: true,\r\n arrowColor: undefined,\r\n arrowSize: 8,\r\n showLabels: false,\r\n labelColor: '#666',\r\n labelFontSize: 12,\r\n cornerRadius: 5,\r\n pathType: LinkPathType.BEZIER,\r\n bezierCurvature: 0.4,\r\n rightAngleOffset: 30,\r\n smoothCorners: true,\r\n enableDashAnimation: true,\r\n dashAnimationSpeed: 0.8,\r\n parentChildStyle: {\r\n color: '#95a5a6',\r\n width: 1,\r\n dashArray: '3,3'\r\n }\r\n })\r\n }\r\n },\r\n setup(props) {\r\n const links = ref<TaskLink[]>([]);\r\n \r\n // 获取任务位置信息\r\n const getTaskPosition = (taskId: string) => {\r\n const task = store.tasks.find(t => t[store.mapFields.id] === taskId);\r\n if (!task) return null;\r\n \r\n // 查找对应的DOM元素 - 查找barRow而不是bar\r\n const barElement = document.querySelector(`[data-task-id=\"${taskId}\"]`) as HTMLElement;\r\n if (!barElement) return null;\r\n \r\n // 查找SVG bar元素获取实际位置\r\n const svgBar = barElement.querySelector('.bar') as SVGSVGElement;\r\n if (!svgBar) return null;\r\n \r\n // 获取容器 - 使用更精确的选择器\r\n const rightTableContent = barElement.closest('.table .content') as HTMLElement;\r\n if (!rightTableContent) return null;\r\n \r\n // 获取SVG的transform属性\r\n const dataX = parseFloat(svgBar.getAttribute('data-x') || '0');\r\n const barWidth = svgBar.width.baseVal.value;\r\n \r\n // 获取任务在当前容器中的位置\r\n const barRowRect = barElement.getBoundingClientRect();\r\n const containerRect = rightTableContent.getBoundingClientRect();\r\n \r\n // 计算任务相对于容器的位置\r\n const relativeY = barRowRect.top - containerRect.top;\r\n \r\n return {\r\n x: dataX,\r\n y: relativeY,\r\n width: barWidth,\r\n height: barRowRect.height,\r\n centerX: dataX + barWidth / 2,\r\n centerY: relativeY + barRowRect.height / 2,\r\n rightX: dataX + barWidth,\r\n leftX: dataX,\r\n topY: relativeY,\r\n bottomY: relativeY + barRowRect.height\r\n };\r\n };\r\n \r\n // 获取父任务的子任务索引(用于计算偏移)\r\n const getChildIndex = (parentId: string, childId: string): number => {\r\n const siblings = store.tasks.filter(task => \r\n task[store.mapFields.parentId] === parentId && \r\n task[store.mapFields.parentId] !== '0'\r\n );\r\n return siblings.findIndex(task => task[store.mapFields.id] === childId);\r\n };\r\n \r\n\r\n \r\n // 获取行高(从DOM或props中获取)\r\n const getRowHeight = (): number => {\r\n // 尝试从第一个barRow元素获取高度\r\n const firstBarRow = document.querySelector('.barRow') as HTMLElement;\r\n if (firstBarRow) {\r\n return firstBarRow.offsetHeight;\r\n }\r\n // 默认行高\r\n return 50;\r\n };\r\n \r\n // 将Y坐标对齐到最近的单元格中心线\r\n const alignToGridCenter = (y: number): number => {\r\n const rowHeight = getRowHeight();\r\n const rowIndex = Math.floor(y / rowHeight);\r\n return rowIndex * rowHeight + rowHeight / 2;\r\n };\r\n \r\n // 根据子任务索引获取对应行的中心线位置(只能向下)\r\n const getChildRowCenter = (parentY: number, childIndex: number): number => {\r\n const rowHeight = getRowHeight();\r\n // 从父任务下方开始,第一个子任务在第一行,第二个在第二行,以此类推\r\n const parentRowIndex = Math.floor(parentY / rowHeight);\r\n const targetRowIndex = parentRowIndex + 1 + childIndex;\r\n return targetRowIndex * rowHeight + rowHeight / 2;\r\n };\r\n \r\n // 确保绕行路径只能向下(不能高过父任务)\r\n const getSafeBypassY = (parentY: number, childY: number, gap: number): number => {\r\n const rowHeight = getRowHeight();\r\n const parentBottomY = Math.floor(parentY / rowHeight) * rowHeight + rowHeight;\r\n const minBypassY = parentBottomY + gap;\r\n \r\n // 如果子任务在父任务下方很远,可以选择一个中间位置\r\n if (childY > minBypassY + rowHeight) {\r\n return alignToGridCenter(minBypassY + rowHeight / 2);\r\n }\r\n \r\n return alignToGridCenter(minBypassY);\r\n };\r\n \r\n // 获取连线类型对应的颜色(从配置中读取)\r\n const getLinkTypeColor = (linkType: LinkType): string => {\r\n const colors = props.linkConfig.linkTypeColors;\r\n if (!colors) {\r\n // 默认颜色\r\n const defaultColors: Record<LinkType, string> = {\r\n [LinkType.FINISH_TO_START]: '#3498db',\r\n [LinkType.START_TO_START]: '#2ecc71',\r\n [LinkType.FINISH_TO_FINISH]: '#e74c3c',\r\n [LinkType.START_TO_FINISH]: '#f39c12',\r\n [LinkType.PARENT_CHILD]: '#95a5a6'\r\n };\r\n return defaultColors[linkType] || props.linkConfig.color;\r\n }\r\n \r\n switch (linkType) {\r\n case LinkType.FINISH_TO_START:\r\n return colors.finishToStart || '#3498db';\r\n case LinkType.START_TO_START:\r\n return colors.startToStart || '#2ecc71';\r\n case LinkType.FINISH_TO_FINISH:\r\n return colors.finishToFinish || '#e74c3c';\r\n case LinkType.START_TO_FINISH:\r\n return colors.startToFinish || '#f39c12';\r\n default:\r\n return props.linkConfig.color;\r\n }\r\n };\r\n\r\n // 获取特定连线类型的样式\r\n const getLinkStyle = (linkType: LinkType) => {\r\n if (linkType === LinkType.PARENT_CHILD) {\r\n return {\r\n color: props.linkConfig.parentChildStyle.color || '#95a5a6',\r\n width: props.linkConfig.parentChildStyle.width,\r\n dashArray: props.linkConfig.parentChildStyle.dashArray\r\n };\r\n }\r\n \r\n // 任务依赖连线使用对应类型的颜色\r\n return {\r\n color: getLinkTypeColor(linkType),\r\n width: props.linkConfig.width,\r\n dashArray: props.linkConfig.dashArray\r\n };\r\n };\r\n \r\n // 生成连线路径\r\n const generateLinkPath = (source: any, target: any, linkType: LinkType, linkId: string = ''): string => {\r\n if (!source || !target) return '';\r\n \r\n const { pathType } = props.linkConfig;\r\n \r\n switch (linkType) {\r\n case LinkType.PARENT_CHILD:\r\n return generateParentChildPath(source, target, pathType, linkId);\r\n case LinkType.FINISH_TO_START:\r\n return generateFinishToStartPath(source, target, pathType);\r\n case LinkType.START_TO_START:\r\n return generateStartToStartPath(source, target, pathType);\r\n case LinkType.FINISH_TO_FINISH:\r\n return generateFinishToFinishPath(source, target, pathType);\r\n case LinkType.START_TO_FINISH:\r\n return generateStartToFinishPath(source, target, pathType);\r\n default:\r\n return generateFinishToStartPath(source, target, pathType);\r\n }\r\n };\r\n \r\n // 父子关系连线路径(从父任务左边缘到子任务左边缘)\r\n const generateParentChildPath = (parent: any, child: any, pathType: LinkPathType, _linkId: string): string => {\r\n const parentId = parent.id || parent.taskId;\r\n const childId = child.id || child.taskId;\r\n \r\n // 获取子任务在兄弟任务中的索引\r\n const childIndex = getChildIndex(parentId, childId);\r\n \r\n // 起点:父任务左边缘中心\r\n const startX = parent.leftX;\r\n const startY = parent.centerY;\r\n \r\n // 终点:子任务左边缘减去箭头大小(连线终点在箭头底边)\r\n // 箭头尖端在 child.leftX, child.centerY,所以连线终点在箭头底边\r\n const arrowSize = props.linkConfig.arrowSize || 8;\r\n const endX = child.leftX - arrowSize;\r\n const endY = child.centerY; // 直接使用中心Y,与箭头位置一致\r\n \r\n // 根据路径类型生成不同的路径\r\n return generateParentToChildPath(startX, startY, endX, endY, childIndex, pathType);\r\n };\r\n \r\n // 生成从父任务到子任务的连线路径(支持不同路径类型)\r\n const generateParentToChildPath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n childIndex: number,\r\n pathType: LinkPathType\r\n ): string => {\r\n const deltaX = endX - startX;\r\n const deltaY = endY - startY;\r\n \r\n // 如果距离很近,直接连线\r\n if (Math.abs(deltaX) < 30 && Math.abs(deltaY) < 15) {\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n \r\n switch (pathType) {\r\n case LinkPathType.STRAIGHT:\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n \r\n case LinkPathType.BEZIER:\r\n return generateBezierPath(startX, startY, endX, endY, childIndex);\r\n \r\n case LinkPathType.RIGHT_ANGLE:\r\n default:\r\n return generateRightAnglePath(startX, startY, endX, endY, childIndex);\r\n }\r\n };\r\n // 生成贝塞尔曲线路径\r\n const generateBezierPath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n _childIndex: number\r\n ): string => {\r\n const deltaX = endX - startX;\r\n const deltaY = endY - startY;\r\n const { bezierCurvature } = props.linkConfig;\r\n \r\n // 如果子任务在父任务的右侧(正常情况)\r\n if (deltaX > 0) {\r\n // 使用简单的S曲线,直接连接起点和终点\r\n const curvature = Math.min(Math.abs(deltaX) * bezierCurvature, 60);\r\n const cp1X = startX + curvature;\r\n const cp2X = endX - curvature;\r\n return `M ${startX} ${startY} C ${cp1X} ${startY} ${cp2X} ${endY} ${endX} ${endY}`;\r\n } else {\r\n // 子任务在父任务的左侧,需要绕行\r\n const gap = props.linkConfig.rightAngleOffset;\r\n const bypassY = getSafeBypassY(startY, endY, gap);\r\n const curvature = gap * bezierCurvature;\r\n \r\n return `M ${startX} ${startY} \r\n C ${startX + curvature} ${startY} ${startX + curvature} ${bypassY} ${startX + gap/2} ${bypassY}\r\n C ${endX - curvature} ${bypassY} ${endX - curvature} ${endY} ${endX} ${endY}`;\r\n }\r\n };\r\n \r\n // 生成直角路径\r\n const generateRightAnglePath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n childIndex: number\r\n ): string => {\r\n const deltaX = endX - startX;\r\n const { rightAngleOffset, smoothCorners, cornerRadius } = props.linkConfig;\r\n \r\n // 计算该子任务应该对齐的行中心位置\r\n const targetRowCenter = getChildRowCenter(startY, childIndex);\r\n \r\n // 如果子任务在父任务的右侧(正常情况)\r\n if (deltaX > 0) {\r\n const midX = startX + rightAngleOffset;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n // 使用圆角的直角路径 - 简化为L型\r\n const r = Math.min(cornerRadius, Math.abs(endY - startY) / 2, Math.abs(endX - midX) / 2);\r\n return `M ${startX} ${startY}\r\n L ${midX - r} ${startY}\r\n Q ${midX} ${startY} ${midX} ${startY + (endY > startY ? r : -r)}\r\n L ${midX} ${endY - (endY > startY ? r : -r)}\r\n Q ${midX} ${endY} ${midX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n } else {\r\n // 标准直角路径 - 简化为L型\r\n return `M ${startX} ${startY}\r\n L ${midX} ${startY}\r\n L ${midX} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n } else {\r\n // 子任务在父任务的左侧,需要绕行\r\n const gap = rightAngleOffset;\r\n const bypassY = getSafeBypassY(startY, endY, gap);\r\n const midX1 = startX + gap/2;\r\n const midX2 = endX - gap/2;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, gap / 4);\r\n return `M ${startX} ${startY}\r\n L ${midX1 - r} ${startY}\r\n Q ${midX1} ${startY} ${midX1} ${startY + r}\r\n L ${midX1} ${bypassY - r}\r\n Q ${midX1} ${bypassY} ${midX1 + r} ${bypassY}\r\n L ${midX2 - r} ${bypassY}\r\n Q ${midX2} ${bypassY} ${midX2} ${bypassY + r}\r\n L ${midX2} ${endY - r}\r\n Q ${midX2} ${endY} ${midX2 + r} ${endY}\r\n L ${endX} ${endY}`;\r\n } else {\r\n return `M ${startX} ${startY} \r\n L ${midX1} ${startY}\r\n L ${midX1} ${bypassY}\r\n L ${midX2} ${bypassY}\r\n L ${midX2} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n }\r\n };\r\n \r\n // 完成-开始连线路径(支持不同路径类型)\r\n const generateFinishToStartPath = (source: any, target: any, pathType: LinkPathType): string => {\r\n const arrowSize = props.linkConfig.arrowSize || 8;\r\n const startX = source.rightX;\r\n const startY = source.centerY;\r\n // 终点在箭头底边位置\r\n const endX = target.leftX - arrowSize;\r\n const endY = target.centerY;\r\n \r\n return generateConnectionPath(startX, startY, endX, endY, pathType, 'horizontal');\r\n };\r\n \r\n // 开始-开始连线路径(支持不同路径类型)\r\n const generateStartToStartPath = (source: any, target: any, pathType: LinkPathType): string => {\r\n const arrowSize = props.linkConfig.arrowSize || 8;\r\n const startX = source.leftX;\r\n const startY = source.centerY;\r\n // 终点在箭头底边位置\r\n const endX = target.leftX - arrowSize;\r\n const endY = target.centerY;\r\n \r\n return generateConnectionPath(startX, startY, endX, endY, pathType, 'left-u');\r\n };\r\n \r\n // 完成-完成连线路径(支持不同路径类型)\r\n const generateFinishToFinishPath = (source: any, target: any, pathType: LinkPathType): string => {\r\n const arrowSize = props.linkConfig.arrowSize || 8;\r\n const startX = source.rightX;\r\n const startY = source.centerY;\r\n // 终点在箭头底边位置(箭头指向左边)\r\n const endX = target.rightX + arrowSize;\r\n const endY = target.centerY;\r\n \r\n return generateConnectionPath(startX, startY, endX, endY, pathType, 'right-u');\r\n };\r\n \r\n // 开始-完成连线路径(支持不同路径类型)\r\n const generateStartToFinishPath = (source: any, target: any, pathType: LinkPathType): string => {\r\n const arrowSize = props.linkConfig.arrowSize || 8;\r\n const startX = source.leftX;\r\n const startY = source.centerY;\r\n // 终点在箭头底边位置(箭头指向左边)\r\n const endX = target.rightX + arrowSize;\r\n const endY = target.centerY;\r\n \r\n return generateConnectionPath(startX, startY, endX, endY, pathType, 'cross');\r\n };\r\n \r\n // 通用连接路径生成函数\r\n const generateConnectionPath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n pathType: LinkPathType, \r\n connectionType: 'horizontal' | 'left-u' | 'right-u' | 'cross'\r\n ): string => {\r\n const { bezierCurvature, rightAngleOffset, smoothCorners, cornerRadius } = props.linkConfig;\r\n \r\n switch (pathType) {\r\n case LinkPathType.STRAIGHT:\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n \r\n case LinkPathType.BEZIER:\r\n return generateBezierConnectionPath(startX, startY, endX, endY, connectionType, bezierCurvature);\r\n \r\n case LinkPathType.RIGHT_ANGLE:\r\n default:\r\n return generateRightAngleConnectionPath(startX, startY, endX, endY, connectionType, rightAngleOffset, smoothCorners, cornerRadius);\r\n }\r\n };\r\n \r\n // 生成贝塞尔连接路径\r\n const generateBezierConnectionPath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n connectionType: string,\r\n curvature: number\r\n ): string => {\r\n const deltaX = endX - startX;\r\n const deltaY = endY - startY;\r\n \r\n switch (connectionType) {\r\n case 'horizontal':\r\n // 水平连接(完成-开始)\r\n if (deltaX > 20 && Math.abs(deltaY) < 10) {\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n \r\n if (deltaX < 20) {\r\n // 需要绕行\r\n const gap = 30;\r\n const bypassY = getSafeBypassY(startY, endY, gap);\r\n const curvatureOffset = gap * curvature;\r\n \r\n return `M ${startX} ${startY} \r\n C ${startX + curvatureOffset} ${startY} ${startX + curvatureOffset} ${bypassY} ${startX + gap/2} ${bypassY}\r\n C ${endX - curvatureOffset} ${bypassY} ${endX - curvatureOffset} ${endY} ${endX} ${endY}`;\r\n }\r\n \r\n // 标准S曲线\r\n const curvatureOffset = Math.min(Math.abs(deltaX) * curvature, 60);\r\n const cp1X = startX + curvatureOffset;\r\n const cp2X = endX - curvatureOffset;\r\n \r\n return `M ${startX} ${startY} C ${cp1X} ${startY} ${cp2X} ${endY} ${endX} ${endY}`;\r\n \r\n case 'left-u':\r\n // 左侧U型连接(开始-开始)\r\n const leftGap = 25;\r\n const leftOffsetX = Math.min(startX, endX) - leftGap;\r\n const leftCurvature = leftGap * curvature;\r\n \r\n if (Math.abs(deltaY) > getRowHeight()) {\r\n const midY = alignToGridCenter((startY + endY) / 2);\r\n return `M ${startX} ${startY} \r\n C ${startX - leftCurvature} ${startY} ${leftOffsetX} ${startY + leftCurvature} ${leftOffsetX} ${midY}\r\n C ${leftOffsetX} ${endY - leftCurvature} ${endX - leftCurvature} ${endY} ${endX} ${endY}`;\r\n }\r\n \r\n return `M ${startX} ${startY} C ${leftOffsetX} ${startY} ${leftOffsetX} ${endY} ${endX} ${endY}`;\r\n \r\n case 'right-u':\r\n // 右侧U型连接(完成-完成)\r\n const rightGap = 25;\r\n const rightOffsetX = Math.max(startX, endX) + rightGap;\r\n const rightCurvature = rightGap * curvature;\r\n \r\n if (Math.abs(deltaY) > getRowHeight()) {\r\n const midY = alignToGridCenter((startY + endY) / 2);\r\n return `M ${startX} ${startY} \r\n C ${startX + rightCurvature} ${startY} ${rightOffsetX} ${startY + rightCurvature} ${rightOffsetX} ${midY}\r\n C ${rightOffsetX} ${endY - rightCurvature} ${endX + rightCurvature} ${endY} ${endX} ${endY}`;\r\n }\r\n \r\n return `M ${startX} ${startY} C ${rightOffsetX} ${startY} ${rightOffsetX} ${endY} ${endX} ${endY}`;\r\n \r\n case 'cross':\r\n // 交叉连接(开始-完成)\r\n if (deltaX > 20 && Math.abs(deltaY) < 10) {\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n \r\n const crossCurvature = Math.min(Math.abs(deltaX) * curvature, 60);\r\n const crossCp1X = startX - crossCurvature;\r\n const crossCp2X = endX + crossCurvature;\r\n \r\n return `M ${startX} ${startY} C ${crossCp1X} ${startY} ${crossCp2X} ${endY} ${endX} ${endY}`;\r\n \r\n default:\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n };\r\n \r\n // 生成直角连接路径\r\n const generateRightAngleConnectionPath = (\r\n startX: number, startY: number, \r\n endX: number, endY: number, \r\n connectionType: string,\r\n offset: number,\r\n smoothCorners: boolean,\r\n cornerRadius: number\r\n ): string => {\r\n const deltaX = endX - startX;\r\n const deltaY = endY - startY;\r\n \r\n switch (connectionType) {\r\n case 'horizontal':\r\n // 水平连接(完成-开始)\r\n if (deltaX > 20 && Math.abs(deltaY) < 10) {\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n \r\n if (deltaX < 20) {\r\n // 需要绕行\r\n const gap = offset;\r\n const bypassY = getSafeBypassY(startY, endY, gap);\r\n const midX1 = startX + gap/2;\r\n const midX2 = endX - gap/2;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, gap / 4);\r\n return `M ${startX} ${startY}\r\n L ${midX1 - r} ${startY}\r\n Q ${midX1} ${startY} ${midX1} ${startY + r}\r\n L ${midX1} ${bypassY - r}\r\n Q ${midX1} ${bypassY} ${midX1 + r} ${bypassY}\r\n L ${midX2 - r} ${bypassY}\r\n Q ${midX2} ${bypassY} ${midX2} ${bypassY + r}\r\n L ${midX2} ${endY - r}\r\n Q ${midX2} ${endY} ${midX2 + r} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n \r\n return `M ${startX} ${startY} \r\n L ${midX1} ${startY}\r\n L ${midX1} ${bypassY}\r\n L ${midX2} ${bypassY}\r\n L ${midX2} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n \r\n // 标准L型路径\r\n const midX = startX + Math.abs(deltaX) / 2;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, Math.abs(deltaX) / 4, Math.abs(deltaY) / 2);\r\n if (deltaY > 0) {\r\n return `M ${startX} ${startY}\r\n L ${midX - r} ${startY}\r\n Q ${midX} ${startY} ${midX} ${startY + r}\r\n L ${midX} ${endY - r}\r\n Q ${midX} ${endY} ${midX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n } else {\r\n return `M ${startX} ${startY}\r\n L ${midX - r} ${startY}\r\n Q ${midX} ${startY} ${midX} ${startY - r}\r\n L ${midX} ${endY + r}\r\n Q ${midX} ${endY} ${midX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n }\r\n \r\n return `M ${startX} ${startY} L ${midX} ${startY} L ${midX} ${endY} L ${endX} ${endY}`;\r\n \r\n case 'left-u':\r\n // 左侧U型连接(开始-开始)\r\n const leftGap = offset;\r\n const leftOffsetX = Math.min(startX, endX) - leftGap;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, leftGap / 2, Math.abs(deltaY) / 4);\r\n return `M ${startX} ${startY}\r\n L ${leftOffsetX + r} ${startY}\r\n Q ${leftOffsetX} ${startY} ${leftOffsetX} ${startY + (deltaY > 0 ? r : -r)}\r\n L ${leftOffsetX} ${endY - (deltaY > 0 ? r : -r)}\r\n Q ${leftOffsetX} ${endY} ${leftOffsetX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n \r\n return `M ${startX} ${startY} L ${leftOffsetX} ${startY} L ${leftOffsetX} ${endY} L ${endX} ${endY}`;\r\n \r\n case 'right-u':\r\n // 右侧U型连接(完成-完成)\r\n const rightGap = offset;\r\n const rightOffsetX = Math.max(startX, endX) + rightGap;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, rightGap / 2, Math.abs(deltaY) / 4);\r\n return `M ${startX} ${startY}\r\n L ${rightOffsetX - r} ${startY}\r\n Q ${rightOffsetX} ${startY} ${rightOffsetX} ${startY + (deltaY > 0 ? r : -r)}\r\n L ${rightOffsetX} ${endY - (deltaY > 0 ? r : -r)}\r\n Q ${rightOffsetX} ${endY} ${rightOffsetX - r} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n \r\n return `M ${startX} ${startY} L ${rightOffsetX} ${startY} L ${rightOffsetX} ${endY} L ${endX} ${endY}`;\r\n \r\n case 'cross':\r\n // 交叉连接(开始-完成)\r\n if (deltaX > 20 && Math.abs(deltaY) < 10) {\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n \r\n const crossMidX = startX + deltaX / 2;\r\n \r\n if (smoothCorners && cornerRadius > 0) {\r\n const r = Math.min(cornerRadius, Math.abs(deltaX) / 4, Math.abs(deltaY) / 2);\r\n if (deltaY > 0) {\r\n return `M ${startX} ${startY}\r\n L ${crossMidX - r} ${startY}\r\n Q ${crossMidX} ${startY} ${crossMidX} ${startY + r}\r\n L ${crossMidX} ${endY - r}\r\n Q ${crossMidX} ${endY} ${crossMidX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n } else {\r\n return `M ${startX} ${startY}\r\n L ${crossMidX - r} ${startY}\r\n Q ${crossMidX} ${startY} ${crossMidX} ${startY - r}\r\n L ${crossMidX} ${endY + r}\r\n Q ${crossMidX} ${endY} ${crossMidX + r} ${endY}\r\n L ${endX} ${endY}`;\r\n }\r\n }\r\n \r\n return `M ${startX} ${startY} L ${crossMidX} ${startY} L ${crossMidX} ${endY} L ${endX} ${endY}`;\r\n \r\n default:\r\n return `M ${startX} ${startY} L ${endX} ${endY}`;\r\n }\r\n };\r\n \r\n // 生成箭头点(直接从子任务位置计算)- 用于父子关系连线\r\n const generateArrowPoints = (childPos: any, arrowSize: number, _linkType: LinkType = LinkType.FINISH_TO_START): string => {\r\n if (!childPos) {\r\n console.warn('子任务位置无效');\r\n return '';\r\n }\r\n \r\n try {\r\n // 箭头尖端:子任务左边缘中心\r\n const tipX = childPos.leftX;\r\n const tipY = childPos.centerY;\r\n \r\n // 父子关系连线:箭头指向右边(指向子任务)\r\n // 箭头底边的两个点\r\n const baseX = tipX - arrowSize;\r\n const baseY1 = tipY - arrowSize / 2;\r\n const baseY2 = tipY + arrowSize / 2;\r\n \r\n const result = `${tipX},${tipY} ${baseX},${baseY1} ${baseX},${baseY2}`;\r\n return result;\r\n } catch (e) {\r\n console.error('箭头生成失败:', e);\r\n return '';\r\n }\r\n };\r\n \r\n // 生成依赖连线的箭头点\r\n const generateDependencyArrowPoints = (\r\n sourcePos: any, \r\n targetPos: any, \r\n linkType: LinkType, \r\n arrowSize: number\r\n ): string => {\r\n if (!sourcePos || !targetPos) return '';\r\n \r\n try {\r\n let endX: number, endY: number;\r\n let direction: 'left' | 'right' | 'up' | 'down' = 'right';\r\n \r\n switch (linkType) {\r\n case LinkType.FINISH_TO_START:\r\n // 箭头指向目标任务的左边缘\r\n endX = targetPos.leftX;\r\n endY = targetPos.centerY;\r\n direction = 'right';\r\n break;\r\n \r\n case LinkType.START_TO_START:\r\n // 箭头指向目标任务的左边缘\r\n endX = targetPos.leftX;\r\n endY = targetPos.centerY;\r\n direction = 'right';\r\n break;\r\n \r\n case LinkType.FINISH_TO_FINISH:\r\n // 箭头指向目标任务的右边缘\r\n endX = targetPos.rightX;\r\n endY = targetPos.centerY;\r\n direction = 'left';\r\n break;\r\n \r\n case LinkType.START_TO_FINISH:\r\n // 箭头指向目标任务的右边缘\r\n endX = targetPos.rightX;\r\n endY = targetPos.centerY;\r\n direction = 'left';\r\n break;\r\n \r\n default:\r\n endX = targetPos.leftX;\r\n endY = targetPos.centerY;\r\n direction = 'right';\r\n }\r\n \r\n // 根据方向生成箭头\r\n let arrowPoint1X: number, arrowPoint1Y: number;\r\n let arrowPoint2X: number, arrowPoint2Y: number;\r\n \r\n if (direction === 'right') {\r\n // 箭头指向右边\r\n arrowPoint1X = endX - arrowSize;\r\n arrowPoint1Y = endY - arrowSize / 2;\r\n arrowPoint2X = endX - arrowSize;\r\n arrowPoint2Y = endY + arrowSize / 2;\r\n } else {\r\n // 箭头指向左边\r\n arrowPoint1X = endX + arrowSize;\r\n arrowPoint1Y = endY - arrowSize / 2;\r\n arrowPoint2X = endX + arrowSize;\r\n arrowPoint2Y = endY + arrowSize / 2;\r\n }\r\n \r\n return `${endX},${endY} ${arrowPoint1X},${arrowPoint1Y} ${arrowPoint2X},${arrowPoint2Y}`;\r\n } catch (e) {\r\n console.error('依赖箭头生成失败:', e);\r\n return '';\r\n }\r\n };\r\n \r\n // 更新连线\r\n // 获取所有被折叠的子任务ID集合(递归)\r\n const getAllCollapsedChildren = (parentId: any): Set<any> => {\r\n const collapsedChildren = new Set<any>();\r\n \r\n const collectChildren = (pid: any) => {\r\n const children = store.tasks.filter(task => task[store.mapFields.parentId] === pid);\r\n children.forEach(child => {\r\n const childId = child[store.mapFields.id];\r\n collapsedChildren.add(childId);\r\n // 递归收集所有子孙任务\r\n collectChildren(childId);\r\n });\r\n };\r\n \r\n collectChildren(parentId);\r\n return collapsedChildren;\r\n };\r\n \r\n // 检查任务是否被折叠(任务本身或其任何祖先被折叠)\r\n const isTaskCollapsed = (taskId: any): boolean => {\r\n // 检查所有已折叠的任务\r\n for (const collapsedId of store.collapsedTasks) {\r\n const collapsedChildren = getAllCollapsedChildren(collapsedId);\r\n if (collapsedChildren.has(taskId)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n };\r\n \r\n const updateLinks = () => {\r\n console.log('updateLinks called');\r\n const newLinks: TaskLink[] = [];\r\n \r\n // 获取连线类型显示配置\r\n const visibility = props.linkConfig.linkTypeVisibility || {\r\n finishToStart: true,\r\n startToStart: true,\r\n finishToFinish: true,\r\n startToFinish: true,\r\n parentChild: true\r\n };\r\n \r\n // 生成父子关系连线(根据 visibility 控制)\r\n if (visibility.parentChild) {\r\n store.tasks.forEach(task => {\r\n const parentId = task[store.mapFields.parentId];\r\n const childId = task[store.mapFields.id];\r\n \r\n if (parentId && parentId !== '0') {\r\n // 检查子任务是否被折叠,如果被折叠则不显示连线\r\n if (isTaskCollapsed(childId)) {\r\n return; // 跳过该连线\r\n }\r\n \r\n const parentPos = getTaskPosition(parentId);\r\n const childPos = getTaskPosition(childId);\r\n \r\n if (parentPos && childPos) {\r\n const linkId = `parent-child-${parentId}-${childId}`;\r\n \r\n // 为位置信息添加任务ID\r\n const parentPosWithId = { ...parentPos, id: parentId, taskId: parentId };\r\n const childPosWithId = { ...childPos, id: childId, taskId: childId };\r\n \r\n const path = generateLinkPath(parentPosWithId, childPosWithId, LinkType.PARENT_CHILD, linkId);\r\n const arrowPoints = props.linkConfig.showArrow ? \r\n generateArrowPoints(childPos, props.linkConfig.arrowSize, LinkType.PARENT_CHILD) : '';\r\n \r\n newLinks.push({\r\n id: linkId,\r\n sourceId: parentId,\r\n targetId: childId,\r\n type: LinkType.PARENT_CHILD,\r\n path,\r\n arrowPoints,\r\n labelX: childPos.centerX,\r\n labelY: childPos.centerY - 10\r\n });\r\n }\r\n }\r\n });\r\n }\r\n \r\n // 生成任务依赖连线\r\n const dependencies = linkDataManager.getDependencies();\r\n console.log('Dependencies:', dependencies);\r\n \r\n // 根据连线类型检查是否显示\r\n const shouldShowLinkType = (linkType: LinkType): boolean => {\r\n switch (linkType) {\r\n case LinkType.FINISH_TO_START:\r\n return visibility.finishToStart;\r\n case LinkType.START_TO_START:\r\n return visibility.startToStart;\r\n case LinkType.FINISH_TO_FINISH:\r\n return visibility.finishToFinish;\r\n case LinkType.START_TO_FINISH:\r\n return visibility.startToFinish;\r\n case LinkType.PARENT_CHILD:\r\n return visibility.parentChild;\r\n default:\r\n return true;\r\n }\r\n };\r\n \r\n dependencies.forEach(dep => {\r\n // 根据 visibility 过滤连线类型\r\n if (!shouldShowLinkType(dep.type)) {\r\n return;\r\n }\r\n \r\n const sourcePos = getTaskPosition(dep.sourceTaskId);\r\n const targetPos = getTaskPosition(dep.targetTaskId);\r\n \r\n if (sourcePos && targetPos) {\r\n const linkId = `dependency-${dep.id}`;\r\n \r\n // 为位置信息添加任务ID\r\n const sourcePosWithId = { ...sourcePos, id: dep.sourceTaskId, taskId: dep.sourceTaskId };\r\n const targetPosWithId = { ...targetPos, id: dep.targetTaskId, taskId: dep.targetTaskId };\r\n \r\n const path = generateLinkPath(sourcePosWithId, targetPosWithId, dep.type, linkId);\r\n \r\n // 根据连线类型生成箭头\r\n const arrowPoints = props.linkConfig.showArrow ? \r\n generateDependencyArrowPoints(sourcePosWithId, targetPosWithId, dep.type, props.linkConfig.arrowSize) : '';\r\n \r\n // 获取连线类型的标签\r\n const labelMap: Record<LinkType, string> = {\r\n [LinkType.FINISH_TO_START]: 'FS',\r\n [LinkType.START_TO_START]: 'SS',\r\n [LinkType.FINISH_TO_FINISH]: 'FF',\r\n [LinkType.START_TO_FINISH]: 'SF',\r\n [LinkType.PARENT_CHILD]: ''\r\n };\r\n \r\n newLinks.push({\r\n id: linkId,\r\n sourceId: dep.sourceTaskId,\r\n targetId: dep.targetTaskId,\r\n type: dep.type,\r\n path,\r\n arrowPoints,\r\n label: labelMap[dep.type] || '',\r\n labelX: (sourcePos.centerX + targetPos.centerX) / 2,\r\n labelY: (sourcePos.centerY + targetPos.centerY) / 2 - 10\r\n });\r\n }\r\n });\r\n \r\n links.value = newLinks;\r\n };\r\n \r\n // 监听任务变化\r\n watch(() => store.tasks, () => {\r\n // 延迟更新,确保DOM已更新\r\n setTimeout(updateLinks, 50);\r\n }, { deep: true });\r\n \r\n watch(() => store.scale, () => {\r\n setTimeout(updateLinks, 50);\r\n });\r\n \r\n // 监听模式变化(月、日、时切换)\r\n watch(() => store.mode, () => {\r\n // 模式切换时需要重新计算bar位置,延迟更新确保bar重绘完成\r\n setTimeout(updateLinks, 200);\r\n });\r\n \r\n // 监听时间轴变化\r\n watch(() => store.timelineCellCount, () => {\r\n setTimeout(updateLinks, 100);\r\n });\r\n \r\n // 监听甘特图日期范围变化\r\n watch(() => [store.startGanttDate, store.endGanttDate], () => {\r\n setTimeout(updateLinks, 100);\r\n });\r\n \r\n // 监听barDate变化(拖拽和调整大小时会触发)\r\n watch(() => store.barDate, () => {\r\n requestAnimationFrame(updateLinks);\r\n }, { deep: true });\r\n \r\n // 监听连线类型显示配置变化\r\n watch(() => props.linkConfig.linkTypeVisibility, () => {\r\n setTimeout(updateLinks, 50);\r\n }, { deep: true });\r\n \r\n // 监听折叠状态变化\r\n watch(() => store.collapsedTasks, () => {\r\n setTimeout(updateLinks, 50);\r\n }, { deep: true });\r\n \r\n // 监听DOM变化(拖拽时重绘)\r\n let resizeObserver: ResizeObserver | null = null;\r\n let mutationObserver: MutationObserver | null = null;\r\n \r\n onMounted(() => {\r\n // 初始更新\r\n setTimeout(updateLinks, 100);\r\n \r\n // 监听容器大小变化\r\n const container = document.querySelector('.gantt');\r\n if (container) {\r\n resizeObserver = new ResizeObserver(updateLinks);\r\n resizeObserver.observe(container);\r\n \r\n\r\n \r\n // 监听DOM变化(任务条位置变化)\r\n mutationObserver = new MutationObserver((mutations) => {\r\n let shouldUpdate = false;\r\n mutations.forEach(mutation => {\r\n const target = mutation.target as HTMLElement;\r\n // 检查是否是SVG bar元素或其父元素\r\n if (mutation.type === 'attributes') {\r\n const attrName = mutation.attributeName;\r\n if (attrName === 'data-x' || \r\n attrName === 'width' || \r\n attrName === 'style' ||\r\n attrName === 'transform') {\r\n // 检查是否是bar元素\r\n if (target.classList?.contains('bar') || \r\n target.classList?.contains('barRow') ||\r\n target.tagName === 'svg') {\r\n shouldUpdate = true;\r\n }\r\n }\r\n }\r\n });\r\n if (shouldUpdate) {\r\n requestAnimationFrame(updateLinks);\r\n }\r\n });\r\n \r\n mutationObserver.observe(container, {\r\n attributes: true,\r\n subtree: true,\r\n attributeFilter: ['style', 'data-x', 'transform', 'width']\r\n });\r\n }\r\n });\r\n \r\n onUnmounted(() => {\r\n if (resizeObserver) {\r\n resizeObserver.disconnect();\r\n }\r\n if (mutationObserver) {\r\n mutationObserver.disconnect();\r\n }\r\n });\r\n \r\n // 虚线动画相关方法\r\n \r\n // 判断是否为虚线\r\n const isDashedLine = (linkType: LinkType): boolean => {\r\n const style = getLinkStyle(linkType);\r\n return !!(style.dashArray && style.dashArray.length > 0);\r\n };\r\n \r\n // 获取虚线流动动画样式\r\n const getDashAnimationStyle = (link: TaskLink) => {\r\n if (!isDashedLine(link.type) || !props.linkConfig.enableDashAnimation) {\r\n return {};\r\n }\r\n \r\n const style = getLinkStyle(link.type);\r\n const speed = props.linkConfig.dashAnimationSpeed || 0.8; // 更快的默认速度\r\n \r\n // 父子关系连线稍快一些\r\n const adjustedSpeed = link.type === LinkType.PARENT_CHILD ? speed * 0.6 : speed;\r\n \r\n // 计算虚线总长度用于动画\r\n const dashArray = style.dashArray || '5,5';\r\n const dashParts = dashArray.split(',').map(Number);\r\n const dashLength = dashParts.reduce((sum, part) => sum + part, 0);\r\n \r\n return {\r\n '--animation-duration': `${adjustedSpeed}s`,\r\n '--dash-length': `${dashLength}px`\r\n };\r\n };\r\n \r\n return {\r\n links,\r\n updateLinks,\r\n getLinkStyle,\r\n isDashedLine,\r\n getDashAnimationStyle\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.task-links-layer {\r\n pointer-events: none;\r\n \r\n .task-link {\r\n transition: stroke-width 0.2s ease;\r\n \r\n &:hover {\r\n stroke-width: 3;\r\n }\r\n \r\n &.parent-child {\r\n opacity: 0.7;\r\n }\r\n \r\n &.finish-to-start {\r\n opacity: 0.9;\r\n }\r\n \r\n // 虚线流动动画\r\n &.dash-animated {\r\n animation: dashFlow var(--animation-duration, 3s) linear infinite;\r\n }\r\n }\r\n \r\n // 虚线流动动画关键帧\r\n @keyframes dashFlow {\r\n 0% {\r\n stroke-dashoffset: 0;\r\n }\r\n 100% {\r\n stroke-dashoffset: calc(-1 * var(--dash-length, 20px));\r\n }\r\n }\r\n \r\n .task-link-arrow {\r\n transition: fill 0.2s ease;\r\n opacity: 1;\r\n pointer-events: none;\r\n }\r\n \r\n .task-link-label {\r\n font-family: Arial, sans-serif;\r\n user-select: none;\r\n }\r\n}\r\n</style>","<template>\r\n <div ref=\"barContent\" @scroll=\"scroll()\" @mouseover=\"mouseover()\"\r\n v-if=\"tasks\" class=\"content\">\r\n <div class=\"content-inner\" :style=\"{ minHeight: containerHeight + 'px', position: 'relative' }\">\r\n <BarRecursionRow :key=\"`${mode}-${scale}-${timelineCellCount}`\" :rowHeight=\"rowHeight\" :tasks=\"tasks\"></BarRecursionRow>\r\n <!-- 任务连线层 -->\r\n <TaskLinks \r\n :containerWidth=\"containerWidth\" \r\n :containerHeight=\"containerHeight\"\r\n :linkConfig=\"linkConfig\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n <script lang=\"ts\">\r\n import { defineComponent, ref, watch, computed, onMounted } from 'vue';\r\n import { store } from '../gantt/Store';\r\n import { useScrollState } from './ShareState';\r\n import { useLinkConfig } from './LinkConfig';\r\n import BarRecursionRow from '../gantt/BarRecursionRow.vue';\r\n import TaskLinks from './TaskLinks.vue';\r\n\r\n export default defineComponent({\r\n props: {\r\n rowHeight: {\r\n type: Number,\r\n required: true\r\n },\r\n headers: {\r\n type: Array,\r\n default: () => []\r\n },\r\n },\r\n components: {\r\n BarRecursionRow,\r\n TaskLinks\r\n },\r\n setup(props) {\r\n const barContent = ref<HTMLDivElement | null>(null);\r\n const { scrollTop, scrollFlag, setScrollTop, setScrollFlag } = useScrollState();\r\n const { config: linkConfig } = useLinkConfig();\r\n\r\n const tasks = computed(() => store.tasks);\r\n const timelineCellCount = computed(() => store.timelineCellCount);\r\n const scale = computed(() => store.scale);\r\n const mode = computed(() => store.mode);\r\n const startGanttDate = computed(() => store.startGanttDate);\r\n const endGanttDate = computed(() => store.endGanttDate);\r\n const mapFields = computed(() => store.mapFields);\r\n \r\n // 计算容器尺寸\r\n const containerWidth = computed(() => {\r\n return timelineCellCount.value * scale.value;\r\n });\r\n \r\n const containerHeight = computed(() => {\r\n return tasks.value.length * props.rowHeight;\r\n });\r\n\r\n // 监听共享的滚动位置变化\r\n watch(scrollTop, (newValue) => {\r\n if (scrollFlag.value && barContent.value) {\r\n barContent.value.scrollTop = newValue;\r\n }\r\n });\r\n\r\n onMounted(() => {\r\n if (barContent.value) {\r\n // 初始化时同步滚动位置\r\n barContent.value.scrollTop = scrollTop.value;\r\n }\r\n });\r\n\r\n const getRootNode = () => {\r\n return tasks.value.filter(obj => obj[mapFields.value['parentId']] === '0');\r\n };\r\n\r\n // 优化:使用requestAnimationFrame优化滚动性能\r\n let rafId: number | null = null;\r\n const scroll = () => {\r\n if (rafId) {\r\n cancelAnimationFrame(rafId);\r\n }\r\n rafId = requestAnimationFrame(() => {\r\n if (barContent.value) {\r\n setScrollFlag(false); // 标记当前面板为主动滚动\r\n setScrollTop(barContent.value.scrollTop);\r\n }\r\n rafId = null;\r\n });\r\n };\r\n\r\n const mouseover = () => {\r\n // 鼠标悬停时不改变滚动标志,让滚动事件处理\r\n };\r\n\r\n return {\r\n barContent,\r\n scrollFlag,\r\n tasks,\r\n timelineCellCount,\r\n scale,\r\n mode,\r\n startGanttDate,\r\n endGanttDate,\r\n mapFields,\r\n getRootNode,\r\n scroll,\r\n mouseover,\r\n setScrollFlag,\r\n containerWidth,\r\n containerHeight,\r\n linkConfig\r\n };\r\n }\r\n });\r\n </script>\r\n <style lang=\"scss\" scoped>\r\n .content {\r\n width: 100%;\r\n height: 100%;\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n margin: 0px 0px -1px 0px;\r\n font-size: 20px;\r\n overflow-y: auto;\r\n overflow-x: hidden;\r\n \r\n .content-inner {\r\n width: 100%;\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n }\r\n }\r\n </style>","<template>\r\n <div ref=\"barContent\" @scroll=\"scroll()\" @mouseover=\"mouseover()\"\r\n v-if=\"tasks\" class=\"content\">\r\n <div class=\"content-inner\" :style=\"{ minHeight: containerHeight + 'px', position: 'relative' }\">\r\n <BarRecursionRow :key=\"`${mode}-${scale}-${timelineCellCount}`\" :rowHeight=\"rowHeight\" :tasks=\"tasks\"></BarRecursionRow>\r\n <!-- 任务连线层 -->\r\n <TaskLinks \r\n :containerWidth=\"containerWidth\" \r\n :containerHeight=\"containerHeight\"\r\n :linkConfig=\"linkConfig\"\r\n />\r\n </div>\r\n </div>\r\n </template>\r\n <script lang=\"ts\">\r\n import { defineComponent, ref, watch, computed, onMounted } from 'vue';\r\n import { store } from '../gantt/Store';\r\n import { useScrollState } from './ShareState';\r\n import { useLinkConfig } from './LinkConfig';\r\n import BarRecursionRow from '../gantt/BarRecursionRow.vue';\r\n import TaskLinks from './TaskLinks.vue';\r\n\r\n export default defineComponent({\r\n props: {\r\n rowHeight: {\r\n type: Number,\r\n required: true\r\n },\r\n headers: {\r\n type: Array,\r\n default: () => []\r\n },\r\n },\r\n components: {\r\n BarRecursionRow,\r\n TaskLinks\r\n },\r\n setup(props) {\r\n const barContent = ref<HTMLDivElement | null>(null);\r\n const { scrollTop, scrollFlag, setScrollTop, setScrollFlag } = useScrollState();\r\n const { config: linkConfig } = useLinkConfig();\r\n\r\n const tasks = computed(() => store.tasks);\r\n const timelineCellCount = computed(() => store.timelineCellCount);\r\n const scale = computed(() => store.scale);\r\n const mode = computed(() => store.mode);\r\n const startGanttDate = computed(() => store.startGanttDate);\r\n const endGanttDate = computed(() => store.endGanttDate);\r\n const mapFields = computed(() => store.mapFields);\r\n \r\n // 计算容器尺寸\r\n const containerWidth = computed(() => {\r\n return timelineCellCount.value * scale.value;\r\n });\r\n \r\n const containerHeight = computed(() => {\r\n return tasks.value.length * props.rowHeight;\r\n });\r\n\r\n // 监听共享的滚动位置变化\r\n watch(scrollTop, (newValue) => {\r\n if (scrollFlag.value && barContent.value) {\r\n barContent.value.scrollTop = newValue;\r\n }\r\n });\r\n\r\n onMounted(() => {\r\n if (barContent.value) {\r\n // 初始化时同步滚动位置\r\n barContent.value.scrollTop = scrollTop.value;\r\n }\r\n });\r\n\r\n const getRootNode = () => {\r\n return tasks.value.filter(obj => obj[mapFields.value['parentId']] === '0');\r\n };\r\n\r\n // 优化:使用requestAnimationFrame优化滚动性能\r\n let rafId: number | null = null;\r\n const scroll = () => {\r\n if (rafId) {\r\n cancelAnimationFrame(rafId);\r\n }\r\n rafId = requestAnimationFrame(() => {\r\n if (barContent.value) {\r\n setScrollFlag(false); // 标记当前面板为主动滚动\r\n setScrollTop(barContent.value.scrollTop);\r\n }\r\n rafId = null;\r\n });\r\n };\r\n\r\n const mouseover = () => {\r\n // 鼠标悬停时不改变滚动标志,让滚动事件处理\r\n };\r\n\r\n return {\r\n barContent,\r\n scrollFlag,\r\n tasks,\r\n timelineCellCount,\r\n scale,\r\n mode,\r\n startGanttDate,\r\n endGanttDate,\r\n mapFields,\r\n getRootNode,\r\n scroll,\r\n mouseover,\r\n setScrollFlag,\r\n containerWidth,\r\n containerHeight,\r\n linkConfig\r\n };\r\n }\r\n });\r\n </script>\r\n <style lang=\"scss\" scoped>\r\n .content {\r\n width: 100%;\r\n height: 100%;\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n margin: 0px 0px -1px 0px;\r\n font-size: 20px;\r\n overflow-y: auto;\r\n overflow-x: hidden;\r\n \r\n .content-inner {\r\n width: 100%;\r\n display: flex;\r\n flex-flow: column nowrap;\r\n align-items: center;\r\n justify-content: flex-start;\r\n }\r\n }\r\n </style>","<template>\r\n <div ref=\"tableBar\" class=\"table\">\r\n <div class=\"header\" :style=\"{ height: `${headersHeight}px` }\">\r\n <div class=\"header-border-top\"></div>\r\n <TimelineHeader :weekHeaders=\"weekHeaders\" :hourHeaders=\"hourHeaders\" :dayHeaders=\"dayHeaders\"\r\n :monthHeaders=\"monthHeaders\"></TimelineHeader>\r\n <div class=\"header-border-bottom\"></div>\r\n </div>\r\n <div class=\"content\" :style=\"{ height: `calc(100% - ${headersHeight}px)`, width: 'fit-content', position: 'relative' }\">\r\n <TableContent :rowHeight='rowHeight'></TableContent>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, onMounted, computed, watch } from 'vue';\r\nimport type { Ref } from 'vue';\r\nimport TimelineHeader from './TimelineHeader.vue';\r\nimport { store } from './Store';\r\nimport dayjs from 'dayjs';\r\nimport sharedState from './ShareState';\r\nimport TableContent from './TableContent.vue';\r\n\r\nexport default defineComponent({\r\n props: {\r\n headersHeight: {\r\n type: Number,\r\n default: 50\r\n },\r\n rowHeight: {\r\n type: Number,\r\n default: 50\r\n }\r\n },\r\n components: {\r\n TimelineHeader,\r\n TableContent\r\n },\r\n setup(props) {\r\n // 引用 tableBar\r\n const tableBar: Ref<HTMLDivElement | null> = ref(null);\r\n \r\n\r\n\r\n // 计算属性\r\n const dayHeaders = computed(() => store.dayHeaders);\r\n const weekHeaders = computed(() => store.weekHeaders);\r\n const monthHeaders = computed(() => store.monthHeaders);\r\n const hourHeaders = computed(() => store.hourHeaders);\r\n const startGanttDate = computed(() => store.startGanttDate);\r\n const mode = computed(() => store.mode);\r\n const scale = computed(() => store.scale);\r\n \r\n // 容器尺寸\r\n const containerWidth = computed(() => {\r\n return store.timelineCellCount * scale.value + 100; // 添加额外空间\r\n });\r\n \r\n const containerHeight = computed(() => {\r\n return store.tasks.length * props.rowHeight + 100; // 使用实际行高\r\n });\r\n\r\n // 滚动到今天的方法\r\n const scrollToToday = () => {\r\n if (tableBar.value) {\r\n switch (mode.value) {\r\n case '月':\r\n case '日':\r\n tableBar.value.scrollLeft = Number(dayjs().diff(dayjs(startGanttDate.value), 'day')) * Number(scale.value);\r\n break;\r\n case '周':\r\n // 周模式:滚动到当前周\r\n const currentWeekStart = dayjs().startOf('isoWeek');\r\n const ganttWeekStart = dayjs(startGanttDate.value).startOf('isoWeek');\r\n tableBar.value.scrollLeft = Number(currentWeekStart.diff(ganttWeekStart, 'week')) * Number(scale.value);\r\n break;\r\n case '时':\r\n tableBar.value.scrollLeft = Number(dayjs().diff(dayjs(startGanttDate.value), 'hour')) * Number(scale.value);\r\n break;\r\n }\r\n }\r\n };\r\n\r\n watch(() => sharedState.shouldScrollToToday, (newValue) => {\r\n if (newValue) {\r\n scrollToToday();\r\n // 重置状态\r\n sharedState.shouldScrollToToday = false;\r\n }\r\n });\r\n\r\n onMounted(() => {\r\n\r\n });\r\n\r\n return {\r\n tableBar,\r\n dayHeaders,\r\n weekHeaders,\r\n monthHeaders,\r\n hourHeaders,\r\n startGanttDate,\r\n mode,\r\n scale,\r\n scrollToToday\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.table {\r\n height: 100%;\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n overflow-y: hidden;\r\n\r\n .header {\r\n width: 100%;\r\n border: 0px;\r\n }\r\n\r\n .header-border-top,\r\n .header-border-bottom {\r\n width: 100%;\r\n border-top: 1px solid var(--border);\r\n margin: 0px 0px -1px -1px;\r\n }\r\n\r\n .content {\r\n overflow-y: auto;\r\n overflow-x: auto;\r\n }\r\n}\r\n</style>","<template>\r\n <div ref=\"tableBar\" class=\"table\">\r\n <div class=\"header\" :style=\"{ height: `${headersHeight}px` }\">\r\n <div class=\"header-border-top\"></div>\r\n <TimelineHeader :weekHeaders=\"weekHeaders\" :hourHeaders=\"hourHeaders\" :dayHeaders=\"dayHeaders\"\r\n :monthHeaders=\"monthHeaders\"></TimelineHeader>\r\n <div class=\"header-border-bottom\"></div>\r\n </div>\r\n <div class=\"content\" :style=\"{ height: `calc(100% - ${headersHeight}px)`, width: 'fit-content', position: 'relative' }\">\r\n <TableContent :rowHeight='rowHeight'></TableContent>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, onMounted, computed, watch } from 'vue';\r\nimport type { Ref } from 'vue';\r\nimport TimelineHeader from './TimelineHeader.vue';\r\nimport { store } from './Store';\r\nimport dayjs from 'dayjs';\r\nimport sharedState from './ShareState';\r\nimport TableContent from './TableContent.vue';\r\n\r\nexport default defineComponent({\r\n props: {\r\n headersHeight: {\r\n type: Number,\r\n default: 50\r\n },\r\n rowHeight: {\r\n type: Number,\r\n default: 50\r\n }\r\n },\r\n components: {\r\n TimelineHeader,\r\n TableContent\r\n },\r\n setup(props) {\r\n // 引用 tableBar\r\n const tableBar: Ref<HTMLDivElement | null> = ref(null);\r\n \r\n\r\n\r\n // 计算属性\r\n const dayHeaders = computed(() => store.dayHeaders);\r\n const weekHeaders = computed(() => store.weekHeaders);\r\n const monthHeaders = computed(() => store.monthHeaders);\r\n const hourHeaders = computed(() => store.hourHeaders);\r\n const startGanttDate = computed(() => store.startGanttDate);\r\n const mode = computed(() => store.mode);\r\n const scale = computed(() => store.scale);\r\n \r\n // 容器尺寸\r\n const containerWidth = computed(() => {\r\n return store.timelineCellCount * scale.value + 100; // 添加额外空间\r\n });\r\n \r\n const containerHeight = computed(() => {\r\n return store.tasks.length * props.rowHeight + 100; // 使用实际行高\r\n });\r\n\r\n // 滚动到今天的方法\r\n const scrollToToday = () => {\r\n if (tableBar.value) {\r\n switch (mode.value) {\r\n case '月':\r\n case '日':\r\n tableBar.value.scrollLeft = Number(dayjs().diff(dayjs(startGanttDate.value), 'day')) * Number(scale.value);\r\n break;\r\n case '周':\r\n // 周模式:滚动到当前周\r\n const currentWeekStart = dayjs().startOf('isoWeek');\r\n const ganttWeekStart = dayjs(startGanttDate.value).startOf('isoWeek');\r\n tableBar.value.scrollLeft = Number(currentWeekStart.diff(ganttWeekStart, 'week')) * Number(scale.value);\r\n break;\r\n case '时':\r\n tableBar.value.scrollLeft = Number(dayjs().diff(dayjs(startGanttDate.value), 'hour')) * Number(scale.value);\r\n break;\r\n }\r\n }\r\n };\r\n\r\n watch(() => sharedState.shouldScrollToToday, (newValue) => {\r\n if (newValue) {\r\n scrollToToday();\r\n // 重置状态\r\n sharedState.shouldScrollToToday = false;\r\n }\r\n });\r\n\r\n onMounted(() => {\r\n\r\n });\r\n\r\n return {\r\n tableBar,\r\n dayHeaders,\r\n weekHeaders,\r\n monthHeaders,\r\n hourHeaders,\r\n startGanttDate,\r\n mode,\r\n scale,\r\n scrollToToday\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.table {\r\n height: 100%;\r\n width: 100%;\r\n display: flex;\r\n flex-direction: column;\r\n overflow-y: hidden;\r\n\r\n .header {\r\n width: 100%;\r\n border: 0px;\r\n }\r\n\r\n .header-border-top,\r\n .header-border-bottom {\r\n width: 100%;\r\n border-top: 1px solid var(--border);\r\n margin: 0px 0px -1px -1px;\r\n }\r\n\r\n .content {\r\n overflow-y: auto;\r\n overflow-x: auto;\r\n }\r\n}\r\n</style>","// 甘特图主题系统\r\nexport interface GanttTheme {\r\n id: string;\r\n nameKey: string; // 主题名称的翻译键\r\n descKey: string; // 主题描述的翻译键\r\n preview: string;\r\n cssVariables: Record<string, string>;\r\n}\r\n\r\nexport const ganttThemes: GanttTheme[] = [\r\n {\r\n id: 'metro',\r\n nameKey: 'theme.metro',\r\n descKey: 'theme.metroDesc',\r\n preview: '#0078d4',\r\n cssVariables: {\r\n // Metro 金属主题变量\r\n '--primary': '#0078d4',\r\n '--primary-dark': '#106ebe',\r\n '--primary-light': '#1084d8',\r\n '--secondary': '#0d5aa7',\r\n \r\n '--bg-metal-light': 'linear-gradient(145deg, #ffffff, #f5f5f5)',\r\n '--bg-metal-normal': 'linear-gradient(145deg, #f5f5f5, #e8e8e8)',\r\n '--bg-metal-dark': 'linear-gradient(145deg, #e6e6e6, #d0d0d0)',\r\n '--bg-metal-pressed': 'linear-gradient(145deg, #e0e0e0, #f8f8f8)',\r\n \r\n '--bg-active': 'linear-gradient(145deg, #0078d4, #106ebe)',\r\n '--bg-active-hover': 'linear-gradient(145deg, #1084d8, #0d5aa7)',\r\n '--bg-active-pressed': 'linear-gradient(145deg, #0d5aa7, #1084d8)',\r\n \r\n '--border': '#d0d0d0',\r\n '--border-dark': '#b0b0b0',\r\n '--shadow-inset': 'inset 0 1px 0 rgba(255, 255, 255, 0.8), inset 0 -1px 0 rgba(0, 0, 0, 0.1)',\r\n '--shadow-outset': '0 2px 4px rgba(0, 0, 0, 0.1)',\r\n '--shadow-active': 'inset 0 1px 0 rgba(255, 255, 255, 0.2), inset 0 -1px 0 rgba(0, 0, 0, 0.3)',\r\n \r\n '--text-primary': '#333333',\r\n '--text-secondary': '#666666',\r\n '--text-muted': '#999999',\r\n '--text-white': '#ffffff',\r\n \r\n '--bg-primary': '#f8f8f8',\r\n '--bg-secondary': '#e8e8e8',\r\n '--bg-content': '#ffffff',\r\n '--row-hover': '#FFF3A1',\r\n \r\n '--transition-fast': '0.15s ease',\r\n '--transition-normal': '0.25s ease',\r\n '--transition-slow': '0.35s ease',\r\n \r\n '--font-family': \"'Segoe UI', Tahoma, Geneva, Verdana, sans-serif\",\r\n '--font-size-base': '12px',\r\n '--font-weight-normal': '500',\r\n '--font-weight-bold': '600'\r\n }\r\n },\r\n {\r\n id: 'dark',\r\n nameKey: 'theme.dark',\r\n descKey: 'theme.darkDesc',\r\n preview: '#00d4ff',\r\n cssVariables: {\r\n '--primary': '#00d4ff',\r\n '--primary-dark': '#00b8e6',\r\n '--primary-light': '#33ddff',\r\n '--secondary': '#0099cc',\r\n \r\n '--bg-metal-light': 'linear-gradient(145deg, #3a3a3a, #2d2d2d)',\r\n '--bg-metal-normal': 'linear-gradient(145deg, #2d2d2d, #1f1f1f)',\r\n '--bg-metal-dark': 'linear-gradient(145deg, #1f1f1f, #0d0d0d)',\r\n '--bg-metal-pressed': 'linear-gradient(145deg, #0d0d0d, #2d2d2d)',\r\n \r\n '--bg-active': 'linear-gradient(145deg, #00d4ff, #0099cc)',\r\n '--bg-active-hover': 'linear-gradient(145deg, #33ddff, #00b8e6)',\r\n '--bg-active-pressed': 'linear-gradient(145deg, #00b8e6, #33ddff)',\r\n \r\n '--border': '#404040',\r\n '--border-dark': '#2d2d2d',\r\n '--shadow-inset': 'inset 0 1px 0 rgba(255, 255, 255, 0.1), inset 0 -1px 0 rgba(0, 0, 0, 0.3)',\r\n '--shadow-outset': '0 2px 8px rgba(0, 0, 0, 0.3)',\r\n '--shadow-active': 'inset 0 1px 0 rgba(255, 255, 255, 0.2), inset 0 -1px 0 rgba(0, 0, 0, 0.5)',\r\n \r\n '--text-primary': '#ffffff',\r\n '--text-secondary': '#cccccc',\r\n '--text-muted': '#888888',\r\n '--text-white': '#ffffff',\r\n \r\n '--bg-primary': '#1a1a1a',\r\n '--bg-secondary': '#2d2d2d',\r\n '--bg-content': '#262626',\r\n '--row-hover': '#3a4a5a',\r\n \r\n '--transition-fast': '0.15s ease',\r\n '--transition-normal': '0.25s ease',\r\n '--transition-slow': '0.35s ease',\r\n \r\n '--font-family': \"'Segoe UI', Tahoma, Geneva, Verdana, sans-serif\",\r\n '--font-size-base': '12px',\r\n '--font-weight-normal': '500',\r\n '--font-weight-bold': '600'\r\n }\r\n },\r\n {\r\n id: 'modern',\r\n nameKey: 'theme.light',\r\n descKey: 'theme.lightDesc',\r\n preview: '#6366f1',\r\n cssVariables: {\r\n '--primary': '#6366f1',\r\n '--primary-dark': '#4f46e5',\r\n '--primary-light': '#8b5cf6',\r\n '--secondary': '#3730a3',\r\n \r\n '--bg-metal-light': 'linear-gradient(145deg, #fafafa, #f0f0f0)',\r\n '--bg-metal-normal': 'linear-gradient(145deg, #f0f0f0, #e0e0e0)',\r\n '--bg-metal-dark': 'linear-gradient(145deg, #e0e0e0, #d0d0d0)',\r\n '--bg-metal-pressed': 'linear-gradient(145deg, #d8d8d8, #f0f0f0)',\r\n \r\n '--bg-active': 'linear-gradient(145deg, #6366f1, #4f46e5)',\r\n '--bg-active-hover': 'linear-gradient(145deg, #8b5cf6, #6366f1)',\r\n '--bg-active-pressed': 'linear-gradient(145deg, #4f46e5, #8b5cf6)',\r\n \r\n '--border': '#e0e0e0',\r\n '--border-dark': '#c0c0c0',\r\n '--shadow-inset': 'inset 0 1px 0 rgba(255, 255, 255, 0.9), inset 0 -1px 0 rgba(0, 0, 0, 0.05)',\r\n '--shadow-outset': '0 1px 3px rgba(0, 0, 0, 0.08)',\r\n '--shadow-active': 'inset 0 1px 0 rgba(255, 255, 255, 0.3), inset 0 -1px 0 rgba(0, 0, 0, 0.2)',\r\n \r\n '--text-primary': '#1f2937',\r\n '--text-secondary': '#6b7280',\r\n '--text-muted': '#9ca3af',\r\n '--text-white': '#ffffff',\r\n \r\n '--bg-primary': '#ffffff',\r\n '--bg-secondary': '#f9fafb',\r\n '--bg-content': '#ffffff',\r\n '--row-hover': '#e0e7ff',\r\n \r\n '--transition-fast': '0.15s ease',\r\n '--transition-normal': '0.25s ease',\r\n '--transition-slow': '0.35s ease',\r\n \r\n '--font-family': \"'Inter', 'Segoe UI', sans-serif\",\r\n '--font-size-base': '12px',\r\n '--font-weight-normal': '400',\r\n '--font-weight-bold': '600'\r\n }\r\n },\r\n {\r\n id: 'classic',\r\n nameKey: 'theme.classic',\r\n descKey: 'theme.classicDesc',\r\n preview: '#2563eb',\r\n cssVariables: {\r\n '--primary': '#2563eb',\r\n '--primary-dark': '#1d4ed8',\r\n '--primary-light': '#3b82f6',\r\n '--secondary': '#1e40af',\r\n \r\n '--bg-metal-light': 'linear-gradient(145deg, #f8f9fa, #e9ecef)',\r\n '--bg-metal-normal': 'linear-gradient(145deg, #e9ecef, #dee2e6)',\r\n '--bg-metal-dark': 'linear-gradient(145deg, #dee2e6, #ced4da)',\r\n '--bg-metal-pressed': 'linear-gradient(145deg, #ced4da, #e9ecef)',\r\n \r\n '--bg-active': 'linear-gradient(145deg, #2563eb, #1d4ed8)',\r\n '--bg-active-hover': 'linear-gradient(145deg, #3b82f6, #2563eb)',\r\n '--bg-active-pressed': 'linear-gradient(145deg, #1d4ed8, #3b82f6)',\r\n \r\n '--border': '#ced4da',\r\n '--border-dark': '#adb5bd',\r\n '--shadow-inset': 'inset 0 1px 0 rgba(255, 255, 255, 0.7), inset 0 -1px 0 rgba(0, 0, 0, 0.1)',\r\n '--shadow-outset': '0 2px 4px rgba(0, 0, 0, 0.12)',\r\n '--shadow-active': 'inset 0 1px 0 rgba(255, 255, 255, 0.2), inset 0 -1px 0 rgba(0, 0, 0, 0.25)',\r\n \r\n '--text-primary': '#212529',\r\n '--text-secondary': '#495057',\r\n '--text-muted': '#6c757d',\r\n '--text-white': '#ffffff',\r\n \r\n '--bg-primary': '#ffffff',\r\n '--bg-secondary': '#f8f9fa',\r\n '--bg-content': '#ffffff',\r\n '--row-hover': '#dbeafe',\r\n \r\n '--transition-fast': '0.15s ease',\r\n '--transition-normal': '0.25s ease',\r\n '--transition-slow': '0.35s ease',\r\n \r\n '--font-family': \"'Times New Roman', serif\",\r\n '--font-size-base': '12px',\r\n '--font-weight-normal': '400',\r\n '--font-weight-bold': '700'\r\n }\r\n },\r\n {\r\n id: 'colorful',\r\n nameKey: 'theme.colorful',\r\n descKey: 'theme.colorfulDesc',\r\n preview: '#f59e0b',\r\n cssVariables: {\r\n '--primary': '#f59e0b',\r\n '--primary-dark': '#d97706',\r\n '--primary-light': '#fbbf24',\r\n '--secondary': '#b45309',\r\n \r\n '--bg-metal-light': 'linear-gradient(145deg, #fef3c7, #fed7aa)',\r\n '--bg-metal-normal': 'linear-gradient(145deg, #fed7aa, #fdba74)',\r\n '--bg-metal-dark': 'linear-gradient(145deg, #fdba74, #fb923c)',\r\n '--bg-metal-pressed': 'linear-gradient(145deg, #fb923c, #fed7aa)',\r\n \r\n '--bg-active': 'linear-gradient(145deg, #f59e0b, #d97706)',\r\n '--bg-active-hover': 'linear-gradient(145deg, #fbbf24, #f59e0b)',\r\n '--bg-active-pressed': 'linear-gradient(145deg, #d97706, #fbbf24)',\r\n \r\n '--border': '#fdba74',\r\n '--border-dark': '#fb923c',\r\n '--shadow-inset': 'inset 0 1px 0 rgba(255, 255, 255, 0.6), inset 0 -1px 0 rgba(0, 0, 0, 0.1)',\r\n '--shadow-outset': '0 2px 6px rgba(245, 158, 11, 0.2)',\r\n '--shadow-active': 'inset 0 1px 0 rgba(255, 255, 255, 0.3), inset 0 -1px 0 rgba(0, 0, 0, 0.2)',\r\n \r\n '--text-primary': '#92400e',\r\n '--text-secondary': '#b45309',\r\n '--text-muted': '#d97706',\r\n '--text-white': '#ffffff',\r\n \r\n '--bg-primary': '#fffbeb',\r\n '--bg-secondary': '#fef3c7',\r\n '--bg-content': '#ffffff',\r\n '--row-hover': '#fef3c7',\r\n \r\n '--transition-fast': '0.15s ease',\r\n '--transition-normal': '0.25s ease',\r\n '--transition-slow': '0.35s ease',\r\n \r\n '--font-family': \"'Comic Sans MS', cursive\",\r\n '--font-size-base': '12px',\r\n '--font-weight-normal': '400',\r\n '--font-weight-bold': '600'\r\n }\r\n },\r\n {\r\n id: 'apple',\r\n nameKey: 'theme.apple',\r\n descKey: 'theme.appleDesc',\r\n preview: '#007aff',\r\n cssVariables: {\r\n // Apple/macOS 风格主题变量\r\n '--primary': '#007aff',\r\n '--primary-dark': '#0051d5',\r\n '--primary-light': '#4da3ff',\r\n '--secondary': '#5856d6',\r\n \r\n '--bg-metal-light': 'linear-gradient(145deg, #fafafa, #f2f2f7)',\r\n '--bg-metal-normal': 'linear-gradient(145deg, #f2f2f7, #e5e5ea)',\r\n '--bg-metal-dark': 'linear-gradient(145deg, #e5e5ea, #d1d1d6)',\r\n '--bg-metal-pressed': 'linear-gradient(145deg, #d1d1d6, #f2f2f7)',\r\n \r\n '--bg-active': 'linear-gradient(145deg, #007aff, #0051d5)',\r\n '--bg-active-hover': 'linear-gradient(145deg, #4da3ff, #007aff)',\r\n '--bg-active-pressed': 'linear-gradient(145deg, #0051d5, #4da3ff)',\r\n \r\n '--border': '#d1d1d6',\r\n '--border-dark': '#c7c7cc',\r\n '--shadow-inset': 'inset 0 0.5px 0 rgba(255, 255, 255, 0.9), inset 0 -0.5px 0 rgba(0, 0, 0, 0.08)',\r\n '--shadow-outset': '0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.08)',\r\n '--shadow-active': 'inset 0 1px 0 rgba(255, 255, 255, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.2)',\r\n \r\n '--text-primary': '#000000',\r\n '--text-secondary': '#3c3c43',\r\n '--text-muted': '#8e8e93',\r\n '--text-white': '#ffffff',\r\n \r\n '--bg-primary': '#ffffff',\r\n '--bg-secondary': '#f2f2f7',\r\n '--bg-content': '#ffffff',\r\n '--row-hover': '#e8f4fd',\r\n \r\n '--transition-fast': '0.2s cubic-bezier(0.4, 0, 0.2, 1)',\r\n '--transition-normal': '0.3s cubic-bezier(0.4, 0, 0.2, 1)',\r\n '--transition-slow': '0.4s cubic-bezier(0.4, 0, 0.2, 1)',\r\n \r\n '--font-family': \"'-apple-system', 'BlinkMacSystemFont', 'SF Pro Text', 'Helvetica Neue', sans-serif\",\r\n '--font-size-base': '13px',\r\n '--font-weight-normal': '400',\r\n '--font-weight-bold': '600'\r\n }\r\n }\r\n];\r\n\r\nexport class GanttThemeManager {\r\n private static instance: GanttThemeManager;\r\n private currentTheme: string = 'metro';\r\n private storageKey = 'gantt-theme';\r\n private ganttContainer: HTMLElement | null = null;\r\n\r\n private constructor() {}\r\n\r\n static getInstance(): GanttThemeManager {\r\n if (!GanttThemeManager.instance) {\r\n GanttThemeManager.instance = new GanttThemeManager();\r\n }\r\n return GanttThemeManager.instance;\r\n }\r\n\r\n // 设置甘特图容器\r\n setGanttContainer(container: HTMLElement): void {\r\n console.log('Setting gantt container:', container);\r\n this.ganttContainer = container;\r\n this.loadTheme();\r\n }\r\n\r\n // 获取当前主题\r\n getCurrentTheme(): string {\r\n return this.currentTheme;\r\n }\r\n\r\n // 设置主题\r\n setTheme(themeId: string): void {\r\n const theme = ganttThemes.find(t => t.id === themeId);\r\n if (!theme) {\r\n console.warn(`Theme ${themeId} not found`);\r\n return;\r\n }\r\n\r\n this.currentTheme = themeId;\r\n this.applyTheme(theme);\r\n this.saveTheme();\r\n }\r\n\r\n // 应用主题到甘特图容器\r\n private applyTheme(theme: GanttTheme): void {\r\n if (!this.ganttContainer) {\r\n console.warn('No gantt container available for theme application');\r\n return;\r\n }\r\n\r\n console.log('Applying theme:', theme.id, 'to container:', this.ganttContainer);\r\n\r\n // 设置data-theme属性\r\n this.ganttContainer.setAttribute('data-gantt-theme', theme.id);\r\n\r\n // 应用CSS变量到甘特图容器\r\n Object.entries(theme.cssVariables).forEach(([property, value]) => {\r\n this.ganttContainer!.style.setProperty(property, value);\r\n });\r\n \r\n console.log('Theme applied successfully. Container styles:', this.ganttContainer.style.cssText);\r\n }\r\n\r\n // 从本地存储加载主题\r\n private loadTheme(): void {\r\n try {\r\n const savedTheme = localStorage.getItem(this.storageKey);\r\n if (savedTheme && ganttThemes.find(t => t.id === savedTheme)) {\r\n this.currentTheme = savedTheme;\r\n }\r\n \r\n const theme = ganttThemes.find(t => t.id === this.currentTheme);\r\n if (theme) {\r\n this.applyTheme(theme);\r\n }\r\n } catch (error) {\r\n console.warn('Failed to load theme from localStorage:', error);\r\n }\r\n }\r\n\r\n // 保存主题到本地存储\r\n private saveTheme(): void {\r\n try {\r\n localStorage.setItem(this.storageKey, this.currentTheme);\r\n } catch (error) {\r\n console.warn('Failed to save theme to localStorage:', error);\r\n }\r\n }\r\n\r\n // 获取所有主题\r\n getThemes(): GanttTheme[] {\r\n return ganttThemes;\r\n }\r\n\r\n // 获取主题信息\r\n getThemeInfo(themeId: string): GanttTheme | undefined {\r\n return ganttThemes.find(t => t.id === themeId);\r\n }\r\n\r\n // 预览主题(临时应用,不保存)\r\n previewTheme(themeId: string): void {\r\n const theme = ganttThemes.find(t => t.id === themeId);\r\n if (theme) {\r\n this.applyTheme(theme);\r\n }\r\n }\r\n\r\n // 取消预览,恢复当前主题\r\n cancelPreview(): void {\r\n const theme = ganttThemes.find(t => t.id === this.currentTheme);\r\n if (theme) {\r\n this.applyTheme(theme);\r\n }\r\n }\r\n\r\n // 导出主题配置\r\n exportThemeConfig(): string {\r\n return JSON.stringify({\r\n currentTheme: this.currentTheme,\r\n timestamp: new Date().toISOString()\r\n }, null, 2);\r\n }\r\n\r\n // 导入主题配置\r\n importThemeConfig(configJson: string): boolean {\r\n try {\r\n const config = JSON.parse(configJson);\r\n if (config.currentTheme && ganttThemes.find(t => t.id === config.currentTheme)) {\r\n this.setTheme(config.currentTheme);\r\n return true;\r\n }\r\n return false;\r\n } catch (error) {\r\n console.error('Failed to import theme config:', error);\r\n return false;\r\n }\r\n }\r\n}\r\n\r\n// 导出单例实例\r\nexport const ganttThemeManager = GanttThemeManager.getInstance();","<template>\r\n <div class=\"config-panel-wrapper\">\r\n <button \r\n class=\"config-btn\" \r\n @click=\"togglePanel\"\r\n :class=\"{ active: isOpen }\"\r\n :title=\"t('configPanel.title')\"\r\n >\r\n <div class=\"btn-content\">\r\n <div class=\"btn-icon\">\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"btn-text\">{{ t('common.config') }}</span>\r\n </div>\r\n </button>\r\n\r\n <transition name=\"panel-fade\">\r\n <div v-if=\"isOpen\" class=\"config-panel\" @click.stop>\r\n <div class=\"panel-header\">\r\n <h3>{{ t('configPanel.title') }}</h3>\r\n <button class=\"close-btn\" @click=\"closePanel\" :title=\"t('common.close')\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"panel-content\">\r\n <!-- 语言配置区域 -->\r\n <div class=\"config-section\">\r\n <h4 class=\"section-title\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z\"/>\r\n </svg>\r\n {{ t('configPanel.languageSettings') }}\r\n </h4>\r\n <div class=\"language-selector-inline\">\r\n <div\r\n v-for=\"locale in locales\"\r\n :key=\"locale.value\"\r\n class=\"language-option\"\r\n :class=\"{ active: currentLocale === locale.value }\"\r\n @click=\"selectLocale(locale.value)\"\r\n >\r\n <span class=\"lang-label\">{{ locale.label }}</span>\r\n <div v-if=\"currentLocale === locale.value\" class=\"lang-check\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 主题配置区域 -->\r\n <div class=\"config-section\">\r\n <h4 class=\"section-title\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z\"/>\r\n </svg>\r\n {{ t('configPanel.themeSettings') }}\r\n </h4>\r\n <div class=\"theme-grid\">\r\n <div\r\n v-for=\"theme in themes\"\r\n :key=\"theme.id\"\r\n class=\"theme-card\"\r\n :class=\"{ active: currentTheme === theme.id }\"\r\n @click=\"selectTheme(theme.id)\"\r\n >\r\n <div class=\"theme-preview\" :style=\"{ background: theme.preview }\"></div>\r\n <div class=\"theme-info\">\r\n <div class=\"theme-name\">{{ t(theme.nameKey) }}</div>\r\n <div class=\"theme-desc\">{{ t(theme.descKey) }}</div>\r\n </div>\r\n <div v-if=\"currentTheme === theme.id\" class=\"theme-check\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 连线配置区域 -->\r\n <div class=\"config-section\">\r\n <h4 class=\"section-title\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M6 9l6 6 6-6\"/>\r\n <circle cx=\"4\" cy=\"9\" r=\"2\"/>\r\n <circle cx=\"20\" cy=\"9\" r=\"2\"/>\r\n <path d=\"M10 9h4\"/>\r\n </svg>\r\n {{ t('configPanel.linkSettings') }}\r\n </h4>\r\n <div class=\"link-config-content\">\r\n <!-- 说明文字 -->\r\n <div class=\"config-info-box\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=\"flex-shrink: 0;\">\r\n <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\"/>\r\n </svg>\r\n <span>{{ t('configPanel.linkConfig.info') }}</span>\r\n </div>\r\n\r\n <!-- 路径类型选择 -->\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.pathType') }}</label>\r\n <div class=\"path-type-grid\">\r\n <div \r\n v-for=\"pathType in pathTypes\" \r\n :key=\"pathType.value\"\r\n class=\"path-type-card\"\r\n :class=\"{ active: linkConfig.pathType === pathType.value }\"\r\n @click=\"selectPathType(pathType.value)\"\r\n >\r\n <svg width=\"50\" height=\"30\" viewBox=\"0 0 60 40\">\r\n <path \r\n :d=\"pathType.preview\" \r\n stroke=\"currentColor\" \r\n stroke-width=\"2\" \r\n fill=\"none\"\r\n />\r\n </svg>\r\n <span class=\"path-name\">{{ pathType.name }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 基础样式配置 -->\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.color') }}</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.color\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.width') }}: {{ linkConfig.width }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.width\" \r\n @input=\"updateLinkConfig\"\r\n min=\"1\" \r\n max=\"5\" \r\n step=\"0.5\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.dashStyle') }}</label>\r\n <select v-model=\"linkConfig.dashArray\" @change=\"updateLinkConfig\" class=\"select-input\">\r\n <option :value=\"undefined\">{{ t('configPanel.linkConfig.solid') }}</option>\r\n <option value=\"3,3\">{{ t('configPanel.linkConfig.shortDash') }}</option>\r\n <option value=\"5,5\">{{ t('configPanel.linkConfig.mediumDash') }}</option>\r\n <option value=\"8,4\">{{ t('configPanel.linkConfig.longDash') }}</option>\r\n <option value=\"2,2,8,2\">{{ t('configPanel.linkConfig.dotDash') }}</option>\r\n </select>\r\n </div>\r\n\r\n <!-- 贝塞尔曲线配置 -->\r\n <div v-if=\"linkConfig.pathType === 'bezier'\" class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.curvature') }}: {{ linkConfig.bezierCurvature }}</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.bezierCurvature\" \r\n @input=\"updateLinkConfig\"\r\n min=\"0.1\" \r\n max=\"1\" \r\n step=\"0.1\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <!-- 直角连线配置 -->\r\n <template v-if=\"linkConfig.pathType === 'right-angle'\">\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.offset') }}: {{ linkConfig.rightAngleOffset }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.rightAngleOffset\" \r\n @input=\"updateLinkConfig\"\r\n min=\"10\" \r\n max=\"80\" \r\n step=\"5\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"linkConfig.smoothCorners\" \r\n @change=\"updateLinkConfig\"\r\n />\r\n {{ t('configPanel.linkConfig.smoothCorners') }}\r\n </label>\r\n </div>\r\n\r\n <div v-if=\"linkConfig.smoothCorners\" class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.cornerRadius') }}: {{ linkConfig.cornerRadius }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.cornerRadius\" \r\n @input=\"updateLinkConfig\"\r\n min=\"0\" \r\n max=\"15\" \r\n step=\"1\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n </template>\r\n\r\n <!-- 箭头配置 -->\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"linkConfig.showArrow\" \r\n @change=\"updateLinkConfig\"\r\n />\r\n {{ t('configPanel.linkConfig.showArrow') }}\r\n </label>\r\n </div>\r\n\r\n <template v-if=\"linkConfig.showArrow\">\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.arrowSize') }}: {{ linkConfig.arrowSize }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.arrowSize\" \r\n @input=\"updateLinkConfig\"\r\n min=\"4\" \r\n max=\"16\" \r\n step=\"1\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.arrowColor') }}</label>\r\n <div class=\"color-group\">\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.arrowColor\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input\"\r\n />\r\n <button \r\n @click=\"linkConfig.arrowColor = linkConfig.color; updateLinkConfig()\" \r\n class=\"sync-btn\"\r\n :title=\"t('tooltip.syncArrowColor')\"\r\n >\r\n {{ t('configPanel.linkConfig.syncColor') }}\r\n </button>\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- 虚线动画 -->\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"linkConfig.enableDashAnimation\" \r\n @change=\"updateLinkConfig\"\r\n />\r\n {{ t('configPanel.linkConfig.dashAnimation') }}\r\n </label>\r\n </div>\r\n\r\n <div v-if=\"linkConfig.enableDashAnimation\" class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.animationSpeed') }}: {{ linkConfig.dashAnimationSpeed }}s</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.dashAnimationSpeed\" \r\n @input=\"updateLinkConfig\"\r\n min=\"0.2\" \r\n max=\"3\" \r\n step=\"0.2\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <!-- 标签配置 -->\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"linkConfig.showLabels\" \r\n @change=\"updateLinkConfig\"\r\n />\r\n {{ t('configPanel.linkConfig.showLabels') }}\r\n </label>\r\n </div>\r\n\r\n <template v-if=\"linkConfig.showLabels\">\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.labelColor') }}</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.labelColor\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.fontSize') }}: {{ linkConfig.labelFontSize }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.labelFontSize\" \r\n @input=\"updateLinkConfig\"\r\n min=\"8\" \r\n max=\"16\" \r\n step=\"1\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n </template>\r\n\r\n <!-- 连线类型颜色配置 -->\r\n <div class=\"config-subsection\">\r\n <h5 class=\"subsection-title\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=\"margin-right: 4px;\">\r\n <path d=\"M19 15l-6 6-1.42-1.42L15.17 16H4V4h2v10h9.17l-3.59-3.58L13 9l6 6z\"/>\r\n </svg>\r\n {{ t('configPanel.linkConfig.typeColors') }}\r\n </h5>\r\n \r\n <div class=\"link-type-colors\">\r\n <div class=\"color-item\">\r\n <div class=\"color-preview\">\r\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\">\r\n <line x1=\"0\" y1=\"5\" x2=\"14\" y2=\"5\" :stroke=\"linkConfig.linkTypeColors.finishToStart\" stroke-width=\"2\"/>\r\n <polygon :points=\"'20,5 14,2 14,8'\" :fill=\"linkConfig.linkTypeColors.finishToStart\"/>\r\n </svg>\r\n </div>\r\n <span class=\"color-label\">{{ t('link.fs') }}</span>\r\n <span class=\"color-desc\">{{ t('link.finishToStart') }}</span>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.linkTypeColors.finishToStart\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input-small\"\r\n />\r\n </div>\r\n \r\n <div class=\"color-item\">\r\n <div class=\"color-preview\">\r\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\">\r\n <line x1=\"0\" y1=\"5\" x2=\"14\" y2=\"5\" :stroke=\"linkConfig.linkTypeColors.startToStart\" stroke-width=\"2\"/>\r\n <polygon :points=\"'20,5 14,2 14,8'\" :fill=\"linkConfig.linkTypeColors.startToStart\"/>\r\n </svg>\r\n </div>\r\n <span class=\"color-label\">{{ t('link.ss') }}</span>\r\n <span class=\"color-desc\">{{ t('link.startToStart') }}</span>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.linkTypeColors.startToStart\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input-small\"\r\n />\r\n </div>\r\n \r\n <div class=\"color-item\">\r\n <div class=\"color-preview\">\r\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\">\r\n <line x1=\"0\" y1=\"5\" x2=\"14\" y2=\"5\" :stroke=\"linkConfig.linkTypeColors.finishToFinish\" stroke-width=\"2\"/>\r\n <polygon :points=\"'20,5 14,2 14,8'\" :fill=\"linkConfig.linkTypeColors.finishToFinish\"/>\r\n </svg>\r\n </div>\r\n <span class=\"color-label\">{{ t('link.ff') }}</span>\r\n <span class=\"color-desc\">{{ t('link.finishToFinish') }}</span>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.linkTypeColors.finishToFinish\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input-small\"\r\n />\r\n </div>\r\n \r\n <div class=\"color-item\">\r\n <div class=\"color-preview\">\r\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\">\r\n <line x1=\"0\" y1=\"5\" x2=\"14\" y2=\"5\" :stroke=\"linkConfig.linkTypeColors.startToFinish\" stroke-width=\"2\"/>\r\n <polygon :points=\"'20,5 14,2 14,8'\" :fill=\"linkConfig.linkTypeColors.startToFinish\"/>\r\n </svg>\r\n </div>\r\n <span class=\"color-label\">{{ t('link.sf') }}</span>\r\n <span class=\"color-desc\">{{ t('link.startToFinish') }}</span>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.linkTypeColors.startToFinish\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input-small\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 父子关系样式 -->\r\n <div class=\"config-subsection\">\r\n <h5 class=\"subsection-title\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=\"margin-right: 4px;\">\r\n <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\"/>\r\n </svg>\r\n {{ t('configPanel.linkConfig.parentChildStyle') }}\r\n </h5>\r\n <div class=\"config-info-box\" style=\"margin-bottom: 12px;\">\r\n <span style=\"font-size: 11px;\">{{ t('configPanel.linkConfig.parentChildInfo') }}</span>\r\n </div>\r\n \r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.color') }}</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.parentChildStyle.color\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.width') }}: {{ linkConfig.parentChildStyle.width }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.parentChildStyle.width\" \r\n @input=\"updateLinkConfig\"\r\n min=\"1\" \r\n max=\"3\" \r\n step=\"0.5\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.dashStyle') }}</label>\r\n <select v-model=\"linkConfig.parentChildStyle.dashArray\" @change=\"updateLinkConfig\" class=\"select-input\">\r\n <option :value=\"undefined\">{{ t('configPanel.linkConfig.solid') }}</option>\r\n <option value=\"3,3\">{{ t('configPanel.linkConfig.shortDash') }}</option>\r\n <option value=\"5,5\">{{ t('configPanel.linkConfig.mediumDash') }}</option>\r\n <option value=\"8,4\">{{ t('configPanel.linkConfig.longDash') }}</option>\r\n </select>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </transition>\r\n\r\n <div v-if=\"isOpen\" class=\"panel-overlay\" @click=\"closePanel\"></div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, onMounted, watch, inject, computed, type Ref } from 'vue';\r\nimport { ganttThemes, ganttThemeManager, type GanttTheme } from './themes/GanttThemes';\r\nimport { useLinkConfig, LinkPathType } from './LinkConfig';\r\nimport { useI18n, type Locale } from './i18n';\r\n\r\nexport default defineComponent({\r\n name: 'GanttConfigPanel',\r\n setup() {\r\n const { t, locale, setLocale, getLocales } = useI18n();\r\n const isOpen = ref(false);\r\n const themes = ref<GanttTheme[]>(ganttThemes);\r\n const currentTheme = ref<string>('metro');\r\n \r\n // 语言选择器相关\r\n const currentLocale = computed(() => locale.value);\r\n const locales = computed(() => getLocales());\r\n \r\n const selectLocale = (localeValue: Locale) => {\r\n setLocale(localeValue);\r\n };\r\n \r\n // 注入甘特图容器引用\r\n const ganttContainer = inject<Ref<HTMLElement | undefined>>('ganttContainer');\r\n\r\n // 使用连线配置管理器\r\n const { config: linkConfigManager, updateConfig: updateLinkConfigManager } = useLinkConfig();\r\n\r\n // 连线配置 - 从管理器初始化\r\n const linkConfig = ref({\r\n pathType: linkConfigManager.pathType || LinkPathType.BEZIER,\r\n color: linkConfigManager.color || '#3498db',\r\n width: linkConfigManager.width || 2,\r\n dashArray: linkConfigManager.dashArray,\r\n bezierCurvature: linkConfigManager.bezierCurvature || 0.5,\r\n rightAngleOffset: linkConfigManager.rightAngleOffset || 40,\r\n smoothCorners: linkConfigManager.smoothCorners || false,\r\n cornerRadius: linkConfigManager.cornerRadius || 5,\r\n showArrow: linkConfigManager.showArrow !== undefined ? linkConfigManager.showArrow : true,\r\n arrowSize: linkConfigManager.arrowSize || 8,\r\n arrowColor: linkConfigManager.arrowColor || '#3498db',\r\n enableDashAnimation: linkConfigManager.enableDashAnimation || false,\r\n dashAnimationSpeed: linkConfigManager.dashAnimationSpeed || 1,\r\n showLabels: linkConfigManager.showLabels || false,\r\n labelColor: linkConfigManager.labelColor || '#333333',\r\n labelFontSize: linkConfigManager.labelFontSize || 12,\r\n parentChildStyle: {\r\n color: linkConfigManager.parentChildStyle?.color || '#999999',\r\n width: linkConfigManager.parentChildStyle?.width || 1.5,\r\n dashArray: linkConfigManager.parentChildStyle?.dashArray || '3,3'\r\n },\r\n linkTypeColors: {\r\n finishToStart: linkConfigManager.linkTypeColors?.finishToStart || '#3498db',\r\n startToStart: linkConfigManager.linkTypeColors?.startToStart || '#2ecc71',\r\n finishToFinish: linkConfigManager.linkTypeColors?.finishToFinish || '#e74c3c',\r\n startToFinish: linkConfigManager.linkTypeColors?.startToFinish || '#f39c12'\r\n },\r\n linkTypeVisibility: {\r\n finishToStart: linkConfigManager.linkTypeVisibility?.finishToStart ?? true,\r\n startToStart: linkConfigManager.linkTypeVisibility?.startToStart ?? true,\r\n finishToFinish: linkConfigManager.linkTypeVisibility?.finishToFinish ?? true,\r\n startToFinish: linkConfigManager.linkTypeVisibility?.startToFinish ?? true,\r\n parentChild: linkConfigManager.linkTypeVisibility?.parentChild ?? true\r\n }\r\n });\r\n\r\n // 路径类型 - 使用 computed 以响应语言变化\r\n const pathTypes = computed(() => [\r\n { value: LinkPathType.STRAIGHT, name: t('configPanel.linkConfig.straight'), preview: 'M 10 20 L 50 20' },\r\n { value: LinkPathType.BEZIER, name: t('configPanel.linkConfig.bezier'), preview: 'M 10 20 C 25 20 35 20 50 20' },\r\n { value: LinkPathType.RIGHT_ANGLE, name: t('configPanel.linkConfig.rightAngle'), preview: 'M 10 20 L 30 20 L 30 30 L 50 30' }\r\n ]);\r\n\r\n const togglePanel = () => {\r\n isOpen.value = !isOpen.value;\r\n };\r\n\r\n const closePanel = () => {\r\n isOpen.value = false;\r\n };\r\n\r\n const selectTheme = (themeId: string) => {\r\n currentTheme.value = themeId;\r\n ganttThemeManager.setTheme(themeId);\r\n };\r\n\r\n const selectPathType = (pathType: string) => {\r\n linkConfig.value.pathType = pathType as LinkPathType;\r\n updateLinkConfig();\r\n };\r\n\r\n const updateLinkConfig = () => {\r\n // 更新到连线配置管理器\r\n updateLinkConfigManager(linkConfig.value);\r\n console.log('Link config updated:', linkConfig.value);\r\n };\r\n\r\n onMounted(() => {\r\n // 设置甘特图容器到主题管理器\r\n if (ganttContainer?.value) {\r\n console.log('GanttConfigPanel: Setting gantt container to theme manager');\r\n ganttThemeManager.setGanttContainer(ganttContainer.value);\r\n } else {\r\n console.warn('GanttConfigPanel: ganttContainer not available');\r\n }\r\n \r\n currentTheme.value = ganttThemeManager.getCurrentTheme();\r\n });\r\n\r\n // 监听linkConfig的深层变化\r\n watch(linkConfig, (newConfig) => {\r\n updateLinkConfigManager(newConfig);\r\n }, { deep: true });\r\n\r\n return {\r\n t,\r\n isOpen,\r\n themes,\r\n currentTheme,\r\n linkConfig,\r\n pathTypes,\r\n currentLocale,\r\n locales,\r\n togglePanel,\r\n closePanel,\r\n selectTheme,\r\n selectPathType,\r\n selectLocale,\r\n updateLinkConfig\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.config-panel-wrapper {\r\n position: relative;\r\n}\r\n\r\n.config-btn {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: var(--shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.8));\r\n padding: 8px 16px;\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n font-family: var(--font-family);\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n\r\n &:hover {\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n }\r\n\r\n &:active, &.active {\r\n background: var(--bg-active, linear-gradient(145deg, #0078d4, #106ebe));\r\n \r\n .btn-icon, .btn-text {\r\n color: var(--text-white, #ffffff);\r\n }\r\n }\r\n\r\n .btn-content {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n }\r\n\r\n .btn-icon {\r\n color: var(--text-secondary, #666666);\r\n display: flex;\r\n align-items: center;\r\n transition: color var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n .btn-text {\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n transition: color var(--transition-fast, 0.15s ease);\r\n }\r\n}\r\n\r\n.panel-overlay {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background: rgba(0, 0, 0, 0.3);\r\n z-index: 999;\r\n}\r\n\r\n.config-panel {\r\n position: fixed;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n width: 90%;\r\n max-width: 1000px;\r\n max-height: 85vh;\r\n background: var(--bg-content, #ffffff);\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);\r\n z-index: 1000;\r\n display: flex;\r\n flex-direction: column;\r\n font-family: var(--font-family);\r\n}\r\n\r\n.panel-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 20px 24px;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border-bottom: 1px solid var(--border, #d0d0d0);\r\n\r\n h3 {\r\n margin: 0;\r\n font-size: 18px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n }\r\n\r\n .close-btn {\r\n background: transparent;\r\n border: none;\r\n cursor: pointer;\r\n padding: 4px;\r\n color: var(--text-secondary, #666666);\r\n transition: all var(--transition-fast, 0.15s ease);\r\n display: flex;\r\n align-items: center;\r\n\r\n &:hover {\r\n color: var(--primary, #0078d4);\r\n transform: scale(1.1);\r\n }\r\n }\r\n}\r\n\r\n.panel-content {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 24px;\r\n display: grid;\r\n grid-template-columns: 1fr 1fr;\r\n gap: 24px;\r\n}\r\n\r\n.config-section {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 16px;\r\n\r\n .section-title {\r\n margin: 0;\r\n font-size: 14px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding-bottom: 12px;\r\n border-bottom: 2px solid var(--border, #d0d0d0);\r\n\r\n svg {\r\n color: var(--primary, #0078d4);\r\n }\r\n }\r\n}\r\n\r\n.theme-grid {\r\n display: grid;\r\n grid-template-columns: 1fr;\r\n gap: 12px;\r\n}\r\n\r\n.theme-card {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n padding: 12px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 2px solid var(--border, #d0d0d0);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n position: relative;\r\n\r\n &:hover {\r\n border-color: var(--primary, #0078d4);\r\n transform: translateY(-2px);\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n &.active {\r\n border-color: var(--primary, #0078d4);\r\n background: var(--bg-content, #ffffff);\r\n box-shadow: 0 0 0 2px var(--primary, #0078d4), 0 2px 8px rgba(0, 120, 212, 0.15);\r\n \r\n .theme-info {\r\n .theme-name {\r\n color: var(--primary, #0078d4);\r\n }\r\n \r\n .theme-desc {\r\n color: var(--text-primary, #333333);\r\n }\r\n }\r\n }\r\n\r\n .theme-preview {\r\n width: 40px;\r\n height: 40px;\r\n border-radius: 4px;\r\n flex-shrink: 0;\r\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2);\r\n }\r\n\r\n .theme-info {\r\n flex: 1;\r\n min-width: 0;\r\n\r\n .theme-name {\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n margin-bottom: 4px;\r\n }\r\n\r\n .theme-desc {\r\n font-size: 11px;\r\n color: var(--text-secondary, #666666);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n }\r\n\r\n .theme-check {\r\n color: var(--primary, #0078d4);\r\n flex-shrink: 0;\r\n }\r\n}\r\n\r\n.language-selector-inline {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\r\n gap: 8px;\r\n \r\n .language-option {\r\n padding: 10px 12px;\r\n border: 1px solid var(--border, #d0d0d0);\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n box-shadow: var(--shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.8));\r\n\r\n &:hover {\r\n border-color: var(--primary, #0078d4);\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n transform: translateY(-1px);\r\n }\r\n\r\n &.active {\r\n border-color: var(--primary, #0078d4);\r\n background: var(--bg-content, #ffffff);\r\n box-shadow: 0 0 0 2px var(--primary, #0078d4), 0 2px 8px rgba(0, 120, 212, 0.15);\r\n \r\n .lang-label {\r\n color: var(--primary, #0078d4);\r\n font-weight: 600;\r\n }\r\n }\r\n\r\n .lang-label {\r\n font-size: 12px;\r\n flex: 1;\r\n color: var(--text-primary, #333333);\r\n }\r\n\r\n .lang-check {\r\n color: var(--primary, #0078d4);\r\n display: flex;\r\n align-items: center;\r\n margin-left: 8px;\r\n }\r\n }\r\n}\r\n\r\n.link-config-content {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 16px;\r\n\r\n .config-group {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n\r\n .config-label {\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n\r\n .color-input {\r\n width: 60px;\r\n height: 36px;\r\n border: 1px solid var(--border, #d0d0d0);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n\r\n &:hover {\r\n border-color: var(--primary, #0078d4);\r\n }\r\n }\r\n\r\n .range-input {\r\n width: 100%;\r\n height: 6px;\r\n -webkit-appearance: none;\r\n appearance: none;\r\n background: var(--bg-secondary, #e8e8e8);\r\n outline: none;\r\n border-radius: 3px;\r\n\r\n &::-webkit-slider-thumb {\r\n -webkit-appearance: none;\r\n appearance: none;\r\n width: 16px;\r\n height: 16px;\r\n background: var(--primary, #0078d4);\r\n cursor: pointer;\r\n border-radius: 50%;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n\r\n &:hover {\r\n transform: scale(1.2);\r\n }\r\n }\r\n\r\n &::-moz-range-thumb {\r\n width: 16px;\r\n height: 16px;\r\n background: var(--primary, #0078d4);\r\n cursor: pointer;\r\n border-radius: 50%;\r\n border: none;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n\r\n &:hover {\r\n transform: scale(1.2);\r\n }\r\n }\r\n }\r\n }\r\n\r\n .path-type-grid {\r\n display: grid;\r\n grid-template-columns: repeat(3, 1fr);\r\n gap: 8px;\r\n }\r\n\r\n .path-type-card {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 12px 8px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 2px solid var(--border, #d0d0d0);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n color: var(--text-secondary, #666666);\r\n\r\n &:hover {\r\n border-color: var(--primary, #0078d4);\r\n color: var(--primary, #0078d4);\r\n }\r\n\r\n &.active {\r\n border-color: var(--primary, #0078d4);\r\n background: var(--bg-content, #ffffff);\r\n box-shadow: 0 0 0 2px var(--primary, #0078d4), 0 2px 8px rgba(0, 120, 212, 0.15);\r\n \r\n .path-name {\r\n color: var(--primary, #0078d4);\r\n }\r\n }\r\n\r\n .path-name {\r\n font-size: 11px;\r\n font-weight: 600;\r\n }\r\n }\r\n\r\n .select-input {\r\n width: 100%;\r\n padding: 8px 12px;\r\n border: 1px solid var(--border, #d0d0d0);\r\n background: var(--bg-content, #ffffff);\r\n color: var(--text-primary, #333333);\r\n font-size: 12px;\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n\r\n &:hover {\r\n border-color: var(--primary, #0078d4);\r\n }\r\n\r\n &:focus {\r\n outline: none;\r\n border-color: var(--primary, #0078d4);\r\n box-shadow: 0 0 0 2px rgba(0, 120, 212, 0.1);\r\n }\r\n }\r\n\r\n .color-group {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n\r\n .sync-btn {\r\n padding: 6px 12px;\r\n font-size: 11px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n color: var(--text-primary, #333333);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n white-space: nowrap;\r\n\r\n &:hover {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border-color: var(--primary, #0078d4);\r\n }\r\n\r\n &:active {\r\n transform: scale(0.95);\r\n }\r\n }\r\n\r\n .config-subsection {\r\n margin-top: 16px;\r\n padding-top: 16px;\r\n border-top: 1px solid var(--border, #d0d0d0);\r\n\r\n .subsection-title {\r\n margin: 0 0 12px 0;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--text-secondary, #666666);\r\n display: flex;\r\n align-items: center;\r\n }\r\n }\r\n\r\n .config-info-box {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n background: var(--bg-secondary, #f8f9fa);\r\n border-left: 3px solid var(--primary, #0078d4);\r\n font-size: 11px;\r\n color: var(--text-secondary, #666666);\r\n line-height: 1.4;\r\n margin-bottom: 16px;\r\n\r\n svg {\r\n margin-top: 1px;\r\n color: var(--primary, #0078d4);\r\n }\r\n }\r\n\r\n .link-type-colors {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n\r\n .color-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 6px 10px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n border-radius: 4px;\r\n\r\n .color-preview {\r\n display: flex;\r\n align-items: center;\r\n width: 24px;\r\n }\r\n\r\n .color-label {\r\n font-size: 11px;\r\n font-weight: 700;\r\n color: var(--text-primary, #333333);\r\n min-width: 20px;\r\n }\r\n\r\n .color-desc {\r\n font-size: 11px;\r\n color: var(--text-secondary, #666666);\r\n flex: 1;\r\n }\r\n\r\n .color-input-small {\r\n width: 28px;\r\n height: 24px;\r\n border: 1px solid var(--border, #d0d0d0);\r\n border-radius: 3px;\r\n cursor: pointer;\r\n padding: 0;\r\n\r\n &::-webkit-color-swatch-wrapper {\r\n padding: 2px;\r\n }\r\n\r\n &::-webkit-color-swatch {\r\n border: none;\r\n border-radius: 2px;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n.panel-fade-enter-active,\r\n.panel-fade-leave-active {\r\n transition: opacity 0.2s ease;\r\n}\r\n\r\n.panel-fade-enter-from,\r\n.panel-fade-leave-to {\r\n opacity: 0;\r\n}\r\n</style>\r\n","<template>\r\n <div class=\"config-panel-wrapper\">\r\n <button \r\n class=\"config-btn\" \r\n @click=\"togglePanel\"\r\n :class=\"{ active: isOpen }\"\r\n :title=\"t('configPanel.title')\"\r\n >\r\n <div class=\"btn-content\">\r\n <div class=\"btn-icon\">\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"btn-text\">{{ t('common.config') }}</span>\r\n </div>\r\n </button>\r\n\r\n <transition name=\"panel-fade\">\r\n <div v-if=\"isOpen\" class=\"config-panel\" @click.stop>\r\n <div class=\"panel-header\">\r\n <h3>{{ t('configPanel.title') }}</h3>\r\n <button class=\"close-btn\" @click=\"closePanel\" :title=\"t('common.close')\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"panel-content\">\r\n <!-- 语言配置区域 -->\r\n <div class=\"config-section\">\r\n <h4 class=\"section-title\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z\"/>\r\n </svg>\r\n {{ t('configPanel.languageSettings') }}\r\n </h4>\r\n <div class=\"language-selector-inline\">\r\n <div\r\n v-for=\"locale in locales\"\r\n :key=\"locale.value\"\r\n class=\"language-option\"\r\n :class=\"{ active: currentLocale === locale.value }\"\r\n @click=\"selectLocale(locale.value)\"\r\n >\r\n <span class=\"lang-label\">{{ locale.label }}</span>\r\n <div v-if=\"currentLocale === locale.value\" class=\"lang-check\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 主题配置区域 -->\r\n <div class=\"config-section\">\r\n <h4 class=\"section-title\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z\"/>\r\n </svg>\r\n {{ t('configPanel.themeSettings') }}\r\n </h4>\r\n <div class=\"theme-grid\">\r\n <div\r\n v-for=\"theme in themes\"\r\n :key=\"theme.id\"\r\n class=\"theme-card\"\r\n :class=\"{ active: currentTheme === theme.id }\"\r\n @click=\"selectTheme(theme.id)\"\r\n >\r\n <div class=\"theme-preview\" :style=\"{ background: theme.preview }\"></div>\r\n <div class=\"theme-info\">\r\n <div class=\"theme-name\">{{ t(theme.nameKey) }}</div>\r\n <div class=\"theme-desc\">{{ t(theme.descKey) }}</div>\r\n </div>\r\n <div v-if=\"currentTheme === theme.id\" class=\"theme-check\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 连线配置区域 -->\r\n <div class=\"config-section\">\r\n <h4 class=\"section-title\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M6 9l6 6 6-6\"/>\r\n <circle cx=\"4\" cy=\"9\" r=\"2\"/>\r\n <circle cx=\"20\" cy=\"9\" r=\"2\"/>\r\n <path d=\"M10 9h4\"/>\r\n </svg>\r\n {{ t('configPanel.linkSettings') }}\r\n </h4>\r\n <div class=\"link-config-content\">\r\n <!-- 说明文字 -->\r\n <div class=\"config-info-box\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=\"flex-shrink: 0;\">\r\n <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\"/>\r\n </svg>\r\n <span>{{ t('configPanel.linkConfig.info') }}</span>\r\n </div>\r\n\r\n <!-- 路径类型选择 -->\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.pathType') }}</label>\r\n <div class=\"path-type-grid\">\r\n <div \r\n v-for=\"pathType in pathTypes\" \r\n :key=\"pathType.value\"\r\n class=\"path-type-card\"\r\n :class=\"{ active: linkConfig.pathType === pathType.value }\"\r\n @click=\"selectPathType(pathType.value)\"\r\n >\r\n <svg width=\"50\" height=\"30\" viewBox=\"0 0 60 40\">\r\n <path \r\n :d=\"pathType.preview\" \r\n stroke=\"currentColor\" \r\n stroke-width=\"2\" \r\n fill=\"none\"\r\n />\r\n </svg>\r\n <span class=\"path-name\">{{ pathType.name }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 基础样式配置 -->\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.color') }}</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.color\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.width') }}: {{ linkConfig.width }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.width\" \r\n @input=\"updateLinkConfig\"\r\n min=\"1\" \r\n max=\"5\" \r\n step=\"0.5\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.dashStyle') }}</label>\r\n <select v-model=\"linkConfig.dashArray\" @change=\"updateLinkConfig\" class=\"select-input\">\r\n <option :value=\"undefined\">{{ t('configPanel.linkConfig.solid') }}</option>\r\n <option value=\"3,3\">{{ t('configPanel.linkConfig.shortDash') }}</option>\r\n <option value=\"5,5\">{{ t('configPanel.linkConfig.mediumDash') }}</option>\r\n <option value=\"8,4\">{{ t('configPanel.linkConfig.longDash') }}</option>\r\n <option value=\"2,2,8,2\">{{ t('configPanel.linkConfig.dotDash') }}</option>\r\n </select>\r\n </div>\r\n\r\n <!-- 贝塞尔曲线配置 -->\r\n <div v-if=\"linkConfig.pathType === 'bezier'\" class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.curvature') }}: {{ linkConfig.bezierCurvature }}</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.bezierCurvature\" \r\n @input=\"updateLinkConfig\"\r\n min=\"0.1\" \r\n max=\"1\" \r\n step=\"0.1\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <!-- 直角连线配置 -->\r\n <template v-if=\"linkConfig.pathType === 'right-angle'\">\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.offset') }}: {{ linkConfig.rightAngleOffset }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.rightAngleOffset\" \r\n @input=\"updateLinkConfig\"\r\n min=\"10\" \r\n max=\"80\" \r\n step=\"5\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"linkConfig.smoothCorners\" \r\n @change=\"updateLinkConfig\"\r\n />\r\n {{ t('configPanel.linkConfig.smoothCorners') }}\r\n </label>\r\n </div>\r\n\r\n <div v-if=\"linkConfig.smoothCorners\" class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.cornerRadius') }}: {{ linkConfig.cornerRadius }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.cornerRadius\" \r\n @input=\"updateLinkConfig\"\r\n min=\"0\" \r\n max=\"15\" \r\n step=\"1\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n </template>\r\n\r\n <!-- 箭头配置 -->\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"linkConfig.showArrow\" \r\n @change=\"updateLinkConfig\"\r\n />\r\n {{ t('configPanel.linkConfig.showArrow') }}\r\n </label>\r\n </div>\r\n\r\n <template v-if=\"linkConfig.showArrow\">\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.arrowSize') }}: {{ linkConfig.arrowSize }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.arrowSize\" \r\n @input=\"updateLinkConfig\"\r\n min=\"4\" \r\n max=\"16\" \r\n step=\"1\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.arrowColor') }}</label>\r\n <div class=\"color-group\">\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.arrowColor\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input\"\r\n />\r\n <button \r\n @click=\"linkConfig.arrowColor = linkConfig.color; updateLinkConfig()\" \r\n class=\"sync-btn\"\r\n :title=\"t('tooltip.syncArrowColor')\"\r\n >\r\n {{ t('configPanel.linkConfig.syncColor') }}\r\n </button>\r\n </div>\r\n </div>\r\n </template>\r\n\r\n <!-- 虚线动画 -->\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"linkConfig.enableDashAnimation\" \r\n @change=\"updateLinkConfig\"\r\n />\r\n {{ t('configPanel.linkConfig.dashAnimation') }}\r\n </label>\r\n </div>\r\n\r\n <div v-if=\"linkConfig.enableDashAnimation\" class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.animationSpeed') }}: {{ linkConfig.dashAnimationSpeed }}s</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.dashAnimationSpeed\" \r\n @input=\"updateLinkConfig\"\r\n min=\"0.2\" \r\n max=\"3\" \r\n step=\"0.2\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <!-- 标签配置 -->\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"linkConfig.showLabels\" \r\n @change=\"updateLinkConfig\"\r\n />\r\n {{ t('configPanel.linkConfig.showLabels') }}\r\n </label>\r\n </div>\r\n\r\n <template v-if=\"linkConfig.showLabels\">\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.labelColor') }}</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.labelColor\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.fontSize') }}: {{ linkConfig.labelFontSize }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.labelFontSize\" \r\n @input=\"updateLinkConfig\"\r\n min=\"8\" \r\n max=\"16\" \r\n step=\"1\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n </template>\r\n\r\n <!-- 连线类型颜色配置 -->\r\n <div class=\"config-subsection\">\r\n <h5 class=\"subsection-title\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=\"margin-right: 4px;\">\r\n <path d=\"M19 15l-6 6-1.42-1.42L15.17 16H4V4h2v10h9.17l-3.59-3.58L13 9l6 6z\"/>\r\n </svg>\r\n {{ t('configPanel.linkConfig.typeColors') }}\r\n </h5>\r\n \r\n <div class=\"link-type-colors\">\r\n <div class=\"color-item\">\r\n <div class=\"color-preview\">\r\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\">\r\n <line x1=\"0\" y1=\"5\" x2=\"14\" y2=\"5\" :stroke=\"linkConfig.linkTypeColors.finishToStart\" stroke-width=\"2\"/>\r\n <polygon :points=\"'20,5 14,2 14,8'\" :fill=\"linkConfig.linkTypeColors.finishToStart\"/>\r\n </svg>\r\n </div>\r\n <span class=\"color-label\">{{ t('link.fs') }}</span>\r\n <span class=\"color-desc\">{{ t('link.finishToStart') }}</span>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.linkTypeColors.finishToStart\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input-small\"\r\n />\r\n </div>\r\n \r\n <div class=\"color-item\">\r\n <div class=\"color-preview\">\r\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\">\r\n <line x1=\"0\" y1=\"5\" x2=\"14\" y2=\"5\" :stroke=\"linkConfig.linkTypeColors.startToStart\" stroke-width=\"2\"/>\r\n <polygon :points=\"'20,5 14,2 14,8'\" :fill=\"linkConfig.linkTypeColors.startToStart\"/>\r\n </svg>\r\n </div>\r\n <span class=\"color-label\">{{ t('link.ss') }}</span>\r\n <span class=\"color-desc\">{{ t('link.startToStart') }}</span>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.linkTypeColors.startToStart\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input-small\"\r\n />\r\n </div>\r\n \r\n <div class=\"color-item\">\r\n <div class=\"color-preview\">\r\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\">\r\n <line x1=\"0\" y1=\"5\" x2=\"14\" y2=\"5\" :stroke=\"linkConfig.linkTypeColors.finishToFinish\" stroke-width=\"2\"/>\r\n <polygon :points=\"'20,5 14,2 14,8'\" :fill=\"linkConfig.linkTypeColors.finishToFinish\"/>\r\n </svg>\r\n </div>\r\n <span class=\"color-label\">{{ t('link.ff') }}</span>\r\n <span class=\"color-desc\">{{ t('link.finishToFinish') }}</span>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.linkTypeColors.finishToFinish\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input-small\"\r\n />\r\n </div>\r\n \r\n <div class=\"color-item\">\r\n <div class=\"color-preview\">\r\n <svg width=\"20\" height=\"10\" viewBox=\"0 0 20 10\">\r\n <line x1=\"0\" y1=\"5\" x2=\"14\" y2=\"5\" :stroke=\"linkConfig.linkTypeColors.startToFinish\" stroke-width=\"2\"/>\r\n <polygon :points=\"'20,5 14,2 14,8'\" :fill=\"linkConfig.linkTypeColors.startToFinish\"/>\r\n </svg>\r\n </div>\r\n <span class=\"color-label\">{{ t('link.sf') }}</span>\r\n <span class=\"color-desc\">{{ t('link.startToFinish') }}</span>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.linkTypeColors.startToFinish\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input-small\"\r\n />\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- 父子关系样式 -->\r\n <div class=\"config-subsection\">\r\n <h5 class=\"subsection-title\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=\"margin-right: 4px;\">\r\n <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z\"/>\r\n </svg>\r\n {{ t('configPanel.linkConfig.parentChildStyle') }}\r\n </h5>\r\n <div class=\"config-info-box\" style=\"margin-bottom: 12px;\">\r\n <span style=\"font-size: 11px;\">{{ t('configPanel.linkConfig.parentChildInfo') }}</span>\r\n </div>\r\n \r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.color') }}</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"linkConfig.parentChildStyle.color\" \r\n @change=\"updateLinkConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.width') }}: {{ linkConfig.parentChildStyle.width }}px</label>\r\n <input \r\n type=\"range\" \r\n v-model.number=\"linkConfig.parentChildStyle.width\" \r\n @input=\"updateLinkConfig\"\r\n min=\"1\" \r\n max=\"3\" \r\n step=\"0.5\"\r\n class=\"range-input\"\r\n />\r\n </div>\r\n\r\n <div class=\"config-group\">\r\n <label class=\"config-label\">{{ t('configPanel.linkConfig.dashStyle') }}</label>\r\n <select v-model=\"linkConfig.parentChildStyle.dashArray\" @change=\"updateLinkConfig\" class=\"select-input\">\r\n <option :value=\"undefined\">{{ t('configPanel.linkConfig.solid') }}</option>\r\n <option value=\"3,3\">{{ t('configPanel.linkConfig.shortDash') }}</option>\r\n <option value=\"5,5\">{{ t('configPanel.linkConfig.mediumDash') }}</option>\r\n <option value=\"8,4\">{{ t('configPanel.linkConfig.longDash') }}</option>\r\n </select>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </transition>\r\n\r\n <div v-if=\"isOpen\" class=\"panel-overlay\" @click=\"closePanel\"></div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, onMounted, watch, inject, computed, type Ref } from 'vue';\r\nimport { ganttThemes, ganttThemeManager, type GanttTheme } from './themes/GanttThemes';\r\nimport { useLinkConfig, LinkPathType } from './LinkConfig';\r\nimport { useI18n, type Locale } from './i18n';\r\n\r\nexport default defineComponent({\r\n name: 'GanttConfigPanel',\r\n setup() {\r\n const { t, locale, setLocale, getLocales } = useI18n();\r\n const isOpen = ref(false);\r\n const themes = ref<GanttTheme[]>(ganttThemes);\r\n const currentTheme = ref<string>('metro');\r\n \r\n // 语言选择器相关\r\n const currentLocale = computed(() => locale.value);\r\n const locales = computed(() => getLocales());\r\n \r\n const selectLocale = (localeValue: Locale) => {\r\n setLocale(localeValue);\r\n };\r\n \r\n // 注入甘特图容器引用\r\n const ganttContainer = inject<Ref<HTMLElement | undefined>>('ganttContainer');\r\n\r\n // 使用连线配置管理器\r\n const { config: linkConfigManager, updateConfig: updateLinkConfigManager } = useLinkConfig();\r\n\r\n // 连线配置 - 从管理器初始化\r\n const linkConfig = ref({\r\n pathType: linkConfigManager.pathType || LinkPathType.BEZIER,\r\n color: linkConfigManager.color || '#3498db',\r\n width: linkConfigManager.width || 2,\r\n dashArray: linkConfigManager.dashArray,\r\n bezierCurvature: linkConfigManager.bezierCurvature || 0.5,\r\n rightAngleOffset: linkConfigManager.rightAngleOffset || 40,\r\n smoothCorners: linkConfigManager.smoothCorners || false,\r\n cornerRadius: linkConfigManager.cornerRadius || 5,\r\n showArrow: linkConfigManager.showArrow !== undefined ? linkConfigManager.showArrow : true,\r\n arrowSize: linkConfigManager.arrowSize || 8,\r\n arrowColor: linkConfigManager.arrowColor || '#3498db',\r\n enableDashAnimation: linkConfigManager.enableDashAnimation || false,\r\n dashAnimationSpeed: linkConfigManager.dashAnimationSpeed || 1,\r\n showLabels: linkConfigManager.showLabels || false,\r\n labelColor: linkConfigManager.labelColor || '#333333',\r\n labelFontSize: linkConfigManager.labelFontSize || 12,\r\n parentChildStyle: {\r\n color: linkConfigManager.parentChildStyle?.color || '#999999',\r\n width: linkConfigManager.parentChildStyle?.width || 1.5,\r\n dashArray: linkConfigManager.parentChildStyle?.dashArray || '3,3'\r\n },\r\n linkTypeColors: {\r\n finishToStart: linkConfigManager.linkTypeColors?.finishToStart || '#3498db',\r\n startToStart: linkConfigManager.linkTypeColors?.startToStart || '#2ecc71',\r\n finishToFinish: linkConfigManager.linkTypeColors?.finishToFinish || '#e74c3c',\r\n startToFinish: linkConfigManager.linkTypeColors?.startToFinish || '#f39c12'\r\n },\r\n linkTypeVisibility: {\r\n finishToStart: linkConfigManager.linkTypeVisibility?.finishToStart ?? true,\r\n startToStart: linkConfigManager.linkTypeVisibility?.startToStart ?? true,\r\n finishToFinish: linkConfigManager.linkTypeVisibility?.finishToFinish ?? true,\r\n startToFinish: linkConfigManager.linkTypeVisibility?.startToFinish ?? true,\r\n parentChild: linkConfigManager.linkTypeVisibility?.parentChild ?? true\r\n }\r\n });\r\n\r\n // 路径类型 - 使用 computed 以响应语言变化\r\n const pathTypes = computed(() => [\r\n { value: LinkPathType.STRAIGHT, name: t('configPanel.linkConfig.straight'), preview: 'M 10 20 L 50 20' },\r\n { value: LinkPathType.BEZIER, name: t('configPanel.linkConfig.bezier'), preview: 'M 10 20 C 25 20 35 20 50 20' },\r\n { value: LinkPathType.RIGHT_ANGLE, name: t('configPanel.linkConfig.rightAngle'), preview: 'M 10 20 L 30 20 L 30 30 L 50 30' }\r\n ]);\r\n\r\n const togglePanel = () => {\r\n isOpen.value = !isOpen.value;\r\n };\r\n\r\n const closePanel = () => {\r\n isOpen.value = false;\r\n };\r\n\r\n const selectTheme = (themeId: string) => {\r\n currentTheme.value = themeId;\r\n ganttThemeManager.setTheme(themeId);\r\n };\r\n\r\n const selectPathType = (pathType: string) => {\r\n linkConfig.value.pathType = pathType as LinkPathType;\r\n updateLinkConfig();\r\n };\r\n\r\n const updateLinkConfig = () => {\r\n // 更新到连线配置管理器\r\n updateLinkConfigManager(linkConfig.value);\r\n console.log('Link config updated:', linkConfig.value);\r\n };\r\n\r\n onMounted(() => {\r\n // 设置甘特图容器到主题管理器\r\n if (ganttContainer?.value) {\r\n console.log('GanttConfigPanel: Setting gantt container to theme manager');\r\n ganttThemeManager.setGanttContainer(ganttContainer.value);\r\n } else {\r\n console.warn('GanttConfigPanel: ganttContainer not available');\r\n }\r\n \r\n currentTheme.value = ganttThemeManager.getCurrentTheme();\r\n });\r\n\r\n // 监听linkConfig的深层变化\r\n watch(linkConfig, (newConfig) => {\r\n updateLinkConfigManager(newConfig);\r\n }, { deep: true });\r\n\r\n return {\r\n t,\r\n isOpen,\r\n themes,\r\n currentTheme,\r\n linkConfig,\r\n pathTypes,\r\n currentLocale,\r\n locales,\r\n togglePanel,\r\n closePanel,\r\n selectTheme,\r\n selectPathType,\r\n selectLocale,\r\n updateLinkConfig\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.config-panel-wrapper {\r\n position: relative;\r\n}\r\n\r\n.config-btn {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: var(--shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.8));\r\n padding: 8px 16px;\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n font-family: var(--font-family);\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n\r\n &:hover {\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n }\r\n\r\n &:active, &.active {\r\n background: var(--bg-active, linear-gradient(145deg, #0078d4, #106ebe));\r\n \r\n .btn-icon, .btn-text {\r\n color: var(--text-white, #ffffff);\r\n }\r\n }\r\n\r\n .btn-content {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n }\r\n\r\n .btn-icon {\r\n color: var(--text-secondary, #666666);\r\n display: flex;\r\n align-items: center;\r\n transition: color var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n .btn-text {\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n transition: color var(--transition-fast, 0.15s ease);\r\n }\r\n}\r\n\r\n.panel-overlay {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background: rgba(0, 0, 0, 0.3);\r\n z-index: 999;\r\n}\r\n\r\n.config-panel {\r\n position: fixed;\r\n top: 50%;\r\n left: 50%;\r\n transform: translate(-50%, -50%);\r\n width: 90%;\r\n max-width: 1000px;\r\n max-height: 85vh;\r\n background: var(--bg-content, #ffffff);\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);\r\n z-index: 1000;\r\n display: flex;\r\n flex-direction: column;\r\n font-family: var(--font-family);\r\n}\r\n\r\n.panel-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 20px 24px;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border-bottom: 1px solid var(--border, #d0d0d0);\r\n\r\n h3 {\r\n margin: 0;\r\n font-size: 18px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n }\r\n\r\n .close-btn {\r\n background: transparent;\r\n border: none;\r\n cursor: pointer;\r\n padding: 4px;\r\n color: var(--text-secondary, #666666);\r\n transition: all var(--transition-fast, 0.15s ease);\r\n display: flex;\r\n align-items: center;\r\n\r\n &:hover {\r\n color: var(--primary, #0078d4);\r\n transform: scale(1.1);\r\n }\r\n }\r\n}\r\n\r\n.panel-content {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 24px;\r\n display: grid;\r\n grid-template-columns: 1fr 1fr;\r\n gap: 24px;\r\n}\r\n\r\n.config-section {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 16px;\r\n\r\n .section-title {\r\n margin: 0;\r\n font-size: 14px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding-bottom: 12px;\r\n border-bottom: 2px solid var(--border, #d0d0d0);\r\n\r\n svg {\r\n color: var(--primary, #0078d4);\r\n }\r\n }\r\n}\r\n\r\n.theme-grid {\r\n display: grid;\r\n grid-template-columns: 1fr;\r\n gap: 12px;\r\n}\r\n\r\n.theme-card {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n padding: 12px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 2px solid var(--border, #d0d0d0);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n position: relative;\r\n\r\n &:hover {\r\n border-color: var(--primary, #0078d4);\r\n transform: translateY(-2px);\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\r\n }\r\n\r\n &.active {\r\n border-color: var(--primary, #0078d4);\r\n background: var(--bg-content, #ffffff);\r\n box-shadow: 0 0 0 2px var(--primary, #0078d4), 0 2px 8px rgba(0, 120, 212, 0.15);\r\n \r\n .theme-info {\r\n .theme-name {\r\n color: var(--primary, #0078d4);\r\n }\r\n \r\n .theme-desc {\r\n color: var(--text-primary, #333333);\r\n }\r\n }\r\n }\r\n\r\n .theme-preview {\r\n width: 40px;\r\n height: 40px;\r\n border-radius: 4px;\r\n flex-shrink: 0;\r\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2);\r\n }\r\n\r\n .theme-info {\r\n flex: 1;\r\n min-width: 0;\r\n\r\n .theme-name {\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n margin-bottom: 4px;\r\n }\r\n\r\n .theme-desc {\r\n font-size: 11px;\r\n color: var(--text-secondary, #666666);\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n }\r\n\r\n .theme-check {\r\n color: var(--primary, #0078d4);\r\n flex-shrink: 0;\r\n }\r\n}\r\n\r\n.language-selector-inline {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\r\n gap: 8px;\r\n \r\n .language-option {\r\n padding: 10px 12px;\r\n border: 1px solid var(--border, #d0d0d0);\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n box-shadow: var(--shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.8));\r\n\r\n &:hover {\r\n border-color: var(--primary, #0078d4);\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n transform: translateY(-1px);\r\n }\r\n\r\n &.active {\r\n border-color: var(--primary, #0078d4);\r\n background: var(--bg-content, #ffffff);\r\n box-shadow: 0 0 0 2px var(--primary, #0078d4), 0 2px 8px rgba(0, 120, 212, 0.15);\r\n \r\n .lang-label {\r\n color: var(--primary, #0078d4);\r\n font-weight: 600;\r\n }\r\n }\r\n\r\n .lang-label {\r\n font-size: 12px;\r\n flex: 1;\r\n color: var(--text-primary, #333333);\r\n }\r\n\r\n .lang-check {\r\n color: var(--primary, #0078d4);\r\n display: flex;\r\n align-items: center;\r\n margin-left: 8px;\r\n }\r\n }\r\n}\r\n\r\n.link-config-content {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 16px;\r\n\r\n .config-group {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n\r\n .config-label {\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n\r\n .color-input {\r\n width: 60px;\r\n height: 36px;\r\n border: 1px solid var(--border, #d0d0d0);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n\r\n &:hover {\r\n border-color: var(--primary, #0078d4);\r\n }\r\n }\r\n\r\n .range-input {\r\n width: 100%;\r\n height: 6px;\r\n -webkit-appearance: none;\r\n appearance: none;\r\n background: var(--bg-secondary, #e8e8e8);\r\n outline: none;\r\n border-radius: 3px;\r\n\r\n &::-webkit-slider-thumb {\r\n -webkit-appearance: none;\r\n appearance: none;\r\n width: 16px;\r\n height: 16px;\r\n background: var(--primary, #0078d4);\r\n cursor: pointer;\r\n border-radius: 50%;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n\r\n &:hover {\r\n transform: scale(1.2);\r\n }\r\n }\r\n\r\n &::-moz-range-thumb {\r\n width: 16px;\r\n height: 16px;\r\n background: var(--primary, #0078d4);\r\n cursor: pointer;\r\n border-radius: 50%;\r\n border: none;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n\r\n &:hover {\r\n transform: scale(1.2);\r\n }\r\n }\r\n }\r\n }\r\n\r\n .path-type-grid {\r\n display: grid;\r\n grid-template-columns: repeat(3, 1fr);\r\n gap: 8px;\r\n }\r\n\r\n .path-type-card {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 12px 8px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 2px solid var(--border, #d0d0d0);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n color: var(--text-secondary, #666666);\r\n\r\n &:hover {\r\n border-color: var(--primary, #0078d4);\r\n color: var(--primary, #0078d4);\r\n }\r\n\r\n &.active {\r\n border-color: var(--primary, #0078d4);\r\n background: var(--bg-content, #ffffff);\r\n box-shadow: 0 0 0 2px var(--primary, #0078d4), 0 2px 8px rgba(0, 120, 212, 0.15);\r\n \r\n .path-name {\r\n color: var(--primary, #0078d4);\r\n }\r\n }\r\n\r\n .path-name {\r\n font-size: 11px;\r\n font-weight: 600;\r\n }\r\n }\r\n\r\n .select-input {\r\n width: 100%;\r\n padding: 8px 12px;\r\n border: 1px solid var(--border, #d0d0d0);\r\n background: var(--bg-content, #ffffff);\r\n color: var(--text-primary, #333333);\r\n font-size: 12px;\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n\r\n &:hover {\r\n border-color: var(--primary, #0078d4);\r\n }\r\n\r\n &:focus {\r\n outline: none;\r\n border-color: var(--primary, #0078d4);\r\n box-shadow: 0 0 0 2px rgba(0, 120, 212, 0.1);\r\n }\r\n }\r\n\r\n .color-group {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n }\r\n\r\n .sync-btn {\r\n padding: 6px 12px;\r\n font-size: 11px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n color: var(--text-primary, #333333);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n white-space: nowrap;\r\n\r\n &:hover {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border-color: var(--primary, #0078d4);\r\n }\r\n\r\n &:active {\r\n transform: scale(0.95);\r\n }\r\n }\r\n\r\n .config-subsection {\r\n margin-top: 16px;\r\n padding-top: 16px;\r\n border-top: 1px solid var(--border, #d0d0d0);\r\n\r\n .subsection-title {\r\n margin: 0 0 12px 0;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--text-secondary, #666666);\r\n display: flex;\r\n align-items: center;\r\n }\r\n }\r\n\r\n .config-info-box {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n background: var(--bg-secondary, #f8f9fa);\r\n border-left: 3px solid var(--primary, #0078d4);\r\n font-size: 11px;\r\n color: var(--text-secondary, #666666);\r\n line-height: 1.4;\r\n margin-bottom: 16px;\r\n\r\n svg {\r\n margin-top: 1px;\r\n color: var(--primary, #0078d4);\r\n }\r\n }\r\n\r\n .link-type-colors {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n\r\n .color-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 6px 10px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n border-radius: 4px;\r\n\r\n .color-preview {\r\n display: flex;\r\n align-items: center;\r\n width: 24px;\r\n }\r\n\r\n .color-label {\r\n font-size: 11px;\r\n font-weight: 700;\r\n color: var(--text-primary, #333333);\r\n min-width: 20px;\r\n }\r\n\r\n .color-desc {\r\n font-size: 11px;\r\n color: var(--text-secondary, #666666);\r\n flex: 1;\r\n }\r\n\r\n .color-input-small {\r\n width: 28px;\r\n height: 24px;\r\n border: 1px solid var(--border, #d0d0d0);\r\n border-radius: 3px;\r\n cursor: pointer;\r\n padding: 0;\r\n\r\n &::-webkit-color-swatch-wrapper {\r\n padding: 2px;\r\n }\r\n\r\n &::-webkit-color-swatch {\r\n border: none;\r\n border-radius: 2px;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n.panel-fade-enter-active,\r\n.panel-fade-leave-active {\r\n transition: opacity 0.2s ease;\r\n}\r\n\r\n.panel-fade-enter-from,\r\n.panel-fade-leave-to {\r\n opacity: 0;\r\n}\r\n</style>\r\n","import { z } from 'zod';\r\n \r\n// 定义 Zod Schema \r\nexport const ConfirmDateDataSchema = z.object({ \r\n date: z.string().regex(/^\\d{4}-\\d{2}-\\d{2}$/), // 格式如 YYYY-MM-DD \r\n year: z.number().int(), \r\n month: z.number().int().min(1).max(12), \r\n week: z.number().int().min(1).max(53), \r\n monthStr: z.string(), \r\n weekStr: z.string(), \r\n day: z.number().int().min(1).max(31), \r\n});\r\n // 生成 TypeScript 类型 \r\nexport type ConfirmDateData = z.infer<typeof ConfirmDateDataSchema>;","<template>\r\n <div class=\"page gantt-container\" ref=\"ganttContainer\">\r\n <div class=\"toolbar\">\r\n <div class=\"dateInput\">\r\n <DatePicker :date=\"startDate\" :min-date=\"minStartDate\" :max-date=\"maxStartDate\"\r\n @confirm=\"confirmStart\" />\r\n <span style=\"margin-right:20px;margin-left:20px;color:#606266\">{{ t('common.to') }}</span>\r\n <DatePicker :date=\"endDate\" :min-date=\"minEndDate\" :max-date=\"maxEndDate\" @confirm=\"confirmEnd\" />\r\n </div>\r\n <div class=\"buttonGroup\">\r\n <div :class=\"buttonClass[0]\" class=\"metro-btn\" @click=\"timeMode('月')\">\r\n <div class=\"metro-content\">\r\n <div class=\"metro-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z\"/>\r\n </svg>\r\n </div>\r\n <div class=\"metro-text\">{{ t('viewMode.month') }}</div>\r\n </div>\r\n </div>\r\n <div :class=\"buttonClass[1]\" class=\"metro-btn\" @click=\"timeMode('周')\">\r\n <div class=\"metro-content\">\r\n <div class=\"metro-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z\"/>\r\n </svg>\r\n </div>\r\n <div class=\"metro-text\">{{ t('viewMode.week') }}</div>\r\n </div>\r\n </div>\r\n <div :class=\"buttonClass[2]\" class=\"metro-btn\" @click=\"timeMode('日')\">\r\n <div class=\"metro-content\">\r\n <div class=\"metro-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 2 2h8c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 18H6V4h8v16z\"/>\r\n </svg>\r\n </div>\r\n <div class=\"metro-text\">{{ t('viewMode.day') }}</div>\r\n </div>\r\n </div>\r\n <div :class=\"buttonClass[3]\" class=\"metro-btn\" @click=\"timeMode('时')\">\r\n <div class=\"metro-content\">\r\n <div class=\"metro-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z\"/>\r\n </svg>\r\n </div>\r\n <div class=\"metro-text\">{{ t('viewMode.hour') }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n <!-- 连线类型图例 -->\r\n <div class=\"link-legend\">\r\n <div class=\"legend-title\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19 15l-6 6-1.42-1.42L15.17 16H4V4h2v10h9.17l-3.59-3.58L13 9l6 6z\"/>\r\n </svg>\r\n {{ t('link.legend') }}\r\n </div>\r\n <div class=\"legend-items\">\r\n <label class=\"legend-item\" :class=\"{ disabled: !linkTypeVisibility.parentChild }\" title=\"父子关系:显示任务的层级结构\">\r\n <input type=\"checkbox\" v-model=\"linkTypeVisibility.parentChild\" @change=\"updateLinkVisibility\" />\r\n <svg width=\"24\" height=\"12\" viewBox=\"0 0 24 12\">\r\n <line x1=\"0\" y1=\"6\" x2=\"18\" y2=\"6\" stroke=\"#95a5a6\" stroke-width=\"1.5\" stroke-dasharray=\"3,3\"/>\r\n <polygon points=\"24,6 18,3 18,9\" fill=\"#95a5a6\"/>\r\n </svg>\r\n <span class=\"legend-label\">{{ t('link.pc') }}</span>\r\n <span class=\"legend-desc\">{{ t('link.parentChild') }}</span>\r\n </label>\r\n <label class=\"legend-item\" :class=\"{ disabled: !linkTypeVisibility.finishToStart }\" title=\"完成-开始:前置任务完成后,后续任务才能开始\">\r\n <input type=\"checkbox\" v-model=\"linkTypeVisibility.finishToStart\" @change=\"updateLinkVisibility\" />\r\n <svg width=\"24\" height=\"12\" viewBox=\"0 0 24 12\">\r\n <line x1=\"0\" y1=\"6\" x2=\"18\" y2=\"6\" :stroke=\"linkTypeColors.finishToStart\" stroke-width=\"2\"/>\r\n <polygon points=\"24,6 18,3 18,9\" :fill=\"linkTypeColors.finishToStart\"/>\r\n </svg>\r\n <span class=\"legend-label\">{{ t('link.fs') }}</span>\r\n <span class=\"legend-desc\">{{ t('link.finishToStart') }}</span>\r\n </label>\r\n <label class=\"legend-item\" :class=\"{ disabled: !linkTypeVisibility.startToStart }\" title=\"开始-开始:两个任务同时开始\">\r\n <input type=\"checkbox\" v-model=\"linkTypeVisibility.startToStart\" @change=\"updateLinkVisibility\" />\r\n <svg width=\"24\" height=\"12\" viewBox=\"0 0 24 12\">\r\n <line x1=\"0\" y1=\"6\" x2=\"18\" y2=\"6\" :stroke=\"linkTypeColors.startToStart\" stroke-width=\"2\"/>\r\n <polygon points=\"24,6 18,3 18,9\" :fill=\"linkTypeColors.startToStart\"/>\r\n </svg>\r\n <span class=\"legend-label\">{{ t('link.ss') }}</span>\r\n <span class=\"legend-desc\">{{ t('link.startToStart') }}</span>\r\n </label>\r\n <label class=\"legend-item\" :class=\"{ disabled: !linkTypeVisibility.finishToFinish }\" title=\"完成-完成:两个任务同时完成\">\r\n <input type=\"checkbox\" v-model=\"linkTypeVisibility.finishToFinish\" @change=\"updateLinkVisibility\" />\r\n <svg width=\"24\" height=\"12\" viewBox=\"0 0 24 12\">\r\n <line x1=\"0\" y1=\"6\" x2=\"18\" y2=\"6\" :stroke=\"linkTypeColors.finishToFinish\" stroke-width=\"2\"/>\r\n <polygon points=\"24,6 18,3 18,9\" :fill=\"linkTypeColors.finishToFinish\"/>\r\n </svg>\r\n <span class=\"legend-label\">{{ t('link.ff') }}</span>\r\n <span class=\"legend-desc\">{{ t('link.finishToFinish') }}</span>\r\n </label>\r\n <label class=\"legend-item\" :class=\"{ disabled: !linkTypeVisibility.startToFinish }\" title=\"开始-完成:前置任务开始后,后续任务才能完成\">\r\n <input type=\"checkbox\" v-model=\"linkTypeVisibility.startToFinish\" @change=\"updateLinkVisibility\" />\r\n <svg width=\"24\" height=\"12\" viewBox=\"0 0 24 12\">\r\n <line x1=\"0\" y1=\"6\" x2=\"18\" y2=\"6\" :stroke=\"linkTypeColors.startToFinish\" stroke-width=\"2\"/>\r\n <polygon points=\"24,6 18,3 18,9\" :fill=\"linkTypeColors.startToFinish\"/>\r\n </svg>\r\n <span class=\"legend-label\">{{ t('link.sf') }}</span>\r\n <span class=\"legend-desc\">{{ t('link.startToFinish') }}</span>\r\n </label>\r\n </div>\r\n </div>\r\n <div class=\"config-buttons\">\r\n <GanttConfigPanel />\r\n </div>\r\n </div>\r\n <div class=\"gantt\">\r\n <SplitPane direction=\"row\" :min=\"0\" :max=\"100\" :triggerLength=\"10\"\r\n v-model:paneLengthPercent=\"paneLengthPercent\">\r\n <template #one>\r\n <TaskTable :headersHeight='styleConfig.headersHeight' :rowHeight='styleConfig.rowHeight'>\r\n </TaskTable>\r\n </template>\r\n <template #two>\r\n <RightTable ref='barContent' :headersHeight='styleConfig.headersHeight'\r\n :rowHeight='styleConfig.rowHeight'></RightTable>\r\n </template>\r\n </SplitPane>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { ref, defineComponent, computed, provide, onBeforeMount, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';\r\nimport dayjs from 'dayjs';\r\nimport customParseFormat from 'dayjs/plugin/customParseFormat';\r\nimport 'dayjs/locale/zh-cn';\r\nimport 'dayjs/locale/en';\r\nimport 'dayjs/locale/ja';\r\nimport 'dayjs/locale/ko';\r\nimport 'dayjs/locale/fr';\r\nimport 'dayjs/locale/de';\r\nimport 'dayjs/locale/es';\r\nimport 'dayjs/locale/ru';\r\ndayjs.extend(customParseFormat);\r\nimport { Symbols } from './Symbols';\r\nimport { linkDataManager, useLinkConfig } from './LinkConfig';\r\nimport { useI18n } from './i18n';\r\n// 导入日期选择器组件\r\nimport DatePicker from './DatePicker.vue';\r\n// 导入分割面板组件\r\nimport SplitPane from './SplitPane.vue';\r\nimport TaskTable from '../gantt/task/TaskTable.vue';\r\nimport RightTable from './RightTable.vue';\r\nimport GanttConfigPanel from './GanttConfigPanel.vue';\r\nimport { store, mutations } from './Store';\r\nexport type { DataConfig, StyleConfig, EventConfig, TaskHeader } from './Types';\r\n// 移除未使用的类型导入\r\nimport { type ConfirmDateData } from './ZodSchema';\r\n\r\n// 定义月份表头类型\r\ntype MonthHeaders = {\r\n title: string;\r\n width: number;\r\n}\r\n\r\n// 定义天表头类型\r\ntype DayHeaders = MonthHeaders & {\r\n fulldate: string;\r\n}\r\n\r\n// 定义周表头类型\r\ntype WeekHeaders = MonthHeaders & {\r\n fulldate: string;\r\n}\r\n\r\n// 定义小时表头类型\r\ntype HourHeaders = {\r\n title: string;\r\n width: number;\r\n}\r\n\r\n/**\r\n * Gantt 组件,用于展示甘特图。\r\n * 该组件接收样式配置、数据配置和事件配置作为属性。\r\n */\r\nexport default defineComponent({\r\n // 组件名称\r\n name: 'Gantt',\r\n props: {\r\n /**\r\n * 样式配置对象,包含表头高度和行高。\r\n * @type {{ headersHeight: number; rowHeight: number }}\r\n * @required\r\n * @default { headersHeight: 100, rowHeight: 60 }\r\n */\r\n styleConfig: {\r\n type: Object as () => {\r\n headersHeight: number;\r\n rowHeight: number;\r\n setBarColor: (row: Record<string, any>) => string;\r\n },\r\n required: true,\r\n default: () => ({\r\n // 表头高度\r\n headersHeight: 100,\r\n // 行高\r\n rowHeight: 60\r\n }),\r\n // 验证参数合法性\r\n validator: (value: { headersHeight: number; rowHeight: number }) => {\r\n return value.headersHeight > 0 && value.rowHeight > 0;\r\n }\r\n },\r\n /**\r\n * 数据配置对象,包含数据源、任务表头和字段映射函数。\r\n * @type {{ dataSource: any[]; taskHeaders: () => any[]; mapFields: () => any }}\r\n * @required\r\n * @default { dataSource: [], taskHeaders: () => [], mapFields: () => {} }\r\n */\r\n dataConfig: {\r\n type: Object as () => {\r\n dataSource: any[];\r\n taskHeaders: any[];\r\n mapFields: Record<string, any>;\r\n queryStartDate: string;\r\n queryEndDate: string;\r\n dependencies?: Omit<import('./Types').TaskDependency, 'id'>[];\r\n },\r\n required: true,\r\n default: () => ({\r\n dataSource: [],\r\n taskHeaders: [],\r\n mapFields: {}\r\n }),\r\n validator: (value: { dataSource: any[]; taskHeaders: any[]; mapFields: Record<string, any> }) => {\r\n return Array.isArray(value.dataSource) &&\r\n Array.isArray(value.taskHeaders) &&\r\n typeof value.mapFields === 'object' && value.mapFields !== null;\r\n }\r\n },\r\n /**\r\n * 事件配置对象,包含添加根任务、添加子任务、移除任务等事件处理函数。\r\n * @type {{\r\n * addRootTask: () => void;\r\n * addSubTask: (task: any) => void;\r\n * removeTask: (task: any) => void;\r\n * queryTask: (startDate: string, endDate: string, mode: string) => void;\r\n * barDate: (id: any, startDate: string, endDate: string) => void;\r\n * allowChangeTaskDate: (allow: boolean) => void;\r\n * }}\r\n * @required\r\n */\r\n eventConfig: {\r\n type: Object as () => {\r\n addRootTask: (row: Record<string, any> | null) => void;\r\n addSubTask: (task: any) => void;\r\n removeTask: (task: any) => void;\r\n editTask: (task: any) => void;\r\n queryTask: (startDate: string, endDate: string, mode: string) => void;\r\n barDate: (id: any, startDate: string, endDate: string) => void;\r\n allowChangeTaskDate: (allow: boolean) => void;\r\n updateProgress?: (detail: { taskId: any; oldProgress: number; newProgress: number; task: Record<string, any> }) => void;\r\n },\r\n required: true\r\n }\r\n },\r\n components: {\r\n DatePicker,\r\n SplitPane,\r\n TaskTable,\r\n RightTable,\r\n GanttConfigPanel\r\n },\r\n setup(props) {\r\n // 国际化\r\n const { t, locale } = useI18n();\r\n \r\n // 根据当前语言设置 dayjs locale\r\n const getDayjsLocale = () => {\r\n const localeMap: Record<string, string> = {\r\n 'zh-CN': 'zh-cn',\r\n 'en-US': 'en',\r\n 'ja-JP': 'ja',\r\n 'ko-KR': 'ko',\r\n 'fr-FR': 'fr',\r\n 'de-DE': 'de',\r\n 'es-ES': 'es',\r\n 'ru-RU': 'ru'\r\n };\r\n return localeMap[locale.value] || 'en';\r\n };\r\n \r\n // 缓存 mapFields 的结果\r\n const mapFields = computed(() => props.dataConfig.mapFields);\r\n // 缓存 dataSource 的结果\r\n const dataSource = computed(() => props.dataConfig.dataSource);\r\n\r\n // 连线配置\r\n const { config: linkConfig, updateConfig: updateLinkConfig } = useLinkConfig();\r\n\r\n // 连线类型显示控制\r\n const linkTypeVisibility = ref({\r\n finishToStart: linkConfig.linkTypeVisibility?.finishToStart ?? true,\r\n startToStart: linkConfig.linkTypeVisibility?.startToStart ?? true,\r\n finishToFinish: linkConfig.linkTypeVisibility?.finishToFinish ?? true,\r\n startToFinish: linkConfig.linkTypeVisibility?.startToFinish ?? true,\r\n parentChild: linkConfig.linkTypeVisibility?.parentChild ?? true\r\n });\r\n\r\n // 更新连线类型显示配置\r\n const updateLinkVisibility = () => {\r\n updateLinkConfig({\r\n linkTypeVisibility: { ...linkTypeVisibility.value }\r\n });\r\n };\r\n\r\n // 定义响应式数据\r\n const initData = ref<any[]>([]);\r\n const paneLengthPercent = ref(35);\r\n const buttonClass = ref(['button is-active', 'button', 'button', 'button']);\r\n const mode = ref('月');\r\n const startDate = ref(dayjs().locale(getDayjsLocale()).format('YYYY-MM-DD'));\r\n const minStartDate = ref(dayjs().locale(getDayjsLocale()).add(-5, 'y').format('YYYY-MM-DD'));\r\n const maxStartDate = ref(dayjs().locale(getDayjsLocale()).add(5, 'y').format('YYYY-MM-DD'));\r\n const showStartDatePicker = ref(false);\r\n const selectedStartDate = ref('点击选择日期');\r\n const endDate = ref(dayjs().locale(getDayjsLocale()).format('YYYY-MM-DD'));\r\n const minEndDate = ref(startDate.value);\r\n const maxEndDate = ref(dayjs(startDate.value).locale(getDayjsLocale()).add(5, 'y').format('YYYY-MM-DD'));\r\n const showEndDatePicker = ref(false);\r\n const selectedEndDate = ref('点击选择日期');\r\n const monthHeaders = ref<MonthHeaders[]>([]);\r\n const dayHeaders = ref<DayHeaders[]>([]);\r\n const weekHeaders = ref<WeekHeaders[]>([]);\r\n const hourHeaders = ref<HourHeaders[]>([]);\r\n const scale = ref(0);\r\n const timelineCellCount = ref(0);\r\n const startGanttDate = ref<string | null>(null);\r\n const endGanttDate = ref<string | null>(null);\r\n const result = ref('');\r\n \r\n // 甘特图容器引用\r\n const ganttContainer = ref<HTMLElement>();\r\n\r\n // 计算属性\r\n const subTask = computed(() => store.subTask);\r\n const editTask = computed(() => store.editTask);\r\n const removeTask = computed(() => store.removeTask);\r\n const rootTask = computed(() => store.rootTask);\r\n const allowChangeTaskDate = computed(() => store.allowChangeTaskDate);\r\n\r\n const setTimeLineHeaders = (newVal: string) => {\r\n const start = dayjs(selectedStartDate.value);\r\n const end = dayjs(selectedEndDate.value);\r\n // 开始时间格式是否合法\r\n if (!start.isValid()) {\r\n return;\r\n }\r\n // 结束时间格式是否合法\r\n if (!end.isValid()) {\r\n return;\r\n }\r\n // 检验开始时间结束时间范围的合法性\r\n const days = end.diff(start, 'day');\r\n if (days < 0) {\r\n return;\r\n }\r\n startGanttDate.value = selectedStartDate.value + ' 00:00:00';\r\n endGanttDate.value = selectedEndDate.value + ' 23:59:59';\r\n weekHeaders.value = [];\r\n dayHeaders.value = [];\r\n monthHeaders.value = [];\r\n hourHeaders.value = [];\r\n switch (newVal) {\r\n case '月': {\r\n scale.value = 80;\r\n const months: string[] = [];\r\n let current = start.startOf('month');\r\n while (current.isBefore(end) || current.isSame(end, 'month')) {\r\n months.push(current.format('YYYY-MM-DD'));\r\n current = current.add(1, 'month');\r\n }\r\n if (!months.some((item) => dayjs(item).format('YYYY-MM') === end.format('YYYY-MM'))) {\r\n months.push(end.format('YYYY-MM-DD'));\r\n }\r\n // 时间跨度只有一个月\r\n if (months.length === 1) {\r\n const days = end.diff(start, 'day') + 1;\r\n monthHeaders.value.push({\r\n title: start.locale(getDayjsLocale()).format('MMMM'),\r\n width: days * scale.value\r\n });\r\n } else {\r\n months.forEach((month, index) => {\r\n if (index === 0) {\r\n const endOfMonth = start.endOf('month').format('YYYY-MM-DD');\r\n const days = dayjs(endOfMonth).diff(start, 'day') + 1;\r\n monthHeaders.value.push({\r\n title: dayjs(month).locale(getDayjsLocale()).format('MMMM'),\r\n width: days * scale.value\r\n });\r\n } else if (index === months.length - 1) {\r\n const startOfMonth = end.startOf('month').format('YYYY-MM-DD');\r\n const days = end.diff(dayjs(startOfMonth), 'day') + 1;\r\n monthHeaders.value.push({\r\n title: dayjs(month).locale(getDayjsLocale()).format('MMMM'),\r\n width: days * scale.value\r\n });\r\n } else {\r\n const days = dayjs(month, 'YYYY-MM').daysInMonth();\r\n monthHeaders.value.push({\r\n title: dayjs(month).locale(getDayjsLocale()).format('MMMM'),\r\n width: days * scale.value\r\n });\r\n }\r\n });\r\n }\r\n\r\n let currentDate = start;\r\n while (currentDate.isBefore(end) || currentDate.isSame(end, 'day')) {\r\n // 中日韩语言需要添加“日”后缀\r\n const needsDaySuffix = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n const caption = needsDaySuffix\r\n ? currentDate.format('DD') + '日'\r\n : currentDate.format('DD');\r\n const fullDate = currentDate.format('YYYY-MM-DD');\r\n const week = currentDate.locale(getDayjsLocale()).format('dddd');\r\n weekHeaders.value.push({\r\n title: week,\r\n width: scale.value,\r\n fulldate: fullDate\r\n });\r\n dayHeaders.value.push({\r\n title: caption,\r\n width: scale.value,\r\n fulldate: fullDate\r\n });\r\n currentDate = currentDate.add(1, 'day');\r\n }\r\n timelineCellCount.value = dayHeaders.value.length;\r\n break;\r\n }\r\n case '周': {\r\n scale.value = 120;\r\n let currentDate = start.startOf('isoWeek'); // 从周一开始\r\n const endWeek = end.endOf('isoWeek'); // 到周日结束\r\n \r\n // 生成月份表头\r\n const months: string[] = [];\r\n let monthCurrent = currentDate.startOf('month');\r\n while (monthCurrent.isBefore(endWeek) || monthCurrent.isSame(endWeek, 'month')) {\r\n months.push(monthCurrent.format('YYYY-MM-DD'));\r\n monthCurrent = monthCurrent.add(1, 'month');\r\n }\r\n \r\n months.forEach((month, index) => {\r\n const monthStart = dayjs(month);\r\n const monthEnd = monthStart.endOf('month');\r\n \r\n // 计算该月包含的周数\r\n let weekCount = 0;\r\n let weekCurrent = currentDate.clone();\r\n while (weekCurrent.isBefore(endWeek) || weekCurrent.isSame(endWeek, 'week')) {\r\n const weekStart = weekCurrent.startOf('isoWeek');\r\n const weekEnd = weekCurrent.endOf('isoWeek');\r\n \r\n // 检查这一周是否与当前月份有交集\r\n if (weekStart.isSame(monthStart, 'month') || weekEnd.isSame(monthStart, 'month') ||\r\n (weekStart.isBefore(monthEnd) && weekEnd.isAfter(monthStart))) {\r\n weekCount++;\r\n }\r\n weekCurrent = weekCurrent.add(1, 'week');\r\n }\r\n \r\n if (weekCount > 0) {\r\n // 根据语言选择月份格式\r\n const isAsian = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n const monthTitle = isAsian\r\n ? monthStart.format('YYYY年MM月')\r\n : monthStart.locale(getDayjsLocale()).format('MMMM YYYY');\r\n monthHeaders.value.push({\r\n title: monthTitle,\r\n width: weekCount * scale.value\r\n });\r\n }\r\n });\r\n \r\n // 生成周表头(不生成日表头,周表头显示开始和结束日期)\r\n while (currentDate.isBefore(endWeek) || currentDate.isSame(endWeek, 'week')) {\r\n const weekStart = currentDate.startOf('isoWeek');\r\n const weekEnd = currentDate.endOf('isoWeek');\r\n \r\n // 周表头 - 显示周数和日期范围\r\n const isAsian = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n const weekTitle = isAsian\r\n ? `第${currentDate.isoWeek()}周 (${weekStart.format('MM/DD')}-${weekEnd.format('MM/DD')})`\r\n : `Week ${currentDate.isoWeek()} (${weekStart.format('MM/DD')}-${weekEnd.format('MM/DD')})`;\r\n weekHeaders.value.push({\r\n title: weekTitle,\r\n width: scale.value,\r\n fulldate: weekStart.format('YYYY-MM-DD')\r\n });\r\n \r\n currentDate = currentDate.add(1, 'week');\r\n }\r\n \r\n timelineCellCount.value = weekHeaders.value.length;\r\n break;\r\n }\r\n case '日': {\r\n scale.value = 80;\r\n let currentDate = start;\r\n while (currentDate.isBefore(end) || currentDate.isSame(end, 'day')) {\r\n // 中日韩语言需要添加“日”后缀\r\n const needsDaySuffix = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n const caption = needsDaySuffix\r\n ? currentDate.locale(getDayjsLocale()).format('MMMM DD') + '日'\r\n : currentDate.locale(getDayjsLocale()).format('MMMM DD');\r\n const fullDate = currentDate.format('YYYY-MM-DD');\r\n const week = currentDate.locale(getDayjsLocale()).format('dddd');\r\n weekHeaders.value.push({\r\n title: week,\r\n width: scale.value,\r\n fulldate: fullDate\r\n });\r\n dayHeaders.value.push({\r\n title: caption,\r\n width: scale.value,\r\n fulldate: fullDate\r\n });\r\n currentDate = currentDate.add(1, 'day');\r\n }\r\n timelineCellCount.value = dayHeaders.value.length;\r\n break;\r\n }\r\n case '时': {\r\n scale.value = 30;\r\n let currentDate = start;\r\n // 预先计算结束日期\r\n const endOfEndDay = end.endOf('day');\r\n while (currentDate.isBefore(endOfEndDay)) {\r\n // 中日韩语言需要添加“日”后缀\r\n const needsDaySuffix = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n const caption = needsDaySuffix\r\n ? currentDate.locale(getDayjsLocale()).format('MMMM DD') + '日'\r\n : currentDate.locale(getDayjsLocale()).format('MMMM DD');\r\n const fullDate = currentDate.format('YYYY-MM-DD');\r\n const week = currentDate.locale(getDayjsLocale()).format('dddd');\r\n weekHeaders.value.push({\r\n title: week,\r\n width: 24 * scale.value,\r\n fulldate: fullDate\r\n });\r\n dayHeaders.value.push({\r\n title: caption,\r\n width: 24 * scale.value,\r\n fulldate: fullDate\r\n });\r\n for (let i = 0; i <= 23; i++) {\r\n // 中日韩语言使用“点”,其他语言使用 :00 格式\r\n const needsHourSuffix = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n hourHeaders.value.push({\r\n title: needsHourSuffix ? i + '点' : `${i}:00`,\r\n width: scale.value\r\n });\r\n }\r\n // 优化代码:更新 currentDate\r\n currentDate = currentDate.add(1, 'day');\r\n }\r\n timelineCellCount.value = hourHeaders.value.length;\r\n break;\r\n }\r\n }\r\n // 选定日期后重新查询\r\n props.eventConfig.queryTask(selectedStartDate.value, selectedEndDate.value, mode.value);\r\n };\r\n\r\n const FindAllParent = (targetData: any[], pid: any) => {\r\n let parent = targetData.filter(obj => obj[mapFields.value['id']] === pid);\r\n if (parent && parent.length > 0) {\r\n result.value = parent[0].index + '.' + result.value;\r\n FindAllParent(targetData, parent[0][mapFields.value['parentId']]);\r\n }\r\n };\r\n\r\n const RecursionData = (id: any, tasks: any[], level: number) => {\r\n let findResult = tasks.filter(obj => obj[mapFields.value['parentId']] === id);\r\n if (findResult && findResult.length > 0) {\r\n level++;\r\n for (let i = 0; i < findResult.length; i++) {\r\n findResult[i].treeLevel = level;\r\n findResult[i].index = i + 1;\r\n\r\n let parent = initData.value.filter(obj => obj[mapFields.value['id']] === findResult[i][mapFields.value['parentId']]);\r\n result.value = '';\r\n if (parent && parent.length > 0) {\r\n result.value = parent[0].index + '.' + findResult[i].index;\r\n FindAllParent(initData.value, parent[0][mapFields.value['parentId']]);\r\n findResult[i].no = result.value;\r\n } else {\r\n findResult[i].no = i + 1 + '';\r\n }\r\n initData.value.push(findResult[i]);\r\n RecursionData(findResult[i][mapFields.value['id']], tasks, level);\r\n }\r\n }\r\n };\r\n\r\n const timeMode = (_mode: string) => {\r\n // 更新按钮状态\r\n for (let i = 0; i < buttonClass.value.length; i++) {\r\n buttonClass.value[i] = 'button';\r\n }\r\n\r\n switch (_mode) {\r\n case '月': {\r\n buttonClass.value[0] = 'button is-active';\r\n break;\r\n }\r\n case '周': {\r\n buttonClass.value[1] = 'button is-active';\r\n break;\r\n }\r\n case '日': {\r\n buttonClass.value[2] = 'button is-active';\r\n break;\r\n }\r\n case '时': {\r\n buttonClass.value[3] = 'button is-active';\r\n break;\r\n }\r\n }\r\n \r\n // 先设置mode,触发响应式更新\r\n mode.value = _mode;\r\n \r\n // 等待DOM更新完成后再滚动\r\n nextTick(() => {\r\n const barContentEl = document.querySelector('.table .content') as HTMLElement;\r\n if (barContentEl) {\r\n barContentEl.scrollLeft = 0;\r\n }\r\n });\r\n };\r\n\r\n const confirmStart = (value: ConfirmDateData) => {\r\n let days = dayjs(endDate.value).diff(dayjs(value.date), 'days')\r\n if (days < 0) {\r\n selectedEndDate.value = value.date\r\n endDate.value = value.date\r\n }\r\n showStartDatePicker.value = false\r\n selectedStartDate.value = value.date\r\n startDate.value = value.date\r\n minEndDate.value = value.date\r\n };\r\n\r\n const confirmEnd = (value: ConfirmDateData) => {\r\n let days = dayjs(value.date).diff(dayjs(startDate.value), 'days')\r\n if (days < 0) {\r\n selectedStartDate.value = dayjs(value.date).format('YYYY-MM-DD');\r\n startDate.value = dayjs(value.date).format('YYYY-MM-DD');\r\n }\r\n showEndDatePicker.value = false\r\n selectedEndDate.value = value.date\r\n endDate.value = value.date\r\n maxStartDate.value = value.date\r\n };\r\n\r\n // 监听 mode 和日期的变化\r\n watch([mode, selectedStartDate, selectedEndDate], ([newMode, newStartDate, newEndDate], [oldMode, oldStartDate, oldEndDate]) => {\r\n if (newMode !== oldMode || newStartDate !== oldStartDate || newEndDate !== oldEndDate) {\r\n setTimeLineHeaders(newMode);\r\n }\r\n });\r\n \r\n // 监听语言变化,重新生成时间轴表头\r\n watch(locale, () => {\r\n setTimeLineHeaders(mode.value);\r\n });\r\n\r\n watch(rootTask, (newVal) => { \r\n props.eventConfig.addRootTask(newVal);\r\n });\r\n\r\n watch(subTask, (newVal) => {\r\n props.eventConfig.addSubTask(newVal);\r\n });\r\n\r\n watch(removeTask, (newVal) => {\r\n props.eventConfig.removeTask(newVal);\r\n });\r\n\r\n watch(editTask, (newVal) => {\r\n props.eventConfig.editTask(newVal);\r\n });\r\n\r\n watch(allowChangeTaskDate, (newVal) => {\r\n props.eventConfig.allowChangeTaskDate(newVal);\r\n });\r\n\r\n // 优化:拆分watchEffect,避免不必要的触发\r\n watch(() => store.barDate, (barDate) => {\r\n if (barDate) {\r\n const { id, startDate, endDate } = barDate;\r\n if (id && startDate && endDate) {\r\n props.eventConfig.barDate(id, startDate, endDate);\r\n }\r\n }\r\n });\r\n\r\n watch(scale, (newScale) => {\r\n mutations.setScale(newScale);\r\n });\r\n\r\n watch(() => props.dataConfig.taskHeaders, (newHeaders) => {\r\n mutations.setTaskHeaders(newHeaders);\r\n });\r\n\r\n watch([monthHeaders, dayHeaders, weekHeaders, hourHeaders], ([newMonth, newDay, newWeek, newHour]) => {\r\n mutations.setMonthHeaders(newMonth);\r\n mutations.setDayHeaders(newDay);\r\n mutations.setWeekHeaders(newWeek);\r\n mutations.setHourHeaders(newHour);\r\n });\r\n\r\n watch(mode, (newMode) => {\r\n mutations.setMode(newMode);\r\n });\r\n\r\n watch(mapFields, (newFields) => {\r\n if (newFields) {\r\n mutations.setMapFields(newFields);\r\n }\r\n });\r\n\r\n watch(() => props.dataConfig.queryStartDate, (newStartDate) => {\r\n if (newStartDate) {\r\n mutations.setStartGanttDate(dayjs(newStartDate).toDate());\r\n startGanttDate.value = newStartDate;\r\n selectedStartDate.value = newStartDate;\r\n startDate.value = newStartDate;\r\n }\r\n });\r\n\r\n watch(() => props.dataConfig.queryEndDate, (newEndDate) => {\r\n if (newEndDate) {\r\n mutations.setEndGanttDate(dayjs(newEndDate).toDate());\r\n endGanttDate.value = newEndDate;\r\n selectedEndDate.value = newEndDate;\r\n endDate.value = newEndDate;\r\n }\r\n });\r\n\r\n watch(timelineCellCount, (newCount) => {\r\n if (newCount) {\r\n mutations.setTimelineCellCount(newCount);\r\n }\r\n });\r\n\r\n onBeforeMount(() => {\r\n mutations.setMonthHeaders(monthHeaders.value)\r\n mutations.setWeekHeaders(weekHeaders.value)\r\n mutations.setDayHeaders(dayHeaders.value)\r\n mutations.setHourHeaders(hourHeaders.value)\r\n mutations.setTaskHeaders(props.dataConfig.taskHeaders)\r\n mutations.setMapFields(mapFields.value)\r\n mutations.setTimelineCellCount(timelineCellCount.value)\r\n // 初始化时如果有数据,先设置\r\n if (dataSource.value && dataSource.value.length > 0) {\r\n mutations.setTasks(dataSource.value)\r\n }\r\n });\r\n\r\n // 进度更新事件处理\r\n const handleProgressUpdate = (event: Event) => {\r\n const customEvent = event as CustomEvent;\r\n if (props.eventConfig.updateProgress) {\r\n props.eventConfig.updateProgress(customEvent.detail);\r\n }\r\n };\r\n\r\n onMounted(() => {\r\n monthHeaders.value = [];\r\n weekHeaders.value = [];\r\n dayHeaders.value = [];\r\n hourHeaders.value = [];\r\n\r\n console.log('Gantt onMounted, dataSource:', dataSource.value);\r\n let level: number = 0;\r\n RecursionData('0', dataSource.value, level);\r\n mutations.setTasks(initData.value);\r\n console.log('initData after RecursionData:', initData.value);\r\n nextTick(() => {\r\n mode.value = '月';\r\n mutations.setMode(mode.value)\r\n });\r\n \r\n // 监听进度更新事件\r\n window.addEventListener('taskProgressUpdate', handleProgressUpdate);\r\n });\r\n \r\n // 优化:监听dataSource变化,使用节流避免频繁更新\r\n let updateTimer: ReturnType<typeof setTimeout> | null = null;\r\n watch(dataSource, (newVal) => {\r\n console.log('dataSource changed:', newVal);\r\n if (newVal && newVal.length > 0) {\r\n // 使用节流,避免频繁更新\r\n if (updateTimer) {\r\n clearTimeout(updateTimer);\r\n }\r\n updateTimer = setTimeout(() => {\r\n initData.value = [];\r\n let level: number = 0;\r\n RecursionData('0', newVal, level);\r\n mutations.setTasks(initData.value);\r\n console.log('Tasks updated:', initData.value);\r\n updateTimer = null;\r\n }, 100);\r\n } else if (newVal && newVal.length === 0) {\r\n // 如果数据为空,也要更新\r\n mutations.setTasks([]);\r\n }\r\n }, { immediate: false });\r\n\r\n onBeforeUnmount(() => {\r\n // 清理进度更新事件监听\r\n window.removeEventListener('taskProgressUpdate', handleProgressUpdate);\r\n });\r\n\r\n provide(Symbols.AddRootTaskSymbol, (row: Record<string, any>) => {\r\n return props.eventConfig.addRootTask(row);\r\n });\r\n\r\n // 设置Bar的颜色,传递到子组件\r\n provide(Symbols.SetBarColorSymbol, (row: Record<string, any>) => {\r\n return props.styleConfig.setBarColor(row);\r\n });\r\n \r\n // 提供甘特图容器引用给主题选择器\r\n provide('ganttContainer', ganttContainer);\r\n\r\n // 监听依赖关系变化\r\n watch(() => props.dataConfig.dependencies, (newDependencies) => {\r\n if (newDependencies && newDependencies.length > 0) {\r\n console.log('Loading dependencies:', newDependencies);\r\n // 清空现有依赖关系\r\n linkDataManager.clear();\r\n // 添加新的依赖关系\r\n newDependencies.forEach(dep => {\r\n linkDataManager.addDependency(dep);\r\n });\r\n }\r\n }, { immediate: true });\r\n\r\n // 连线配置变化处理\r\n const onLinkConfigChange = (config: any) => {\r\n console.log('连线配置已更新:', config);\r\n // 这里可以添加额外的处理逻辑,比如通知其他组件更新\r\n };\r\n\r\n // 连线类型颜色(从配置中读取,用于图例显示)\r\n const linkTypeColors = computed(() => ({\r\n finishToStart: linkConfig.linkTypeColors?.finishToStart || '#3498db',\r\n startToStart: linkConfig.linkTypeColors?.startToStart || '#2ecc71',\r\n finishToFinish: linkConfig.linkTypeColors?.finishToFinish || '#e74c3c',\r\n startToFinish: linkConfig.linkTypeColors?.startToFinish || '#f39c12'\r\n }));\r\n\r\n return {\r\n t,\r\n subTask,\r\n editTask,\r\n removeTask,\r\n rootTask,\r\n allowChangeTaskDate,\r\n paneLengthPercent,\r\n startDate,\r\n endDate,\r\n minStartDate,\r\n maxStartDate,\r\n confirmStart,\r\n minEndDate,\r\n maxEndDate,\r\n confirmEnd,\r\n buttonClass,\r\n timeMode,\r\n onLinkConfigChange,\r\n ganttContainer,\r\n linkTypeColors,\r\n linkTypeVisibility,\r\n updateLinkVisibility\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n$toolbarHeight: 70px;\r\n\r\n.page {\r\n height: 100%;\r\n width: 100%;\r\n overflow: hidden;\r\n display: flex;\r\n flex-direction: column;\r\n\r\n .toolbar {\r\n height: $toolbarHeight;\r\n width: 100%;\r\n display: flex;\r\n flex-direction: row;\r\n align-items: center;\r\n justify-content: flex-start;\r\n padding: calc($toolbarHeight / 2);\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border-bottom: 1px solid var(--border, #d0d0d0);\r\n transition: all var(--transition-normal, 0.25s ease);\r\n\r\n .dateInput {\r\n cursor: pointer;\r\n height: calc($toolbarHeight / 1.5);\r\n width: 450px;\r\n display: flex;\r\n flex-direction: row;\r\n align-items: center;\r\n justify-content: center;\r\n margin-right: 20px;\r\n border-radius: 5px;\r\n color: var(--primary, #0078d4);\r\n font-size: 14px;\r\n transition: color var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n .buttonGroup {\r\n height: calc($toolbarHeight / 1.5);\r\n display: flex;\r\n flex-direction: row;\r\n margin-right: 20px;\r\n background: var(--bg-metal-normal);\r\n border: 1px solid var(--border);\r\n box-shadow: var(--shadow-inset), var(--shadow-outset);\r\n border-radius: 2px;\r\n overflow: hidden;\r\n transition: all var(--transition-normal);\r\n\r\n .metro-btn {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 80px;\r\n height: 100%;\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border-right: 1px solid var(--border, #d0d0d0);\r\n \r\n &:last-child {\r\n border-right: none;\r\n }\r\n\r\n &::before {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f0f0f0));\r\n opacity: 0;\r\n transition: opacity var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n &::after {\r\n content: '';\r\n position: absolute;\r\n top: 2px;\r\n left: 2px;\r\n right: 2px;\r\n bottom: 2px;\r\n background: var(--bg-metal-pressed, linear-gradient(145deg, #e0e0e0, #f8f8f8));\r\n opacity: 0;\r\n transition: opacity var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n .metro-content {\r\n position: relative;\r\n z-index: 3;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 4px;\r\n }\r\n\r\n .metro-icon {\r\n color: var(--text-secondary, #666666);\r\n transition: color var(--transition-fast, 0.15s ease);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n\r\n .metro-text {\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--text-secondary, #555555);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n transition: color var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n &:hover {\r\n &::before {\r\n opacity: 1;\r\n }\r\n\r\n .metro-icon {\r\n color: var(--text-primary, #333333);\r\n }\r\n\r\n .metro-text {\r\n color: var(--text-primary, #333333);\r\n }\r\n }\r\n\r\n &:active {\r\n &::after {\r\n opacity: 1;\r\n }\r\n }\r\n\r\n // 激活状态\r\n &.button.is-active,\r\n &.is-active {\r\n background: linear-gradient(145deg, #0078d4, #106ebe);\r\n box-shadow: \r\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\r\n inset 0 -1px 0 rgba(0, 0, 0, 0.3),\r\n 0 1px 2px rgba(0, 0, 0, 0.2);\r\n\r\n &::before {\r\n background: linear-gradient(145deg, #1084d8, #0d5aa7);\r\n opacity: 0;\r\n }\r\n\r\n &::after {\r\n background: linear-gradient(145deg, #0d5aa7, #1084d8);\r\n opacity: 0;\r\n }\r\n\r\n .metro-icon {\r\n color: #ffffff;\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n }\r\n\r\n .metro-text {\r\n color: #ffffff;\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n font-weight: 700;\r\n }\r\n\r\n &:hover {\r\n &::before {\r\n opacity: 1;\r\n }\r\n }\r\n\r\n &:active {\r\n &::after {\r\n opacity: 1;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 兼容旧的class名称\r\n .button {\r\n @extend .metro-btn;\r\n }\r\n }\r\n \r\n .link-legend {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n padding: 6px 16px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n border-radius: 4px;\r\n margin-right: 16px;\r\n\r\n .legend-title {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--text-secondary, #666666);\r\n padding-right: 12px;\r\n border-right: 1px solid var(--border, #d0d0d0);\r\n \r\n svg {\r\n color: var(--primary, #0078d4);\r\n }\r\n }\r\n\r\n .legend-items {\r\n display: flex;\r\n gap: 12px;\r\n }\r\n\r\n .legend-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n cursor: pointer;\r\n padding: 2px 6px;\r\n border-radius: 3px;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n\r\n input[type=\"checkbox\"] {\r\n width: 14px;\r\n height: 14px;\r\n cursor: pointer;\r\n accent-color: var(--primary, #0078d4);\r\n margin: 0;\r\n }\r\n\r\n &:hover {\r\n background: var(--bg-secondary, #e8e8e8);\r\n }\r\n\r\n &.disabled {\r\n opacity: 0.5;\r\n \r\n svg {\r\n opacity: 0.4;\r\n }\r\n \r\n .legend-label,\r\n .legend-desc {\r\n text-decoration: line-through;\r\n }\r\n }\r\n\r\n .legend-label {\r\n font-size: 10px;\r\n font-weight: 700;\r\n color: var(--text-primary, #333333);\r\n min-width: 18px;\r\n }\r\n\r\n .legend-desc {\r\n font-size: 10px;\r\n color: var(--text-secondary, #666666);\r\n white-space: nowrap;\r\n }\r\n }\r\n }\r\n\r\n .config-buttons {\r\n display: flex;\r\n gap: 12px;\r\n margin-left: auto;\r\n padding: 0 8px;\r\n }\r\n \r\n .link-config-btn {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n padding: 10px 16px;\r\n background: linear-gradient(135deg, \r\n rgba(52, 152, 219, 0.1) 0%, \r\n rgba(155, 89, 182, 0.1) 50%, \r\n rgba(52, 152, 219, 0.1) 100%);\r\n border: 1px solid rgba(52, 152, 219, 0.3);\r\n border-radius: 8px;\r\n cursor: pointer;\r\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n overflow: hidden;\r\n \r\n &::before {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n left: -100%;\r\n width: 100%;\r\n height: 100%;\r\n background: linear-gradient(90deg, \r\n transparent, \r\n rgba(255, 255, 255, 0.2), \r\n transparent);\r\n transition: left 0.5s ease;\r\n }\r\n \r\n .btn-content {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n z-index: 2;\r\n }\r\n \r\n .btn-icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n \r\n svg {\r\n width: 18px;\r\n height: 18px;\r\n color: #3498db;\r\n transition: all 0.3s ease;\r\n filter: drop-shadow(0 0 3px rgba(52, 152, 219, 0.3));\r\n }\r\n }\r\n \r\n .btn-text {\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: #2c3e50;\r\n transition: all 0.3s ease;\r\n }\r\n \r\n // 悬停效果\r\n &:hover {\r\n transform: translateY(-2px);\r\n background: linear-gradient(135deg, \r\n rgba(52, 152, 219, 0.2) 0%, \r\n rgba(155, 89, 182, 0.2) 50%, \r\n rgba(52, 152, 219, 0.2) 100%);\r\n border-color: rgba(52, 152, 219, 0.5);\r\n box-shadow: 0 4px 12px rgba(52, 152, 219, 0.2);\r\n \r\n &::before {\r\n left: 100%;\r\n }\r\n \r\n .btn-icon svg {\r\n color: #2980b9;\r\n transform: scale(1.1);\r\n }\r\n \r\n .btn-text {\r\n color: #2980b9;\r\n }\r\n }\r\n \r\n // 激活状态\r\n &.active {\r\n background: linear-gradient(135deg, \r\n rgba(231, 76, 60, 0.15) 0%, \r\n rgba(192, 57, 43, 0.15) 50%, \r\n rgba(231, 76, 60, 0.15) 100%);\r\n border-color: rgba(231, 76, 60, 0.4);\r\n box-shadow: 0 0 15px rgba(231, 76, 60, 0.3);\r\n \r\n .btn-icon svg {\r\n color: #e74c3c;\r\n animation: pulse 2s infinite ease-in-out;\r\n }\r\n \r\n .btn-text {\r\n color: #e74c3c;\r\n font-weight: 700;\r\n }\r\n }\r\n }\r\n \r\n // 动画定义\r\n @keyframes pulse {\r\n 0%, 100% {\r\n transform: scale(1);\r\n filter: drop-shadow(0 0 3px rgba(231, 76, 60, 0.3));\r\n }\r\n 50% {\r\n transform: scale(1.1);\r\n filter: drop-shadow(0 0 8px rgba(231, 76, 60, 0.6));\r\n }\r\n }\r\n }\r\n\r\n .gantt {\r\n height: calc(100% - #{$toolbarHeight});\r\n width: 100%;\r\n }\r\n \r\n .config-panel-overlay {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n z-index: 1000;\r\n }\r\n \r\n .config-panel-container {\r\n position: relative;\r\n max-height: 90vh;\r\n overflow: hidden;\r\n }\r\n}\r\n</style>","<template>\r\n <div class=\"page gantt-container\" ref=\"ganttContainer\">\r\n <div class=\"toolbar\">\r\n <div class=\"dateInput\">\r\n <DatePicker :date=\"startDate\" :min-date=\"minStartDate\" :max-date=\"maxStartDate\"\r\n @confirm=\"confirmStart\" />\r\n <span style=\"margin-right:20px;margin-left:20px;color:#606266\">{{ t('common.to') }}</span>\r\n <DatePicker :date=\"endDate\" :min-date=\"minEndDate\" :max-date=\"maxEndDate\" @confirm=\"confirmEnd\" />\r\n </div>\r\n <div class=\"buttonGroup\">\r\n <div :class=\"buttonClass[0]\" class=\"metro-btn\" @click=\"timeMode('月')\">\r\n <div class=\"metro-content\">\r\n <div class=\"metro-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z\"/>\r\n </svg>\r\n </div>\r\n <div class=\"metro-text\">{{ t('viewMode.month') }}</div>\r\n </div>\r\n </div>\r\n <div :class=\"buttonClass[1]\" class=\"metro-btn\" @click=\"timeMode('周')\">\r\n <div class=\"metro-content\">\r\n <div class=\"metro-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z\"/>\r\n </svg>\r\n </div>\r\n <div class=\"metro-text\">{{ t('viewMode.week') }}</div>\r\n </div>\r\n </div>\r\n <div :class=\"buttonClass[2]\" class=\"metro-btn\" @click=\"timeMode('日')\">\r\n <div class=\"metro-content\">\r\n <div class=\"metro-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 2 2h8c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 18H6V4h8v16z\"/>\r\n </svg>\r\n </div>\r\n <div class=\"metro-text\">{{ t('viewMode.day') }}</div>\r\n </div>\r\n </div>\r\n <div :class=\"buttonClass[3]\" class=\"metro-btn\" @click=\"timeMode('时')\">\r\n <div class=\"metro-content\">\r\n <div class=\"metro-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z\"/>\r\n </svg>\r\n </div>\r\n <div class=\"metro-text\">{{ t('viewMode.hour') }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n <!-- 连线类型图例 -->\r\n <div class=\"link-legend\">\r\n <div class=\"legend-title\">\r\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19 15l-6 6-1.42-1.42L15.17 16H4V4h2v10h9.17l-3.59-3.58L13 9l6 6z\"/>\r\n </svg>\r\n {{ t('link.legend') }}\r\n </div>\r\n <div class=\"legend-items\">\r\n <label class=\"legend-item\" :class=\"{ disabled: !linkTypeVisibility.parentChild }\" title=\"父子关系:显示任务的层级结构\">\r\n <input type=\"checkbox\" v-model=\"linkTypeVisibility.parentChild\" @change=\"updateLinkVisibility\" />\r\n <svg width=\"24\" height=\"12\" viewBox=\"0 0 24 12\">\r\n <line x1=\"0\" y1=\"6\" x2=\"18\" y2=\"6\" stroke=\"#95a5a6\" stroke-width=\"1.5\" stroke-dasharray=\"3,3\"/>\r\n <polygon points=\"24,6 18,3 18,9\" fill=\"#95a5a6\"/>\r\n </svg>\r\n <span class=\"legend-label\">{{ t('link.pc') }}</span>\r\n <span class=\"legend-desc\">{{ t('link.parentChild') }}</span>\r\n </label>\r\n <label class=\"legend-item\" :class=\"{ disabled: !linkTypeVisibility.finishToStart }\" title=\"完成-开始:前置任务完成后,后续任务才能开始\">\r\n <input type=\"checkbox\" v-model=\"linkTypeVisibility.finishToStart\" @change=\"updateLinkVisibility\" />\r\n <svg width=\"24\" height=\"12\" viewBox=\"0 0 24 12\">\r\n <line x1=\"0\" y1=\"6\" x2=\"18\" y2=\"6\" :stroke=\"linkTypeColors.finishToStart\" stroke-width=\"2\"/>\r\n <polygon points=\"24,6 18,3 18,9\" :fill=\"linkTypeColors.finishToStart\"/>\r\n </svg>\r\n <span class=\"legend-label\">{{ t('link.fs') }}</span>\r\n <span class=\"legend-desc\">{{ t('link.finishToStart') }}</span>\r\n </label>\r\n <label class=\"legend-item\" :class=\"{ disabled: !linkTypeVisibility.startToStart }\" title=\"开始-开始:两个任务同时开始\">\r\n <input type=\"checkbox\" v-model=\"linkTypeVisibility.startToStart\" @change=\"updateLinkVisibility\" />\r\n <svg width=\"24\" height=\"12\" viewBox=\"0 0 24 12\">\r\n <line x1=\"0\" y1=\"6\" x2=\"18\" y2=\"6\" :stroke=\"linkTypeColors.startToStart\" stroke-width=\"2\"/>\r\n <polygon points=\"24,6 18,3 18,9\" :fill=\"linkTypeColors.startToStart\"/>\r\n </svg>\r\n <span class=\"legend-label\">{{ t('link.ss') }}</span>\r\n <span class=\"legend-desc\">{{ t('link.startToStart') }}</span>\r\n </label>\r\n <label class=\"legend-item\" :class=\"{ disabled: !linkTypeVisibility.finishToFinish }\" title=\"完成-完成:两个任务同时完成\">\r\n <input type=\"checkbox\" v-model=\"linkTypeVisibility.finishToFinish\" @change=\"updateLinkVisibility\" />\r\n <svg width=\"24\" height=\"12\" viewBox=\"0 0 24 12\">\r\n <line x1=\"0\" y1=\"6\" x2=\"18\" y2=\"6\" :stroke=\"linkTypeColors.finishToFinish\" stroke-width=\"2\"/>\r\n <polygon points=\"24,6 18,3 18,9\" :fill=\"linkTypeColors.finishToFinish\"/>\r\n </svg>\r\n <span class=\"legend-label\">{{ t('link.ff') }}</span>\r\n <span class=\"legend-desc\">{{ t('link.finishToFinish') }}</span>\r\n </label>\r\n <label class=\"legend-item\" :class=\"{ disabled: !linkTypeVisibility.startToFinish }\" title=\"开始-完成:前置任务开始后,后续任务才能完成\">\r\n <input type=\"checkbox\" v-model=\"linkTypeVisibility.startToFinish\" @change=\"updateLinkVisibility\" />\r\n <svg width=\"24\" height=\"12\" viewBox=\"0 0 24 12\">\r\n <line x1=\"0\" y1=\"6\" x2=\"18\" y2=\"6\" :stroke=\"linkTypeColors.startToFinish\" stroke-width=\"2\"/>\r\n <polygon points=\"24,6 18,3 18,9\" :fill=\"linkTypeColors.startToFinish\"/>\r\n </svg>\r\n <span class=\"legend-label\">{{ t('link.sf') }}</span>\r\n <span class=\"legend-desc\">{{ t('link.startToFinish') }}</span>\r\n </label>\r\n </div>\r\n </div>\r\n <div class=\"config-buttons\">\r\n <GanttConfigPanel />\r\n </div>\r\n </div>\r\n <div class=\"gantt\">\r\n <SplitPane direction=\"row\" :min=\"0\" :max=\"100\" :triggerLength=\"10\"\r\n v-model:paneLengthPercent=\"paneLengthPercent\">\r\n <template #one>\r\n <TaskTable :headersHeight='styleConfig.headersHeight' :rowHeight='styleConfig.rowHeight'>\r\n </TaskTable>\r\n </template>\r\n <template #two>\r\n <RightTable ref='barContent' :headersHeight='styleConfig.headersHeight'\r\n :rowHeight='styleConfig.rowHeight'></RightTable>\r\n </template>\r\n </SplitPane>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { ref, defineComponent, computed, provide, onBeforeMount, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';\r\nimport dayjs from 'dayjs';\r\nimport customParseFormat from 'dayjs/plugin/customParseFormat';\r\nimport 'dayjs/locale/zh-cn';\r\nimport 'dayjs/locale/en';\r\nimport 'dayjs/locale/ja';\r\nimport 'dayjs/locale/ko';\r\nimport 'dayjs/locale/fr';\r\nimport 'dayjs/locale/de';\r\nimport 'dayjs/locale/es';\r\nimport 'dayjs/locale/ru';\r\ndayjs.extend(customParseFormat);\r\nimport { Symbols } from './Symbols';\r\nimport { linkDataManager, useLinkConfig } from './LinkConfig';\r\nimport { useI18n } from './i18n';\r\n// 导入日期选择器组件\r\nimport DatePicker from './DatePicker.vue';\r\n// 导入分割面板组件\r\nimport SplitPane from './SplitPane.vue';\r\nimport TaskTable from '../gantt/task/TaskTable.vue';\r\nimport RightTable from './RightTable.vue';\r\nimport GanttConfigPanel from './GanttConfigPanel.vue';\r\nimport { store, mutations } from './Store';\r\nexport type { DataConfig, StyleConfig, EventConfig, TaskHeader } from './Types';\r\n// 移除未使用的类型导入\r\nimport { type ConfirmDateData } from './ZodSchema';\r\n\r\n// 定义月份表头类型\r\ntype MonthHeaders = {\r\n title: string;\r\n width: number;\r\n}\r\n\r\n// 定义天表头类型\r\ntype DayHeaders = MonthHeaders & {\r\n fulldate: string;\r\n}\r\n\r\n// 定义周表头类型\r\ntype WeekHeaders = MonthHeaders & {\r\n fulldate: string;\r\n}\r\n\r\n// 定义小时表头类型\r\ntype HourHeaders = {\r\n title: string;\r\n width: number;\r\n}\r\n\r\n/**\r\n * Gantt 组件,用于展示甘特图。\r\n * 该组件接收样式配置、数据配置和事件配置作为属性。\r\n */\r\nexport default defineComponent({\r\n // 组件名称\r\n name: 'Gantt',\r\n props: {\r\n /**\r\n * 样式配置对象,包含表头高度和行高。\r\n * @type {{ headersHeight: number; rowHeight: number }}\r\n * @required\r\n * @default { headersHeight: 100, rowHeight: 60 }\r\n */\r\n styleConfig: {\r\n type: Object as () => {\r\n headersHeight: number;\r\n rowHeight: number;\r\n setBarColor: (row: Record<string, any>) => string;\r\n },\r\n required: true,\r\n default: () => ({\r\n // 表头高度\r\n headersHeight: 100,\r\n // 行高\r\n rowHeight: 60\r\n }),\r\n // 验证参数合法性\r\n validator: (value: { headersHeight: number; rowHeight: number }) => {\r\n return value.headersHeight > 0 && value.rowHeight > 0;\r\n }\r\n },\r\n /**\r\n * 数据配置对象,包含数据源、任务表头和字段映射函数。\r\n * @type {{ dataSource: any[]; taskHeaders: () => any[]; mapFields: () => any }}\r\n * @required\r\n * @default { dataSource: [], taskHeaders: () => [], mapFields: () => {} }\r\n */\r\n dataConfig: {\r\n type: Object as () => {\r\n dataSource: any[];\r\n taskHeaders: any[];\r\n mapFields: Record<string, any>;\r\n queryStartDate: string;\r\n queryEndDate: string;\r\n dependencies?: Omit<import('./Types').TaskDependency, 'id'>[];\r\n },\r\n required: true,\r\n default: () => ({\r\n dataSource: [],\r\n taskHeaders: [],\r\n mapFields: {}\r\n }),\r\n validator: (value: { dataSource: any[]; taskHeaders: any[]; mapFields: Record<string, any> }) => {\r\n return Array.isArray(value.dataSource) &&\r\n Array.isArray(value.taskHeaders) &&\r\n typeof value.mapFields === 'object' && value.mapFields !== null;\r\n }\r\n },\r\n /**\r\n * 事件配置对象,包含添加根任务、添加子任务、移除任务等事件处理函数。\r\n * @type {{\r\n * addRootTask: () => void;\r\n * addSubTask: (task: any) => void;\r\n * removeTask: (task: any) => void;\r\n * queryTask: (startDate: string, endDate: string, mode: string) => void;\r\n * barDate: (id: any, startDate: string, endDate: string) => void;\r\n * allowChangeTaskDate: (allow: boolean) => void;\r\n * }}\r\n * @required\r\n */\r\n eventConfig: {\r\n type: Object as () => {\r\n addRootTask: (row: Record<string, any> | null) => void;\r\n addSubTask: (task: any) => void;\r\n removeTask: (task: any) => void;\r\n editTask: (task: any) => void;\r\n queryTask: (startDate: string, endDate: string, mode: string) => void;\r\n barDate: (id: any, startDate: string, endDate: string) => void;\r\n allowChangeTaskDate: (allow: boolean) => void;\r\n updateProgress?: (detail: { taskId: any; oldProgress: number; newProgress: number; task: Record<string, any> }) => void;\r\n },\r\n required: true\r\n }\r\n },\r\n components: {\r\n DatePicker,\r\n SplitPane,\r\n TaskTable,\r\n RightTable,\r\n GanttConfigPanel\r\n },\r\n setup(props) {\r\n // 国际化\r\n const { t, locale } = useI18n();\r\n \r\n // 根据当前语言设置 dayjs locale\r\n const getDayjsLocale = () => {\r\n const localeMap: Record<string, string> = {\r\n 'zh-CN': 'zh-cn',\r\n 'en-US': 'en',\r\n 'ja-JP': 'ja',\r\n 'ko-KR': 'ko',\r\n 'fr-FR': 'fr',\r\n 'de-DE': 'de',\r\n 'es-ES': 'es',\r\n 'ru-RU': 'ru'\r\n };\r\n return localeMap[locale.value] || 'en';\r\n };\r\n \r\n // 缓存 mapFields 的结果\r\n const mapFields = computed(() => props.dataConfig.mapFields);\r\n // 缓存 dataSource 的结果\r\n const dataSource = computed(() => props.dataConfig.dataSource);\r\n\r\n // 连线配置\r\n const { config: linkConfig, updateConfig: updateLinkConfig } = useLinkConfig();\r\n\r\n // 连线类型显示控制\r\n const linkTypeVisibility = ref({\r\n finishToStart: linkConfig.linkTypeVisibility?.finishToStart ?? true,\r\n startToStart: linkConfig.linkTypeVisibility?.startToStart ?? true,\r\n finishToFinish: linkConfig.linkTypeVisibility?.finishToFinish ?? true,\r\n startToFinish: linkConfig.linkTypeVisibility?.startToFinish ?? true,\r\n parentChild: linkConfig.linkTypeVisibility?.parentChild ?? true\r\n });\r\n\r\n // 更新连线类型显示配置\r\n const updateLinkVisibility = () => {\r\n updateLinkConfig({\r\n linkTypeVisibility: { ...linkTypeVisibility.value }\r\n });\r\n };\r\n\r\n // 定义响应式数据\r\n const initData = ref<any[]>([]);\r\n const paneLengthPercent = ref(35);\r\n const buttonClass = ref(['button is-active', 'button', 'button', 'button']);\r\n const mode = ref('月');\r\n const startDate = ref(dayjs().locale(getDayjsLocale()).format('YYYY-MM-DD'));\r\n const minStartDate = ref(dayjs().locale(getDayjsLocale()).add(-5, 'y').format('YYYY-MM-DD'));\r\n const maxStartDate = ref(dayjs().locale(getDayjsLocale()).add(5, 'y').format('YYYY-MM-DD'));\r\n const showStartDatePicker = ref(false);\r\n const selectedStartDate = ref('点击选择日期');\r\n const endDate = ref(dayjs().locale(getDayjsLocale()).format('YYYY-MM-DD'));\r\n const minEndDate = ref(startDate.value);\r\n const maxEndDate = ref(dayjs(startDate.value).locale(getDayjsLocale()).add(5, 'y').format('YYYY-MM-DD'));\r\n const showEndDatePicker = ref(false);\r\n const selectedEndDate = ref('点击选择日期');\r\n const monthHeaders = ref<MonthHeaders[]>([]);\r\n const dayHeaders = ref<DayHeaders[]>([]);\r\n const weekHeaders = ref<WeekHeaders[]>([]);\r\n const hourHeaders = ref<HourHeaders[]>([]);\r\n const scale = ref(0);\r\n const timelineCellCount = ref(0);\r\n const startGanttDate = ref<string | null>(null);\r\n const endGanttDate = ref<string | null>(null);\r\n const result = ref('');\r\n \r\n // 甘特图容器引用\r\n const ganttContainer = ref<HTMLElement>();\r\n\r\n // 计算属性\r\n const subTask = computed(() => store.subTask);\r\n const editTask = computed(() => store.editTask);\r\n const removeTask = computed(() => store.removeTask);\r\n const rootTask = computed(() => store.rootTask);\r\n const allowChangeTaskDate = computed(() => store.allowChangeTaskDate);\r\n\r\n const setTimeLineHeaders = (newVal: string) => {\r\n const start = dayjs(selectedStartDate.value);\r\n const end = dayjs(selectedEndDate.value);\r\n // 开始时间格式是否合法\r\n if (!start.isValid()) {\r\n return;\r\n }\r\n // 结束时间格式是否合法\r\n if (!end.isValid()) {\r\n return;\r\n }\r\n // 检验开始时间结束时间范围的合法性\r\n const days = end.diff(start, 'day');\r\n if (days < 0) {\r\n return;\r\n }\r\n startGanttDate.value = selectedStartDate.value + ' 00:00:00';\r\n endGanttDate.value = selectedEndDate.value + ' 23:59:59';\r\n weekHeaders.value = [];\r\n dayHeaders.value = [];\r\n monthHeaders.value = [];\r\n hourHeaders.value = [];\r\n switch (newVal) {\r\n case '月': {\r\n scale.value = 80;\r\n const months: string[] = [];\r\n let current = start.startOf('month');\r\n while (current.isBefore(end) || current.isSame(end, 'month')) {\r\n months.push(current.format('YYYY-MM-DD'));\r\n current = current.add(1, 'month');\r\n }\r\n if (!months.some((item) => dayjs(item).format('YYYY-MM') === end.format('YYYY-MM'))) {\r\n months.push(end.format('YYYY-MM-DD'));\r\n }\r\n // 时间跨度只有一个月\r\n if (months.length === 1) {\r\n const days = end.diff(start, 'day') + 1;\r\n monthHeaders.value.push({\r\n title: start.locale(getDayjsLocale()).format('MMMM'),\r\n width: days * scale.value\r\n });\r\n } else {\r\n months.forEach((month, index) => {\r\n if (index === 0) {\r\n const endOfMonth = start.endOf('month').format('YYYY-MM-DD');\r\n const days = dayjs(endOfMonth).diff(start, 'day') + 1;\r\n monthHeaders.value.push({\r\n title: dayjs(month).locale(getDayjsLocale()).format('MMMM'),\r\n width: days * scale.value\r\n });\r\n } else if (index === months.length - 1) {\r\n const startOfMonth = end.startOf('month').format('YYYY-MM-DD');\r\n const days = end.diff(dayjs(startOfMonth), 'day') + 1;\r\n monthHeaders.value.push({\r\n title: dayjs(month).locale(getDayjsLocale()).format('MMMM'),\r\n width: days * scale.value\r\n });\r\n } else {\r\n const days = dayjs(month, 'YYYY-MM').daysInMonth();\r\n monthHeaders.value.push({\r\n title: dayjs(month).locale(getDayjsLocale()).format('MMMM'),\r\n width: days * scale.value\r\n });\r\n }\r\n });\r\n }\r\n\r\n let currentDate = start;\r\n while (currentDate.isBefore(end) || currentDate.isSame(end, 'day')) {\r\n // 中日韩语言需要添加“日”后缀\r\n const needsDaySuffix = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n const caption = needsDaySuffix\r\n ? currentDate.format('DD') + '日'\r\n : currentDate.format('DD');\r\n const fullDate = currentDate.format('YYYY-MM-DD');\r\n const week = currentDate.locale(getDayjsLocale()).format('dddd');\r\n weekHeaders.value.push({\r\n title: week,\r\n width: scale.value,\r\n fulldate: fullDate\r\n });\r\n dayHeaders.value.push({\r\n title: caption,\r\n width: scale.value,\r\n fulldate: fullDate\r\n });\r\n currentDate = currentDate.add(1, 'day');\r\n }\r\n timelineCellCount.value = dayHeaders.value.length;\r\n break;\r\n }\r\n case '周': {\r\n scale.value = 120;\r\n let currentDate = start.startOf('isoWeek'); // 从周一开始\r\n const endWeek = end.endOf('isoWeek'); // 到周日结束\r\n \r\n // 生成月份表头\r\n const months: string[] = [];\r\n let monthCurrent = currentDate.startOf('month');\r\n while (monthCurrent.isBefore(endWeek) || monthCurrent.isSame(endWeek, 'month')) {\r\n months.push(monthCurrent.format('YYYY-MM-DD'));\r\n monthCurrent = monthCurrent.add(1, 'month');\r\n }\r\n \r\n months.forEach((month, index) => {\r\n const monthStart = dayjs(month);\r\n const monthEnd = monthStart.endOf('month');\r\n \r\n // 计算该月包含的周数\r\n let weekCount = 0;\r\n let weekCurrent = currentDate.clone();\r\n while (weekCurrent.isBefore(endWeek) || weekCurrent.isSame(endWeek, 'week')) {\r\n const weekStart = weekCurrent.startOf('isoWeek');\r\n const weekEnd = weekCurrent.endOf('isoWeek');\r\n \r\n // 检查这一周是否与当前月份有交集\r\n if (weekStart.isSame(monthStart, 'month') || weekEnd.isSame(monthStart, 'month') ||\r\n (weekStart.isBefore(monthEnd) && weekEnd.isAfter(monthStart))) {\r\n weekCount++;\r\n }\r\n weekCurrent = weekCurrent.add(1, 'week');\r\n }\r\n \r\n if (weekCount > 0) {\r\n // 根据语言选择月份格式\r\n const isAsian = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n const monthTitle = isAsian\r\n ? monthStart.format('YYYY年MM月')\r\n : monthStart.locale(getDayjsLocale()).format('MMMM YYYY');\r\n monthHeaders.value.push({\r\n title: monthTitle,\r\n width: weekCount * scale.value\r\n });\r\n }\r\n });\r\n \r\n // 生成周表头(不生成日表头,周表头显示开始和结束日期)\r\n while (currentDate.isBefore(endWeek) || currentDate.isSame(endWeek, 'week')) {\r\n const weekStart = currentDate.startOf('isoWeek');\r\n const weekEnd = currentDate.endOf('isoWeek');\r\n \r\n // 周表头 - 显示周数和日期范围\r\n const isAsian = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n const weekTitle = isAsian\r\n ? `第${currentDate.isoWeek()}周 (${weekStart.format('MM/DD')}-${weekEnd.format('MM/DD')})`\r\n : `Week ${currentDate.isoWeek()} (${weekStart.format('MM/DD')}-${weekEnd.format('MM/DD')})`;\r\n weekHeaders.value.push({\r\n title: weekTitle,\r\n width: scale.value,\r\n fulldate: weekStart.format('YYYY-MM-DD')\r\n });\r\n \r\n currentDate = currentDate.add(1, 'week');\r\n }\r\n \r\n timelineCellCount.value = weekHeaders.value.length;\r\n break;\r\n }\r\n case '日': {\r\n scale.value = 80;\r\n let currentDate = start;\r\n while (currentDate.isBefore(end) || currentDate.isSame(end, 'day')) {\r\n // 中日韩语言需要添加“日”后缀\r\n const needsDaySuffix = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n const caption = needsDaySuffix\r\n ? currentDate.locale(getDayjsLocale()).format('MMMM DD') + '日'\r\n : currentDate.locale(getDayjsLocale()).format('MMMM DD');\r\n const fullDate = currentDate.format('YYYY-MM-DD');\r\n const week = currentDate.locale(getDayjsLocale()).format('dddd');\r\n weekHeaders.value.push({\r\n title: week,\r\n width: scale.value,\r\n fulldate: fullDate\r\n });\r\n dayHeaders.value.push({\r\n title: caption,\r\n width: scale.value,\r\n fulldate: fullDate\r\n });\r\n currentDate = currentDate.add(1, 'day');\r\n }\r\n timelineCellCount.value = dayHeaders.value.length;\r\n break;\r\n }\r\n case '时': {\r\n scale.value = 30;\r\n let currentDate = start;\r\n // 预先计算结束日期\r\n const endOfEndDay = end.endOf('day');\r\n while (currentDate.isBefore(endOfEndDay)) {\r\n // 中日韩语言需要添加“日”后缀\r\n const needsDaySuffix = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n const caption = needsDaySuffix\r\n ? currentDate.locale(getDayjsLocale()).format('MMMM DD') + '日'\r\n : currentDate.locale(getDayjsLocale()).format('MMMM DD');\r\n const fullDate = currentDate.format('YYYY-MM-DD');\r\n const week = currentDate.locale(getDayjsLocale()).format('dddd');\r\n weekHeaders.value.push({\r\n title: week,\r\n width: 24 * scale.value,\r\n fulldate: fullDate\r\n });\r\n dayHeaders.value.push({\r\n title: caption,\r\n width: 24 * scale.value,\r\n fulldate: fullDate\r\n });\r\n for (let i = 0; i <= 23; i++) {\r\n // 中日韩语言使用“点”,其他语言使用 :00 格式\r\n const needsHourSuffix = ['zh-CN', 'ja-JP', 'ko-KR'].includes(locale.value);\r\n hourHeaders.value.push({\r\n title: needsHourSuffix ? i + '点' : `${i}:00`,\r\n width: scale.value\r\n });\r\n }\r\n // 优化代码:更新 currentDate\r\n currentDate = currentDate.add(1, 'day');\r\n }\r\n timelineCellCount.value = hourHeaders.value.length;\r\n break;\r\n }\r\n }\r\n // 选定日期后重新查询\r\n props.eventConfig.queryTask(selectedStartDate.value, selectedEndDate.value, mode.value);\r\n };\r\n\r\n const FindAllParent = (targetData: any[], pid: any) => {\r\n let parent = targetData.filter(obj => obj[mapFields.value['id']] === pid);\r\n if (parent && parent.length > 0) {\r\n result.value = parent[0].index + '.' + result.value;\r\n FindAllParent(targetData, parent[0][mapFields.value['parentId']]);\r\n }\r\n };\r\n\r\n const RecursionData = (id: any, tasks: any[], level: number) => {\r\n let findResult = tasks.filter(obj => obj[mapFields.value['parentId']] === id);\r\n if (findResult && findResult.length > 0) {\r\n level++;\r\n for (let i = 0; i < findResult.length; i++) {\r\n findResult[i].treeLevel = level;\r\n findResult[i].index = i + 1;\r\n\r\n let parent = initData.value.filter(obj => obj[mapFields.value['id']] === findResult[i][mapFields.value['parentId']]);\r\n result.value = '';\r\n if (parent && parent.length > 0) {\r\n result.value = parent[0].index + '.' + findResult[i].index;\r\n FindAllParent(initData.value, parent[0][mapFields.value['parentId']]);\r\n findResult[i].no = result.value;\r\n } else {\r\n findResult[i].no = i + 1 + '';\r\n }\r\n initData.value.push(findResult[i]);\r\n RecursionData(findResult[i][mapFields.value['id']], tasks, level);\r\n }\r\n }\r\n };\r\n\r\n const timeMode = (_mode: string) => {\r\n // 更新按钮状态\r\n for (let i = 0; i < buttonClass.value.length; i++) {\r\n buttonClass.value[i] = 'button';\r\n }\r\n\r\n switch (_mode) {\r\n case '月': {\r\n buttonClass.value[0] = 'button is-active';\r\n break;\r\n }\r\n case '周': {\r\n buttonClass.value[1] = 'button is-active';\r\n break;\r\n }\r\n case '日': {\r\n buttonClass.value[2] = 'button is-active';\r\n break;\r\n }\r\n case '时': {\r\n buttonClass.value[3] = 'button is-active';\r\n break;\r\n }\r\n }\r\n \r\n // 先设置mode,触发响应式更新\r\n mode.value = _mode;\r\n \r\n // 等待DOM更新完成后再滚动\r\n nextTick(() => {\r\n const barContentEl = document.querySelector('.table .content') as HTMLElement;\r\n if (barContentEl) {\r\n barContentEl.scrollLeft = 0;\r\n }\r\n });\r\n };\r\n\r\n const confirmStart = (value: ConfirmDateData) => {\r\n let days = dayjs(endDate.value).diff(dayjs(value.date), 'days')\r\n if (days < 0) {\r\n selectedEndDate.value = value.date\r\n endDate.value = value.date\r\n }\r\n showStartDatePicker.value = false\r\n selectedStartDate.value = value.date\r\n startDate.value = value.date\r\n minEndDate.value = value.date\r\n };\r\n\r\n const confirmEnd = (value: ConfirmDateData) => {\r\n let days = dayjs(value.date).diff(dayjs(startDate.value), 'days')\r\n if (days < 0) {\r\n selectedStartDate.value = dayjs(value.date).format('YYYY-MM-DD');\r\n startDate.value = dayjs(value.date).format('YYYY-MM-DD');\r\n }\r\n showEndDatePicker.value = false\r\n selectedEndDate.value = value.date\r\n endDate.value = value.date\r\n maxStartDate.value = value.date\r\n };\r\n\r\n // 监听 mode 和日期的变化\r\n watch([mode, selectedStartDate, selectedEndDate], ([newMode, newStartDate, newEndDate], [oldMode, oldStartDate, oldEndDate]) => {\r\n if (newMode !== oldMode || newStartDate !== oldStartDate || newEndDate !== oldEndDate) {\r\n setTimeLineHeaders(newMode);\r\n }\r\n });\r\n \r\n // 监听语言变化,重新生成时间轴表头\r\n watch(locale, () => {\r\n setTimeLineHeaders(mode.value);\r\n });\r\n\r\n watch(rootTask, (newVal) => { \r\n props.eventConfig.addRootTask(newVal);\r\n });\r\n\r\n watch(subTask, (newVal) => {\r\n props.eventConfig.addSubTask(newVal);\r\n });\r\n\r\n watch(removeTask, (newVal) => {\r\n props.eventConfig.removeTask(newVal);\r\n });\r\n\r\n watch(editTask, (newVal) => {\r\n props.eventConfig.editTask(newVal);\r\n });\r\n\r\n watch(allowChangeTaskDate, (newVal) => {\r\n props.eventConfig.allowChangeTaskDate(newVal);\r\n });\r\n\r\n // 优化:拆分watchEffect,避免不必要的触发\r\n watch(() => store.barDate, (barDate) => {\r\n if (barDate) {\r\n const { id, startDate, endDate } = barDate;\r\n if (id && startDate && endDate) {\r\n props.eventConfig.barDate(id, startDate, endDate);\r\n }\r\n }\r\n });\r\n\r\n watch(scale, (newScale) => {\r\n mutations.setScale(newScale);\r\n });\r\n\r\n watch(() => props.dataConfig.taskHeaders, (newHeaders) => {\r\n mutations.setTaskHeaders(newHeaders);\r\n });\r\n\r\n watch([monthHeaders, dayHeaders, weekHeaders, hourHeaders], ([newMonth, newDay, newWeek, newHour]) => {\r\n mutations.setMonthHeaders(newMonth);\r\n mutations.setDayHeaders(newDay);\r\n mutations.setWeekHeaders(newWeek);\r\n mutations.setHourHeaders(newHour);\r\n });\r\n\r\n watch(mode, (newMode) => {\r\n mutations.setMode(newMode);\r\n });\r\n\r\n watch(mapFields, (newFields) => {\r\n if (newFields) {\r\n mutations.setMapFields(newFields);\r\n }\r\n });\r\n\r\n watch(() => props.dataConfig.queryStartDate, (newStartDate) => {\r\n if (newStartDate) {\r\n mutations.setStartGanttDate(dayjs(newStartDate).toDate());\r\n startGanttDate.value = newStartDate;\r\n selectedStartDate.value = newStartDate;\r\n startDate.value = newStartDate;\r\n }\r\n });\r\n\r\n watch(() => props.dataConfig.queryEndDate, (newEndDate) => {\r\n if (newEndDate) {\r\n mutations.setEndGanttDate(dayjs(newEndDate).toDate());\r\n endGanttDate.value = newEndDate;\r\n selectedEndDate.value = newEndDate;\r\n endDate.value = newEndDate;\r\n }\r\n });\r\n\r\n watch(timelineCellCount, (newCount) => {\r\n if (newCount) {\r\n mutations.setTimelineCellCount(newCount);\r\n }\r\n });\r\n\r\n onBeforeMount(() => {\r\n mutations.setMonthHeaders(monthHeaders.value)\r\n mutations.setWeekHeaders(weekHeaders.value)\r\n mutations.setDayHeaders(dayHeaders.value)\r\n mutations.setHourHeaders(hourHeaders.value)\r\n mutations.setTaskHeaders(props.dataConfig.taskHeaders)\r\n mutations.setMapFields(mapFields.value)\r\n mutations.setTimelineCellCount(timelineCellCount.value)\r\n // 初始化时如果有数据,先设置\r\n if (dataSource.value && dataSource.value.length > 0) {\r\n mutations.setTasks(dataSource.value)\r\n }\r\n });\r\n\r\n // 进度更新事件处理\r\n const handleProgressUpdate = (event: Event) => {\r\n const customEvent = event as CustomEvent;\r\n if (props.eventConfig.updateProgress) {\r\n props.eventConfig.updateProgress(customEvent.detail);\r\n }\r\n };\r\n\r\n onMounted(() => {\r\n monthHeaders.value = [];\r\n weekHeaders.value = [];\r\n dayHeaders.value = [];\r\n hourHeaders.value = [];\r\n\r\n console.log('Gantt onMounted, dataSource:', dataSource.value);\r\n let level: number = 0;\r\n RecursionData('0', dataSource.value, level);\r\n mutations.setTasks(initData.value);\r\n console.log('initData after RecursionData:', initData.value);\r\n nextTick(() => {\r\n mode.value = '月';\r\n mutations.setMode(mode.value)\r\n });\r\n \r\n // 监听进度更新事件\r\n window.addEventListener('taskProgressUpdate', handleProgressUpdate);\r\n });\r\n \r\n // 优化:监听dataSource变化,使用节流避免频繁更新\r\n let updateTimer: ReturnType<typeof setTimeout> | null = null;\r\n watch(dataSource, (newVal) => {\r\n console.log('dataSource changed:', newVal);\r\n if (newVal && newVal.length > 0) {\r\n // 使用节流,避免频繁更新\r\n if (updateTimer) {\r\n clearTimeout(updateTimer);\r\n }\r\n updateTimer = setTimeout(() => {\r\n initData.value = [];\r\n let level: number = 0;\r\n RecursionData('0', newVal, level);\r\n mutations.setTasks(initData.value);\r\n console.log('Tasks updated:', initData.value);\r\n updateTimer = null;\r\n }, 100);\r\n } else if (newVal && newVal.length === 0) {\r\n // 如果数据为空,也要更新\r\n mutations.setTasks([]);\r\n }\r\n }, { immediate: false });\r\n\r\n onBeforeUnmount(() => {\r\n // 清理进度更新事件监听\r\n window.removeEventListener('taskProgressUpdate', handleProgressUpdate);\r\n });\r\n\r\n provide(Symbols.AddRootTaskSymbol, (row: Record<string, any>) => {\r\n return props.eventConfig.addRootTask(row);\r\n });\r\n\r\n // 设置Bar的颜色,传递到子组件\r\n provide(Symbols.SetBarColorSymbol, (row: Record<string, any>) => {\r\n return props.styleConfig.setBarColor(row);\r\n });\r\n \r\n // 提供甘特图容器引用给主题选择器\r\n provide('ganttContainer', ganttContainer);\r\n\r\n // 监听依赖关系变化\r\n watch(() => props.dataConfig.dependencies, (newDependencies) => {\r\n if (newDependencies && newDependencies.length > 0) {\r\n console.log('Loading dependencies:', newDependencies);\r\n // 清空现有依赖关系\r\n linkDataManager.clear();\r\n // 添加新的依赖关系\r\n newDependencies.forEach(dep => {\r\n linkDataManager.addDependency(dep);\r\n });\r\n }\r\n }, { immediate: true });\r\n\r\n // 连线配置变化处理\r\n const onLinkConfigChange = (config: any) => {\r\n console.log('连线配置已更新:', config);\r\n // 这里可以添加额外的处理逻辑,比如通知其他组件更新\r\n };\r\n\r\n // 连线类型颜色(从配置中读取,用于图例显示)\r\n const linkTypeColors = computed(() => ({\r\n finishToStart: linkConfig.linkTypeColors?.finishToStart || '#3498db',\r\n startToStart: linkConfig.linkTypeColors?.startToStart || '#2ecc71',\r\n finishToFinish: linkConfig.linkTypeColors?.finishToFinish || '#e74c3c',\r\n startToFinish: linkConfig.linkTypeColors?.startToFinish || '#f39c12'\r\n }));\r\n\r\n return {\r\n t,\r\n subTask,\r\n editTask,\r\n removeTask,\r\n rootTask,\r\n allowChangeTaskDate,\r\n paneLengthPercent,\r\n startDate,\r\n endDate,\r\n minStartDate,\r\n maxStartDate,\r\n confirmStart,\r\n minEndDate,\r\n maxEndDate,\r\n confirmEnd,\r\n buttonClass,\r\n timeMode,\r\n onLinkConfigChange,\r\n ganttContainer,\r\n linkTypeColors,\r\n linkTypeVisibility,\r\n updateLinkVisibility\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n$toolbarHeight: 70px;\r\n\r\n.page {\r\n height: 100%;\r\n width: 100%;\r\n overflow: hidden;\r\n display: flex;\r\n flex-direction: column;\r\n\r\n .toolbar {\r\n height: $toolbarHeight;\r\n width: 100%;\r\n display: flex;\r\n flex-direction: row;\r\n align-items: center;\r\n justify-content: flex-start;\r\n padding: calc($toolbarHeight / 2);\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border-bottom: 1px solid var(--border, #d0d0d0);\r\n transition: all var(--transition-normal, 0.25s ease);\r\n\r\n .dateInput {\r\n cursor: pointer;\r\n height: calc($toolbarHeight / 1.5);\r\n width: 450px;\r\n display: flex;\r\n flex-direction: row;\r\n align-items: center;\r\n justify-content: center;\r\n margin-right: 20px;\r\n border-radius: 5px;\r\n color: var(--primary, #0078d4);\r\n font-size: 14px;\r\n transition: color var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n .buttonGroup {\r\n height: calc($toolbarHeight / 1.5);\r\n display: flex;\r\n flex-direction: row;\r\n margin-right: 20px;\r\n background: var(--bg-metal-normal);\r\n border: 1px solid var(--border);\r\n box-shadow: var(--shadow-inset), var(--shadow-outset);\r\n border-radius: 2px;\r\n overflow: hidden;\r\n transition: all var(--transition-normal);\r\n\r\n .metro-btn {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 80px;\r\n height: 100%;\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border-right: 1px solid var(--border, #d0d0d0);\r\n \r\n &:last-child {\r\n border-right: none;\r\n }\r\n\r\n &::before {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f0f0f0));\r\n opacity: 0;\r\n transition: opacity var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n &::after {\r\n content: '';\r\n position: absolute;\r\n top: 2px;\r\n left: 2px;\r\n right: 2px;\r\n bottom: 2px;\r\n background: var(--bg-metal-pressed, linear-gradient(145deg, #e0e0e0, #f8f8f8));\r\n opacity: 0;\r\n transition: opacity var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n .metro-content {\r\n position: relative;\r\n z-index: 3;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 4px;\r\n }\r\n\r\n .metro-icon {\r\n color: var(--text-secondary, #666666);\r\n transition: color var(--transition-fast, 0.15s ease);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n\r\n .metro-text {\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--text-secondary, #555555);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n transition: color var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n &:hover {\r\n &::before {\r\n opacity: 1;\r\n }\r\n\r\n .metro-icon {\r\n color: var(--text-primary, #333333);\r\n }\r\n\r\n .metro-text {\r\n color: var(--text-primary, #333333);\r\n }\r\n }\r\n\r\n &:active {\r\n &::after {\r\n opacity: 1;\r\n }\r\n }\r\n\r\n // 激活状态\r\n &.button.is-active,\r\n &.is-active {\r\n background: linear-gradient(145deg, #0078d4, #106ebe);\r\n box-shadow: \r\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\r\n inset 0 -1px 0 rgba(0, 0, 0, 0.3),\r\n 0 1px 2px rgba(0, 0, 0, 0.2);\r\n\r\n &::before {\r\n background: linear-gradient(145deg, #1084d8, #0d5aa7);\r\n opacity: 0;\r\n }\r\n\r\n &::after {\r\n background: linear-gradient(145deg, #0d5aa7, #1084d8);\r\n opacity: 0;\r\n }\r\n\r\n .metro-icon {\r\n color: #ffffff;\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n }\r\n\r\n .metro-text {\r\n color: #ffffff;\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n font-weight: 700;\r\n }\r\n\r\n &:hover {\r\n &::before {\r\n opacity: 1;\r\n }\r\n }\r\n\r\n &:active {\r\n &::after {\r\n opacity: 1;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 兼容旧的class名称\r\n .button {\r\n @extend .metro-btn;\r\n }\r\n }\r\n \r\n .link-legend {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n padding: 6px 16px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n border-radius: 4px;\r\n margin-right: 16px;\r\n\r\n .legend-title {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n font-size: 11px;\r\n font-weight: 600;\r\n color: var(--text-secondary, #666666);\r\n padding-right: 12px;\r\n border-right: 1px solid var(--border, #d0d0d0);\r\n \r\n svg {\r\n color: var(--primary, #0078d4);\r\n }\r\n }\r\n\r\n .legend-items {\r\n display: flex;\r\n gap: 12px;\r\n }\r\n\r\n .legend-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n cursor: pointer;\r\n padding: 2px 6px;\r\n border-radius: 3px;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n\r\n input[type=\"checkbox\"] {\r\n width: 14px;\r\n height: 14px;\r\n cursor: pointer;\r\n accent-color: var(--primary, #0078d4);\r\n margin: 0;\r\n }\r\n\r\n &:hover {\r\n background: var(--bg-secondary, #e8e8e8);\r\n }\r\n\r\n &.disabled {\r\n opacity: 0.5;\r\n \r\n svg {\r\n opacity: 0.4;\r\n }\r\n \r\n .legend-label,\r\n .legend-desc {\r\n text-decoration: line-through;\r\n }\r\n }\r\n\r\n .legend-label {\r\n font-size: 10px;\r\n font-weight: 700;\r\n color: var(--text-primary, #333333);\r\n min-width: 18px;\r\n }\r\n\r\n .legend-desc {\r\n font-size: 10px;\r\n color: var(--text-secondary, #666666);\r\n white-space: nowrap;\r\n }\r\n }\r\n }\r\n\r\n .config-buttons {\r\n display: flex;\r\n gap: 12px;\r\n margin-left: auto;\r\n padding: 0 8px;\r\n }\r\n \r\n .link-config-btn {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n padding: 10px 16px;\r\n background: linear-gradient(135deg, \r\n rgba(52, 152, 219, 0.1) 0%, \r\n rgba(155, 89, 182, 0.1) 50%, \r\n rgba(52, 152, 219, 0.1) 100%);\r\n border: 1px solid rgba(52, 152, 219, 0.3);\r\n border-radius: 8px;\r\n cursor: pointer;\r\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n overflow: hidden;\r\n \r\n &::before {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n left: -100%;\r\n width: 100%;\r\n height: 100%;\r\n background: linear-gradient(90deg, \r\n transparent, \r\n rgba(255, 255, 255, 0.2), \r\n transparent);\r\n transition: left 0.5s ease;\r\n }\r\n \r\n .btn-content {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n z-index: 2;\r\n }\r\n \r\n .btn-icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n \r\n svg {\r\n width: 18px;\r\n height: 18px;\r\n color: #3498db;\r\n transition: all 0.3s ease;\r\n filter: drop-shadow(0 0 3px rgba(52, 152, 219, 0.3));\r\n }\r\n }\r\n \r\n .btn-text {\r\n font-size: 13px;\r\n font-weight: 600;\r\n color: #2c3e50;\r\n transition: all 0.3s ease;\r\n }\r\n \r\n // 悬停效果\r\n &:hover {\r\n transform: translateY(-2px);\r\n background: linear-gradient(135deg, \r\n rgba(52, 152, 219, 0.2) 0%, \r\n rgba(155, 89, 182, 0.2) 50%, \r\n rgba(52, 152, 219, 0.2) 100%);\r\n border-color: rgba(52, 152, 219, 0.5);\r\n box-shadow: 0 4px 12px rgba(52, 152, 219, 0.2);\r\n \r\n &::before {\r\n left: 100%;\r\n }\r\n \r\n .btn-icon svg {\r\n color: #2980b9;\r\n transform: scale(1.1);\r\n }\r\n \r\n .btn-text {\r\n color: #2980b9;\r\n }\r\n }\r\n \r\n // 激活状态\r\n &.active {\r\n background: linear-gradient(135deg, \r\n rgba(231, 76, 60, 0.15) 0%, \r\n rgba(192, 57, 43, 0.15) 50%, \r\n rgba(231, 76, 60, 0.15) 100%);\r\n border-color: rgba(231, 76, 60, 0.4);\r\n box-shadow: 0 0 15px rgba(231, 76, 60, 0.3);\r\n \r\n .btn-icon svg {\r\n color: #e74c3c;\r\n animation: pulse 2s infinite ease-in-out;\r\n }\r\n \r\n .btn-text {\r\n color: #e74c3c;\r\n font-weight: 700;\r\n }\r\n }\r\n }\r\n \r\n // 动画定义\r\n @keyframes pulse {\r\n 0%, 100% {\r\n transform: scale(1);\r\n filter: drop-shadow(0 0 3px rgba(231, 76, 60, 0.3));\r\n }\r\n 50% {\r\n transform: scale(1.1);\r\n filter: drop-shadow(0 0 8px rgba(231, 76, 60, 0.6));\r\n }\r\n }\r\n }\r\n\r\n .gantt {\r\n height: calc(100% - #{$toolbarHeight});\r\n width: 100%;\r\n }\r\n \r\n .config-panel-overlay {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n z-index: 1000;\r\n }\r\n \r\n .config-panel-container {\r\n position: relative;\r\n max-height: 90vh;\r\n overflow: hidden;\r\n }\r\n}\r\n</style>","<template>\r\n <div class=\"gantt-theme-selector\">\r\n <div class=\"theme-selector-trigger\" @click=\"toggleSelector\" :class=\"{ active: isOpen }\">\r\n <div class=\"theme-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"theme-text\">主题</span>\r\n <div class=\"theme-arrow\" :class=\"{ rotated: isOpen }\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"theme-dropdown\" v-show=\"isOpen\" @click.stop>\r\n <div class=\"theme-dropdown-header\">\r\n <h3>选择主题</h3>\r\n <button class=\"close-btn\" @click=\"closeSelector\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"theme-grid\">\r\n <div \r\n v-for=\"theme in availableThemes\" \r\n :key=\"theme.id\"\r\n class=\"theme-card\"\r\n :class=\"{ \r\n active: currentTheme === theme.id,\r\n preview: previewTheme === theme.id \r\n }\"\r\n @click=\"selectTheme(theme.id)\"\r\n @mouseenter=\"onPreviewTheme(theme.id)\"\r\n @mouseleave=\"onCancelPreview\"\r\n >\r\n <div class=\"theme-preview\" :style=\"{ backgroundColor: theme.preview }\">\r\n <div class=\"theme-preview-content\">\r\n <div class=\"preview-header\" :style=\"{ backgroundColor: theme.preview }\"></div>\r\n <div class=\"preview-body\">\r\n <div class=\"preview-bar\"></div>\r\n <div class=\"preview-bar short\"></div>\r\n <div class=\"preview-bar medium\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"theme-info\">\r\n <h4 class=\"theme-name\">{{ t(theme.nameKey) }}</h4>\r\n <p class=\"theme-description\">{{ t(theme.descKey) }}</p>\r\n </div>\r\n <div class=\"theme-status\">\r\n <div v-if=\"currentTheme === theme.id\" class=\"status-badge current\">当前</div>\r\n <div v-else-if=\"previewTheme === theme.id\" class=\"status-badge preview\">预览</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"theme-actions\">\r\n <button class=\"action-btn\" @click=\"exportConfig\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z\"/>\r\n </svg>\r\n 导出配置\r\n </button>\r\n <button class=\"action-btn\" @click=\"importConfig\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z\"/>\r\n </svg>\r\n 导入配置\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <input \r\n ref=\"fileInput\" \r\n type=\"file\" \r\n accept=\".json\" \r\n style=\"display: none\" \r\n @change=\"handleFileImport\"\r\n >\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, onMounted, onUnmounted, inject, watchEffect, nextTick } from 'vue';\r\nimport { ganttThemes, ganttThemeManager, type GanttTheme } from './themes/GanttThemes';\r\nimport { useI18n } from './i18n';\r\n\r\nexport default defineComponent({\r\n name: 'GanttThemeSelector',\r\n setup() {\r\n const { t } = useI18n();\r\n const isOpen = ref(false);\r\n const currentTheme = ref('metro');\r\n const previewTheme = ref('');\r\n const fileInput = ref<HTMLInputElement>();\r\n const availableThemes = ref<GanttTheme[]>(ganttThemes);\r\n\r\n // 获取甘特图容器引用\r\n const ganttContainer = inject<any>('ganttContainer');\r\n\r\n const toggleSelector = () => {\r\n isOpen.value = !isOpen.value;\r\n };\r\n\r\n const closeSelector = () => {\r\n isOpen.value = false;\r\n onCancelPreview();\r\n };\r\n\r\n const selectTheme = (themeId: string) => {\r\n console.log('🎯 selectTheme called with:', themeId);\r\n console.log('📦 ganttContainer:', ganttContainer);\r\n console.log('📦 ganttContainer.value:', ganttContainer?.value);\r\n \r\n currentTheme.value = themeId;\r\n previewTheme.value = '';\r\n \r\n // 先尝试注入样式,不依赖容器引用\r\n injectThemeStyles(themeId);\r\n \r\n // 查找甘特图容器的多种方式\r\n let container = null;\r\n \r\n if (ganttContainer && ganttContainer.value) {\r\n container = ganttContainer.value;\r\n console.log('✅ Using injected container reference');\r\n } else {\r\n // 备用方案:直接查找DOM元素\r\n container = document.querySelector('.gantt-container') || \r\n document.querySelector('.page') ||\r\n document.querySelector('[class*=\"gantt\"]');\r\n console.log('🔍 Using DOM query fallback, found:', container);\r\n }\r\n \r\n if (container) {\r\n // 设置容器属性\r\n container.setAttribute('data-gantt-theme', themeId);\r\n console.log('✅ Container attribute set:', container.getAttribute('data-gantt-theme'));\r\n \r\n // 同时设置到页面根元素\r\n const pageElement = document.querySelector('.page');\r\n if (pageElement) {\r\n pageElement.setAttribute('data-gantt-theme', themeId);\r\n console.log('✅ Page element attribute set');\r\n }\r\n \r\n // 保存到localStorage\r\n try {\r\n localStorage.setItem('gantt-theme', themeId);\r\n console.log('💾 Theme saved to localStorage:', themeId);\r\n } catch (error) {\r\n console.warn('Failed to save theme:', error);\r\n }\r\n \r\n // 强制触发重绘\r\n setTimeout(() => {\r\n console.log('🔄 Forcing style recalculation...');\r\n if (container) {\r\n container.style.display = 'none';\r\n container.offsetHeight; // 触发重排\r\n container.style.display = '';\r\n }\r\n }, 50);\r\n \r\n } else {\r\n console.error('❌ No gantt container found! Available elements:');\r\n console.log('Available .page elements:', document.querySelectorAll('.page'));\r\n console.log('Available .gantt-container elements:', document.querySelectorAll('.gantt-container'));\r\n console.log('Available elements with gantt in class:', document.querySelectorAll('[class*=\"gantt\"]'));\r\n }\r\n \r\n closeSelector();\r\n };\r\n\r\n const onPreviewTheme = (themeId: string) => {\r\n if (themeId !== currentTheme.value && ganttContainer && ganttContainer.value) {\r\n previewTheme.value = themeId;\r\n \r\n // 临时注入预览主题\r\n injectThemeStyles(themeId);\r\n }\r\n };\r\n\r\n const onCancelPreview = () => {\r\n if (previewTheme.value && ganttContainer && ganttContainer.value) {\r\n previewTheme.value = '';\r\n \r\n // 恢复当前主题\r\n injectThemeStyles(currentTheme.value);\r\n }\r\n };\r\n\r\n const exportConfig = () => {\r\n const config = ganttThemeManager.exportThemeConfig();\r\n const blob = new Blob([config], { type: 'application/json' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = `gantt-theme-config-${new Date().toISOString().split('T')[0]}.json`;\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n URL.revokeObjectURL(url);\r\n };\r\n\r\n const importConfig = () => {\r\n fileInput.value?.click();\r\n };\r\n\r\n const handleFileImport = (event: Event) => {\r\n const file = (event.target as HTMLInputElement).files?.[0];\r\n if (file) {\r\n const reader = new FileReader();\r\n reader.onload = (e) => {\r\n try {\r\n const content = e.target?.result as string;\r\n if (ganttThemeManager.importThemeConfig(content)) {\r\n currentTheme.value = ganttThemeManager.getCurrentTheme();\r\n alert('主题配置导入成功!');\r\n } else {\r\n alert('主题配置文件格式错误!');\r\n }\r\n } catch (error) {\r\n alert('主题配置文件格式错误!');\r\n }\r\n };\r\n reader.readAsText(file);\r\n }\r\n };\r\n\r\n const handleClickOutside = (event: MouseEvent) => {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.gantt-theme-selector')) {\r\n closeSelector();\r\n }\r\n };\r\n\r\n // 动态注入主题样式 - 增强版\r\n const injectThemeStyles = (themeId: string) => {\r\n console.log('🎨 Starting theme injection for:', themeId);\r\n \r\n // 移除之前的主题样式\r\n const existingStyle = document.getElementById('gantt-theme-styles');\r\n if (existingStyle) {\r\n existingStyle.remove();\r\n console.log('🗑️ Removed existing theme styles');\r\n }\r\n \r\n const theme = ganttThemes.find(t => t.id === themeId);\r\n if (!theme) {\r\n console.error('❌ Theme not found:', themeId);\r\n return;\r\n }\r\n \r\n console.log('📋 Theme found:', t(theme.nameKey), 'Variables count:', Object.keys(theme.cssVariables).length);\r\n \r\n // 创建样式元素\r\n const style = document.createElement('style');\r\n style.id = 'gantt-theme-styles';\r\n \r\n // 生成CSS规则\r\n const cssRules = Object.entries(theme.cssVariables)\r\n .map(([property, value]) => `${property}: ${value};`)\r\n .join('\\n ');\r\n \r\n // 创建更强力的CSS内容,使用!important确保优先级\r\n style.textContent = `\r\n /* 甘特图主题样式 - ${themeId} */\r\n .page.gantt-container,\r\n .page.gantt-container *,\r\n .gantt-container,\r\n .gantt-container *,\r\n [data-gantt-theme=\"${themeId}\"],\r\n [data-gantt-theme=\"${themeId}\"] *,\r\n .toolbar,\r\n .toolbar *,\r\n .buttonGroup,\r\n .buttonGroup *,\r\n .metro-btn,\r\n .metro-btn *,\r\n .gantt,\r\n .gantt * {\r\n ${cssRules}\r\n }\r\n \r\n /* 根级别变量 */\r\n :root {\r\n ${cssRules}\r\n }\r\n \r\n /* 强制应用到特定元素 */\r\n .page[data-gantt-theme=\"${themeId}\"] .toolbar {\r\n background: var(--bg-metal-normal) !important;\r\n border-bottom: 1px solid var(--border) !important;\r\n }\r\n \r\n .page[data-gantt-theme=\"${themeId}\"] .buttonGroup {\r\n background: var(--bg-metal-normal) !important;\r\n border: 1px solid var(--border) !important;\r\n }\r\n \r\n .page[data-gantt-theme=\"${themeId}\"] .metro-btn {\r\n background: var(--bg-metal-normal) !important;\r\n color: var(--text-secondary) !important;\r\n border-right: 1px solid var(--border) !important;\r\n }\r\n \r\n .page[data-gantt-theme=\"${themeId}\"] .metro-btn.is-active,\r\n .page[data-gantt-theme=\"${themeId}\"] .metro-btn.button.is-active {\r\n background: var(--bg-active) !important;\r\n color: var(--text-white) !important;\r\n }\r\n `;\r\n \r\n document.head.appendChild(style);\r\n console.log('✅ Theme styles injected successfully');\r\n console.log('📊 Injected CSS length:', style.textContent.length, 'characters');\r\n \r\n // 验证样式是否正确注入\r\n const injectedStyle = document.getElementById('gantt-theme-styles');\r\n if (injectedStyle) {\r\n console.log('✅ Style element found in DOM');\r\n } else {\r\n console.error('❌ Style element not found in DOM');\r\n }\r\n };\r\n\r\n // 初始化主题 - 增强版\r\n const initTheme = () => {\r\n console.log('🚀 initTheme called');\r\n console.log('📦 ganttContainer:', ganttContainer);\r\n console.log('📦 ganttContainer.value:', ganttContainer?.value);\r\n \r\n // 从localStorage加载保存的主题\r\n try {\r\n const savedTheme = localStorage.getItem('gantt-theme');\r\n if (savedTheme && ganttThemes.find(t => t.id === savedTheme)) {\r\n currentTheme.value = savedTheme;\r\n console.log('💾 Loaded theme from localStorage:', savedTheme);\r\n }\r\n } catch (error) {\r\n console.warn('Failed to load theme from localStorage:', error);\r\n }\r\n \r\n console.log('🎨 Current theme:', currentTheme.value);\r\n \r\n // 先注入样式\r\n injectThemeStyles(currentTheme.value);\r\n \r\n // 查找并设置容器属性\r\n let container = null;\r\n \r\n if (ganttContainer && ganttContainer.value) {\r\n container = ganttContainer.value;\r\n console.log('✅ Using injected container reference');\r\n } else {\r\n // 备用方案:直接查找DOM元素\r\n container = document.querySelector('.gantt-container') || \r\n document.querySelector('.page') ||\r\n document.querySelector('[class*=\"gantt\"]');\r\n console.log('🔍 Using DOM query fallback, found:', container);\r\n }\r\n \r\n if (container) {\r\n container.setAttribute('data-gantt-theme', currentTheme.value);\r\n console.log('✅ Container attribute set to:', currentTheme.value);\r\n \r\n // 同时设置到页面根元素\r\n const pageElement = document.querySelector('.page');\r\n if (pageElement) {\r\n pageElement.setAttribute('data-gantt-theme', currentTheme.value);\r\n console.log('✅ Page element attribute set');\r\n }\r\n } else {\r\n console.warn('⚠️ No container found during initialization');\r\n // 延迟重试\r\n setTimeout(() => {\r\n console.log('🔄 Retrying theme initialization...');\r\n initTheme();\r\n }, 500);\r\n }\r\n \r\n console.log('✅ Theme initialization completed');\r\n };\r\n\r\n // 使用watchEffect监听容器变化\r\n watchEffect(() => {\r\n if (ganttContainer && ganttContainer.value) {\r\n nextTick(() => {\r\n initTheme();\r\n });\r\n }\r\n });\r\n\r\n onMounted(() => {\r\n document.addEventListener('click', handleClickOutside);\r\n // 如果容器还没准备好,延迟初始化\r\n if (!ganttContainer || !ganttContainer.value) {\r\n setTimeout(() => {\r\n initTheme();\r\n }, 200);\r\n }\r\n });\r\n\r\n onUnmounted(() => {\r\n document.removeEventListener('click', handleClickOutside);\r\n onCancelPreview();\r\n });\r\n\r\n return {\r\n t,\r\n availableThemes,\r\n isOpen,\r\n currentTheme,\r\n previewTheme,\r\n fileInput,\r\n toggleSelector,\r\n closeSelector,\r\n selectTheme,\r\n onPreviewTheme,\r\n onCancelPreview,\r\n exportConfig,\r\n importConfig,\r\n handleFileImport\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.gantt-theme-selector {\r\n position: relative;\r\n display: inline-block;\r\n}\r\n\r\n.theme-selector-trigger {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: var(--shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.8)), var(--shadow-outset, 0 2px 4px rgba(0, 0, 0, 0.1));\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n font-family: var(--font-family, 'Segoe UI', sans-serif);\r\n font-size: var(--font-size-base, 12px);\r\n font-weight: var(--font-weight-bold, 600);\r\n color: var(--text-secondary, #666666);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.theme-selector-trigger:hover {\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n color: var(--text-primary, #333333);\r\n}\r\n\r\n.theme-selector-trigger.active {\r\n background: var(--bg-active, linear-gradient(145deg, #0078d4, #106ebe));\r\n color: var(--text-white, #ffffff);\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.theme-icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.theme-arrow {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n transition: transform var(--transition-fast, 0.15s ease);\r\n}\r\n\r\n.theme-arrow.rotated {\r\n transform: rotate(180deg);\r\n}\r\n\r\n.theme-dropdown {\r\n position: absolute;\r\n top: 100%;\r\n right: 0;\r\n z-index: 1000;\r\n width: 480px;\r\n max-height: 600px;\r\n background: var(--bg-content, #ffffff);\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: var(--shadow-outset, 0 2px 4px rgba(0, 0, 0, 0.1)), 0 8px 24px rgba(0, 0, 0, 0.15);\r\n overflow: hidden;\r\n margin-top: 4px;\r\n}\r\n\r\n.theme-dropdown-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 16px 20px;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border-bottom: 1px solid var(--border, #d0d0d0);\r\n}\r\n\r\n.theme-dropdown-header h3 {\r\n margin: 0;\r\n font-size: 16px;\r\n font-weight: var(--font-weight-bold, 600);\r\n color: var(--text-primary, #333333);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.close-btn {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n color: var(--text-secondary, #666666);\r\n}\r\n\r\n.close-btn:hover {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n color: var(--text-primary, #333333);\r\n}\r\n\r\n.theme-grid {\r\n display: grid;\r\n grid-template-columns: repeat(2, 1fr);\r\n gap: 16px;\r\n padding: 20px;\r\n max-height: 400px;\r\n overflow-y: auto;\r\n}\r\n\r\n.theme-card {\r\n position: relative;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n border-radius: 8px;\r\n overflow: hidden;\r\n cursor: pointer;\r\n transition: all var(--transition-normal, 0.25s ease);\r\n}\r\n\r\n.theme-card:hover {\r\n transform: translateY(-2px);\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n}\r\n\r\n.theme-card.active {\r\n border-color: var(--primary, #0078d4);\r\n box-shadow: 0 0 0 2px rgba(0, 120, 212, 0.2);\r\n}\r\n\r\n.theme-card.preview {\r\n border-color: var(--secondary, #0d5aa7);\r\n box-shadow: 0 0 0 2px rgba(13, 90, 167, 0.2);\r\n}\r\n\r\n.theme-preview {\r\n height: 80px;\r\n position: relative;\r\n overflow: hidden;\r\n}\r\n\r\n.theme-preview-content {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n.preview-header {\r\n height: 20px;\r\n opacity: 0.9;\r\n}\r\n\r\n.preview-body {\r\n flex: 1;\r\n padding: 8px;\r\n background: rgba(255, 255, 255, 0.9);\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n}\r\n\r\n.preview-bar {\r\n height: 6px;\r\n background: rgba(0, 0, 0, 0.1);\r\n border-radius: 3px;\r\n}\r\n\r\n.preview-bar.short {\r\n width: 60%;\r\n}\r\n\r\n.preview-bar.medium {\r\n width: 80%;\r\n}\r\n\r\n.theme-info {\r\n padding: 12px;\r\n}\r\n\r\n.theme-name {\r\n margin: 0 0 4px 0;\r\n font-size: 14px;\r\n font-weight: var(--font-weight-bold, 600);\r\n color: var(--text-primary, #333333);\r\n}\r\n\r\n.theme-description {\r\n margin: 0;\r\n font-size: 12px;\r\n color: var(--text-secondary, #666666);\r\n line-height: 1.4;\r\n}\r\n\r\n.theme-status {\r\n position: absolute;\r\n top: 8px;\r\n right: 8px;\r\n}\r\n\r\n.status-badge {\r\n padding: 2px 6px;\r\n font-size: 10px;\r\n font-weight: var(--font-weight-bold, 600);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n border-radius: 10px;\r\n}\r\n\r\n.status-badge.current {\r\n background: var(--primary, #0078d4);\r\n color: var(--text-white, #ffffff);\r\n}\r\n\r\n.status-badge.preview {\r\n background: var(--secondary, #0d5aa7);\r\n color: var(--text-white, #ffffff);\r\n}\r\n\r\n.theme-actions {\r\n display: flex;\r\n gap: 8px;\r\n padding: 16px 20px;\r\n background: var(--bg-secondary, #e8e8e8);\r\n border-top: 1px solid var(--border, #d0d0d0);\r\n}\r\n\r\n.action-btn {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 8px 12px;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border: 1px solid var(--border, #d0d0d0);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n font-family: var(--font-family, 'Segoe UI', sans-serif);\r\n font-size: 11px;\r\n font-weight: var(--font-weight-bold, 600);\r\n color: var(--text-secondary, #666666);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.action-btn:hover {\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n color: var(--text-primary, #333333);\r\n}\r\n\r\n/* 滚动条样式 */\r\n.theme-grid::-webkit-scrollbar {\r\n width: 8px;\r\n}\r\n\r\n.theme-grid::-webkit-scrollbar-track {\r\n background: var(--bg-secondary, #e8e8e8);\r\n}\r\n\r\n.theme-grid::-webkit-scrollbar-thumb {\r\n background: var(--border, #d0d0d0);\r\n border-radius: 4px;\r\n}\r\n\r\n.theme-grid::-webkit-scrollbar-thumb:hover {\r\n background: var(--primary, #0078d4);\r\n}\r\n</style>","<template>\r\n <div class=\"gantt-theme-selector\">\r\n <div class=\"theme-selector-trigger\" @click=\"toggleSelector\" :class=\"{ active: isOpen }\">\r\n <div class=\"theme-icon\">\r\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"theme-text\">主题</span>\r\n <div class=\"theme-arrow\" :class=\"{ rotated: isOpen }\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n\r\n <div class=\"theme-dropdown\" v-show=\"isOpen\" @click.stop>\r\n <div class=\"theme-dropdown-header\">\r\n <h3>选择主题</h3>\r\n <button class=\"close-btn\" @click=\"closeSelector\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"theme-grid\">\r\n <div \r\n v-for=\"theme in availableThemes\" \r\n :key=\"theme.id\"\r\n class=\"theme-card\"\r\n :class=\"{ \r\n active: currentTheme === theme.id,\r\n preview: previewTheme === theme.id \r\n }\"\r\n @click=\"selectTheme(theme.id)\"\r\n @mouseenter=\"onPreviewTheme(theme.id)\"\r\n @mouseleave=\"onCancelPreview\"\r\n >\r\n <div class=\"theme-preview\" :style=\"{ backgroundColor: theme.preview }\">\r\n <div class=\"theme-preview-content\">\r\n <div class=\"preview-header\" :style=\"{ backgroundColor: theme.preview }\"></div>\r\n <div class=\"preview-body\">\r\n <div class=\"preview-bar\"></div>\r\n <div class=\"preview-bar short\"></div>\r\n <div class=\"preview-bar medium\"></div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"theme-info\">\r\n <h4 class=\"theme-name\">{{ t(theme.nameKey) }}</h4>\r\n <p class=\"theme-description\">{{ t(theme.descKey) }}</p>\r\n </div>\r\n <div class=\"theme-status\">\r\n <div v-if=\"currentTheme === theme.id\" class=\"status-badge current\">当前</div>\r\n <div v-else-if=\"previewTheme === theme.id\" class=\"status-badge preview\">预览</div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"theme-actions\">\r\n <button class=\"action-btn\" @click=\"exportConfig\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z\"/>\r\n </svg>\r\n 导出配置\r\n </button>\r\n <button class=\"action-btn\" @click=\"importConfig\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z\"/>\r\n </svg>\r\n 导入配置\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <input \r\n ref=\"fileInput\" \r\n type=\"file\" \r\n accept=\".json\" \r\n style=\"display: none\" \r\n @change=\"handleFileImport\"\r\n >\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, onMounted, onUnmounted, inject, watchEffect, nextTick } from 'vue';\r\nimport { ganttThemes, ganttThemeManager, type GanttTheme } from './themes/GanttThemes';\r\nimport { useI18n } from './i18n';\r\n\r\nexport default defineComponent({\r\n name: 'GanttThemeSelector',\r\n setup() {\r\n const { t } = useI18n();\r\n const isOpen = ref(false);\r\n const currentTheme = ref('metro');\r\n const previewTheme = ref('');\r\n const fileInput = ref<HTMLInputElement>();\r\n const availableThemes = ref<GanttTheme[]>(ganttThemes);\r\n\r\n // 获取甘特图容器引用\r\n const ganttContainer = inject<any>('ganttContainer');\r\n\r\n const toggleSelector = () => {\r\n isOpen.value = !isOpen.value;\r\n };\r\n\r\n const closeSelector = () => {\r\n isOpen.value = false;\r\n onCancelPreview();\r\n };\r\n\r\n const selectTheme = (themeId: string) => {\r\n console.log('🎯 selectTheme called with:', themeId);\r\n console.log('📦 ganttContainer:', ganttContainer);\r\n console.log('📦 ganttContainer.value:', ganttContainer?.value);\r\n \r\n currentTheme.value = themeId;\r\n previewTheme.value = '';\r\n \r\n // 先尝试注入样式,不依赖容器引用\r\n injectThemeStyles(themeId);\r\n \r\n // 查找甘特图容器的多种方式\r\n let container = null;\r\n \r\n if (ganttContainer && ganttContainer.value) {\r\n container = ganttContainer.value;\r\n console.log('✅ Using injected container reference');\r\n } else {\r\n // 备用方案:直接查找DOM元素\r\n container = document.querySelector('.gantt-container') || \r\n document.querySelector('.page') ||\r\n document.querySelector('[class*=\"gantt\"]');\r\n console.log('🔍 Using DOM query fallback, found:', container);\r\n }\r\n \r\n if (container) {\r\n // 设置容器属性\r\n container.setAttribute('data-gantt-theme', themeId);\r\n console.log('✅ Container attribute set:', container.getAttribute('data-gantt-theme'));\r\n \r\n // 同时设置到页面根元素\r\n const pageElement = document.querySelector('.page');\r\n if (pageElement) {\r\n pageElement.setAttribute('data-gantt-theme', themeId);\r\n console.log('✅ Page element attribute set');\r\n }\r\n \r\n // 保存到localStorage\r\n try {\r\n localStorage.setItem('gantt-theme', themeId);\r\n console.log('💾 Theme saved to localStorage:', themeId);\r\n } catch (error) {\r\n console.warn('Failed to save theme:', error);\r\n }\r\n \r\n // 强制触发重绘\r\n setTimeout(() => {\r\n console.log('🔄 Forcing style recalculation...');\r\n if (container) {\r\n container.style.display = 'none';\r\n container.offsetHeight; // 触发重排\r\n container.style.display = '';\r\n }\r\n }, 50);\r\n \r\n } else {\r\n console.error('❌ No gantt container found! Available elements:');\r\n console.log('Available .page elements:', document.querySelectorAll('.page'));\r\n console.log('Available .gantt-container elements:', document.querySelectorAll('.gantt-container'));\r\n console.log('Available elements with gantt in class:', document.querySelectorAll('[class*=\"gantt\"]'));\r\n }\r\n \r\n closeSelector();\r\n };\r\n\r\n const onPreviewTheme = (themeId: string) => {\r\n if (themeId !== currentTheme.value && ganttContainer && ganttContainer.value) {\r\n previewTheme.value = themeId;\r\n \r\n // 临时注入预览主题\r\n injectThemeStyles(themeId);\r\n }\r\n };\r\n\r\n const onCancelPreview = () => {\r\n if (previewTheme.value && ganttContainer && ganttContainer.value) {\r\n previewTheme.value = '';\r\n \r\n // 恢复当前主题\r\n injectThemeStyles(currentTheme.value);\r\n }\r\n };\r\n\r\n const exportConfig = () => {\r\n const config = ganttThemeManager.exportThemeConfig();\r\n const blob = new Blob([config], { type: 'application/json' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = `gantt-theme-config-${new Date().toISOString().split('T')[0]}.json`;\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n URL.revokeObjectURL(url);\r\n };\r\n\r\n const importConfig = () => {\r\n fileInput.value?.click();\r\n };\r\n\r\n const handleFileImport = (event: Event) => {\r\n const file = (event.target as HTMLInputElement).files?.[0];\r\n if (file) {\r\n const reader = new FileReader();\r\n reader.onload = (e) => {\r\n try {\r\n const content = e.target?.result as string;\r\n if (ganttThemeManager.importThemeConfig(content)) {\r\n currentTheme.value = ganttThemeManager.getCurrentTheme();\r\n alert('主题配置导入成功!');\r\n } else {\r\n alert('主题配置文件格式错误!');\r\n }\r\n } catch (error) {\r\n alert('主题配置文件格式错误!');\r\n }\r\n };\r\n reader.readAsText(file);\r\n }\r\n };\r\n\r\n const handleClickOutside = (event: MouseEvent) => {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.gantt-theme-selector')) {\r\n closeSelector();\r\n }\r\n };\r\n\r\n // 动态注入主题样式 - 增强版\r\n const injectThemeStyles = (themeId: string) => {\r\n console.log('🎨 Starting theme injection for:', themeId);\r\n \r\n // 移除之前的主题样式\r\n const existingStyle = document.getElementById('gantt-theme-styles');\r\n if (existingStyle) {\r\n existingStyle.remove();\r\n console.log('🗑️ Removed existing theme styles');\r\n }\r\n \r\n const theme = ganttThemes.find(t => t.id === themeId);\r\n if (!theme) {\r\n console.error('❌ Theme not found:', themeId);\r\n return;\r\n }\r\n \r\n console.log('📋 Theme found:', t(theme.nameKey), 'Variables count:', Object.keys(theme.cssVariables).length);\r\n \r\n // 创建样式元素\r\n const style = document.createElement('style');\r\n style.id = 'gantt-theme-styles';\r\n \r\n // 生成CSS规则\r\n const cssRules = Object.entries(theme.cssVariables)\r\n .map(([property, value]) => `${property}: ${value};`)\r\n .join('\\n ');\r\n \r\n // 创建更强力的CSS内容,使用!important确保优先级\r\n style.textContent = `\r\n /* 甘特图主题样式 - ${themeId} */\r\n .page.gantt-container,\r\n .page.gantt-container *,\r\n .gantt-container,\r\n .gantt-container *,\r\n [data-gantt-theme=\"${themeId}\"],\r\n [data-gantt-theme=\"${themeId}\"] *,\r\n .toolbar,\r\n .toolbar *,\r\n .buttonGroup,\r\n .buttonGroup *,\r\n .metro-btn,\r\n .metro-btn *,\r\n .gantt,\r\n .gantt * {\r\n ${cssRules}\r\n }\r\n \r\n /* 根级别变量 */\r\n :root {\r\n ${cssRules}\r\n }\r\n \r\n /* 强制应用到特定元素 */\r\n .page[data-gantt-theme=\"${themeId}\"] .toolbar {\r\n background: var(--bg-metal-normal) !important;\r\n border-bottom: 1px solid var(--border) !important;\r\n }\r\n \r\n .page[data-gantt-theme=\"${themeId}\"] .buttonGroup {\r\n background: var(--bg-metal-normal) !important;\r\n border: 1px solid var(--border) !important;\r\n }\r\n \r\n .page[data-gantt-theme=\"${themeId}\"] .metro-btn {\r\n background: var(--bg-metal-normal) !important;\r\n color: var(--text-secondary) !important;\r\n border-right: 1px solid var(--border) !important;\r\n }\r\n \r\n .page[data-gantt-theme=\"${themeId}\"] .metro-btn.is-active,\r\n .page[data-gantt-theme=\"${themeId}\"] .metro-btn.button.is-active {\r\n background: var(--bg-active) !important;\r\n color: var(--text-white) !important;\r\n }\r\n `;\r\n \r\n document.head.appendChild(style);\r\n console.log('✅ Theme styles injected successfully');\r\n console.log('📊 Injected CSS length:', style.textContent.length, 'characters');\r\n \r\n // 验证样式是否正确注入\r\n const injectedStyle = document.getElementById('gantt-theme-styles');\r\n if (injectedStyle) {\r\n console.log('✅ Style element found in DOM');\r\n } else {\r\n console.error('❌ Style element not found in DOM');\r\n }\r\n };\r\n\r\n // 初始化主题 - 增强版\r\n const initTheme = () => {\r\n console.log('🚀 initTheme called');\r\n console.log('📦 ganttContainer:', ganttContainer);\r\n console.log('📦 ganttContainer.value:', ganttContainer?.value);\r\n \r\n // 从localStorage加载保存的主题\r\n try {\r\n const savedTheme = localStorage.getItem('gantt-theme');\r\n if (savedTheme && ganttThemes.find(t => t.id === savedTheme)) {\r\n currentTheme.value = savedTheme;\r\n console.log('💾 Loaded theme from localStorage:', savedTheme);\r\n }\r\n } catch (error) {\r\n console.warn('Failed to load theme from localStorage:', error);\r\n }\r\n \r\n console.log('🎨 Current theme:', currentTheme.value);\r\n \r\n // 先注入样式\r\n injectThemeStyles(currentTheme.value);\r\n \r\n // 查找并设置容器属性\r\n let container = null;\r\n \r\n if (ganttContainer && ganttContainer.value) {\r\n container = ganttContainer.value;\r\n console.log('✅ Using injected container reference');\r\n } else {\r\n // 备用方案:直接查找DOM元素\r\n container = document.querySelector('.gantt-container') || \r\n document.querySelector('.page') ||\r\n document.querySelector('[class*=\"gantt\"]');\r\n console.log('🔍 Using DOM query fallback, found:', container);\r\n }\r\n \r\n if (container) {\r\n container.setAttribute('data-gantt-theme', currentTheme.value);\r\n console.log('✅ Container attribute set to:', currentTheme.value);\r\n \r\n // 同时设置到页面根元素\r\n const pageElement = document.querySelector('.page');\r\n if (pageElement) {\r\n pageElement.setAttribute('data-gantt-theme', currentTheme.value);\r\n console.log('✅ Page element attribute set');\r\n }\r\n } else {\r\n console.warn('⚠️ No container found during initialization');\r\n // 延迟重试\r\n setTimeout(() => {\r\n console.log('🔄 Retrying theme initialization...');\r\n initTheme();\r\n }, 500);\r\n }\r\n \r\n console.log('✅ Theme initialization completed');\r\n };\r\n\r\n // 使用watchEffect监听容器变化\r\n watchEffect(() => {\r\n if (ganttContainer && ganttContainer.value) {\r\n nextTick(() => {\r\n initTheme();\r\n });\r\n }\r\n });\r\n\r\n onMounted(() => {\r\n document.addEventListener('click', handleClickOutside);\r\n // 如果容器还没准备好,延迟初始化\r\n if (!ganttContainer || !ganttContainer.value) {\r\n setTimeout(() => {\r\n initTheme();\r\n }, 200);\r\n }\r\n });\r\n\r\n onUnmounted(() => {\r\n document.removeEventListener('click', handleClickOutside);\r\n onCancelPreview();\r\n });\r\n\r\n return {\r\n t,\r\n availableThemes,\r\n isOpen,\r\n currentTheme,\r\n previewTheme,\r\n fileInput,\r\n toggleSelector,\r\n closeSelector,\r\n selectTheme,\r\n onPreviewTheme,\r\n onCancelPreview,\r\n exportConfig,\r\n importConfig,\r\n handleFileImport\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.gantt-theme-selector {\r\n position: relative;\r\n display: inline-block;\r\n}\r\n\r\n.theme-selector-trigger {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 8px 12px;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: var(--shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.8)), var(--shadow-outset, 0 2px 4px rgba(0, 0, 0, 0.1));\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n font-family: var(--font-family, 'Segoe UI', sans-serif);\r\n font-size: var(--font-size-base, 12px);\r\n font-weight: var(--font-weight-bold, 600);\r\n color: var(--text-secondary, #666666);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.theme-selector-trigger:hover {\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n color: var(--text-primary, #333333);\r\n}\r\n\r\n.theme-selector-trigger.active {\r\n background: var(--bg-active, linear-gradient(145deg, #0078d4, #106ebe));\r\n color: var(--text-white, #ffffff);\r\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);\r\n}\r\n\r\n.theme-icon {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.theme-arrow {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n transition: transform var(--transition-fast, 0.15s ease);\r\n}\r\n\r\n.theme-arrow.rotated {\r\n transform: rotate(180deg);\r\n}\r\n\r\n.theme-dropdown {\r\n position: absolute;\r\n top: 100%;\r\n right: 0;\r\n z-index: 1000;\r\n width: 480px;\r\n max-height: 600px;\r\n background: var(--bg-content, #ffffff);\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: var(--shadow-outset, 0 2px 4px rgba(0, 0, 0, 0.1)), 0 8px 24px rgba(0, 0, 0, 0.15);\r\n overflow: hidden;\r\n margin-top: 4px;\r\n}\r\n\r\n.theme-dropdown-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 16px 20px;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border-bottom: 1px solid var(--border, #d0d0d0);\r\n}\r\n\r\n.theme-dropdown-header h3 {\r\n margin: 0;\r\n font-size: 16px;\r\n font-weight: var(--font-weight-bold, 600);\r\n color: var(--text-primary, #333333);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.close-btn {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n color: var(--text-secondary, #666666);\r\n}\r\n\r\n.close-btn:hover {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n color: var(--text-primary, #333333);\r\n}\r\n\r\n.theme-grid {\r\n display: grid;\r\n grid-template-columns: repeat(2, 1fr);\r\n gap: 16px;\r\n padding: 20px;\r\n max-height: 400px;\r\n overflow-y: auto;\r\n}\r\n\r\n.theme-card {\r\n position: relative;\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n border: 1px solid var(--border, #d0d0d0);\r\n border-radius: 8px;\r\n overflow: hidden;\r\n cursor: pointer;\r\n transition: all var(--transition-normal, 0.25s ease);\r\n}\r\n\r\n.theme-card:hover {\r\n transform: translateY(-2px);\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n}\r\n\r\n.theme-card.active {\r\n border-color: var(--primary, #0078d4);\r\n box-shadow: 0 0 0 2px rgba(0, 120, 212, 0.2);\r\n}\r\n\r\n.theme-card.preview {\r\n border-color: var(--secondary, #0d5aa7);\r\n box-shadow: 0 0 0 2px rgba(13, 90, 167, 0.2);\r\n}\r\n\r\n.theme-preview {\r\n height: 80px;\r\n position: relative;\r\n overflow: hidden;\r\n}\r\n\r\n.theme-preview-content {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n.preview-header {\r\n height: 20px;\r\n opacity: 0.9;\r\n}\r\n\r\n.preview-body {\r\n flex: 1;\r\n padding: 8px;\r\n background: rgba(255, 255, 255, 0.9);\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n}\r\n\r\n.preview-bar {\r\n height: 6px;\r\n background: rgba(0, 0, 0, 0.1);\r\n border-radius: 3px;\r\n}\r\n\r\n.preview-bar.short {\r\n width: 60%;\r\n}\r\n\r\n.preview-bar.medium {\r\n width: 80%;\r\n}\r\n\r\n.theme-info {\r\n padding: 12px;\r\n}\r\n\r\n.theme-name {\r\n margin: 0 0 4px 0;\r\n font-size: 14px;\r\n font-weight: var(--font-weight-bold, 600);\r\n color: var(--text-primary, #333333);\r\n}\r\n\r\n.theme-description {\r\n margin: 0;\r\n font-size: 12px;\r\n color: var(--text-secondary, #666666);\r\n line-height: 1.4;\r\n}\r\n\r\n.theme-status {\r\n position: absolute;\r\n top: 8px;\r\n right: 8px;\r\n}\r\n\r\n.status-badge {\r\n padding: 2px 6px;\r\n font-size: 10px;\r\n font-weight: var(--font-weight-bold, 600);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n border-radius: 10px;\r\n}\r\n\r\n.status-badge.current {\r\n background: var(--primary, #0078d4);\r\n color: var(--text-white, #ffffff);\r\n}\r\n\r\n.status-badge.preview {\r\n background: var(--secondary, #0d5aa7);\r\n color: var(--text-white, #ffffff);\r\n}\r\n\r\n.theme-actions {\r\n display: flex;\r\n gap: 8px;\r\n padding: 16px 20px;\r\n background: var(--bg-secondary, #e8e8e8);\r\n border-top: 1px solid var(--border, #d0d0d0);\r\n}\r\n\r\n.action-btn {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 8px 12px;\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border: 1px solid var(--border, #d0d0d0);\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n font-family: var(--font-family, 'Segoe UI', sans-serif);\r\n font-size: 11px;\r\n font-weight: var(--font-weight-bold, 600);\r\n color: var(--text-secondary, #666666);\r\n text-transform: uppercase;\r\n letter-spacing: 0.5px;\r\n}\r\n\r\n.action-btn:hover {\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n color: var(--text-primary, #333333);\r\n}\r\n\r\n/* 滚动条样式 */\r\n.theme-grid::-webkit-scrollbar {\r\n width: 8px;\r\n}\r\n\r\n.theme-grid::-webkit-scrollbar-track {\r\n background: var(--bg-secondary, #e8e8e8);\r\n}\r\n\r\n.theme-grid::-webkit-scrollbar-thumb {\r\n background: var(--border, #d0d0d0);\r\n border-radius: 4px;\r\n}\r\n\r\n.theme-grid::-webkit-scrollbar-thumb:hover {\r\n background: var(--primary, #0078d4);\r\n}\r\n</style>","<template>\r\n <div class=\"language-selector\">\r\n <button \r\n class=\"lang-btn\" \r\n @click=\"toggleDropdown\"\r\n :class=\"{ active: isOpen }\"\r\n :title=\"t('configPanel.languageSettings')\"\r\n >\r\n <div class=\"btn-content\">\r\n <div class=\"btn-icon\">\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"btn-text\">{{ currentLocaleLabel }}</span>\r\n <div class=\"btn-arrow\" :class=\"{ rotated: isOpen }\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n </button>\r\n\r\n <transition name=\"dropdown-fade\">\r\n <div v-if=\"isOpen\" class=\"lang-dropdown\">\r\n <div\r\n v-for=\"locale in locales\"\r\n :key=\"locale.value\"\r\n class=\"lang-option\"\r\n :class=\"{ active: currentLocale === locale.value }\"\r\n @click=\"selectLocale(locale.value)\"\r\n >\r\n <span class=\"lang-label\">{{ locale.label }}</span>\r\n <div v-if=\"currentLocale === locale.value\" class=\"lang-check\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n </div>\r\n </transition>\r\n\r\n <div v-if=\"isOpen\" class=\"dropdown-overlay\" @click=\"closeDropdown\"></div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed, onMounted, onUnmounted } from 'vue';\r\nimport { useI18n, type Locale } from './i18n';\r\n\r\nexport default defineComponent({\r\n name: 'LanguageSelector',\r\n setup() {\r\n const { locale, t, setLocale, getLocales } = useI18n();\r\n const isOpen = ref(false);\r\n\r\n const currentLocale = computed(() => locale.value);\r\n const locales = computed(() => getLocales());\r\n \r\n const currentLocaleLabel = computed(() => {\r\n const current = locales.value.find((l: { value: Locale; label: string }) => l.value === currentLocale.value);\r\n return current?.label || 'Language';\r\n });\r\n\r\n const toggleDropdown = () => {\r\n isOpen.value = !isOpen.value;\r\n };\r\n\r\n const closeDropdown = () => {\r\n isOpen.value = false;\r\n };\r\n\r\n const selectLocale = (localeValue: Locale) => {\r\n setLocale(localeValue);\r\n closeDropdown();\r\n };\r\n\r\n // 点击外部关闭下拉菜单\r\n const handleClickOutside = (event: MouseEvent) => {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.language-selector')) {\r\n closeDropdown();\r\n }\r\n };\r\n\r\n onMounted(() => {\r\n document.addEventListener('click', handleClickOutside);\r\n });\r\n\r\n onUnmounted(() => {\r\n document.removeEventListener('click', handleClickOutside);\r\n });\r\n\r\n return {\r\n isOpen,\r\n currentLocale,\r\n currentLocaleLabel,\r\n locales,\r\n t,\r\n toggleDropdown,\r\n closeDropdown,\r\n selectLocale\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.language-selector {\r\n position: relative;\r\n}\r\n\r\n.lang-btn {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: var(--shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.8));\r\n padding: 8px 12px;\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n font-family: var(--font-family);\r\n display: flex;\r\n align-items: center;\r\n min-width: 140px;\r\n\r\n &:hover {\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n }\r\n\r\n &:active,\r\n &.active {\r\n background: var(--bg-active, linear-gradient(145deg, #0078d4, #106ebe));\r\n\r\n .btn-icon,\r\n .btn-text,\r\n .btn-arrow {\r\n color: var(--text-white, #ffffff);\r\n }\r\n }\r\n\r\n .btn-content {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n width: 100%;\r\n }\r\n\r\n .btn-icon {\r\n color: var(--text-secondary, #666666);\r\n display: flex;\r\n align-items: center;\r\n transition: color var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n .btn-text {\r\n flex: 1;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n transition: color var(--transition-fast, 0.15s ease);\r\n text-align: left;\r\n }\r\n\r\n .btn-arrow {\r\n color: var(--text-secondary, #666666);\r\n display: flex;\r\n align-items: center;\r\n transition: transform var(--transition-fast, 0.15s ease), color var(--transition-fast, 0.15s ease);\r\n\r\n &.rotated {\r\n transform: rotate(180deg);\r\n }\r\n }\r\n}\r\n\r\n.dropdown-overlay {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n z-index: 998;\r\n}\r\n\r\n.lang-dropdown {\r\n position: absolute;\r\n top: calc(100% + 4px);\r\n left: 0;\r\n right: 0;\r\n background: var(--bg-content, #ffffff);\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n z-index: 999;\r\n min-width: 140px;\r\n color: var(--text-primary, #333333);\r\n}\r\n\r\n.lang-option {\r\n padding: 10px 12px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n border-bottom: 1px solid var(--border, #e8e8e8);\r\n color: var(--text-primary, #333333);\r\n\r\n &:last-child {\r\n border-bottom: none;\r\n }\r\n\r\n &:hover {\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n }\r\n\r\n &.active {\r\n background: var(--bg-active-hover, linear-gradient(145deg, #e3f2fd, #bbdefb));\r\n color: var(--primary, #0078d4);\r\n font-weight: 600;\r\n }\r\n\r\n .lang-label {\r\n font-size: 12px;\r\n }\r\n\r\n .lang-check {\r\n color: var(--primary, #0078d4);\r\n display: flex;\r\n align-items: center;\r\n }\r\n}\r\n\r\n.dropdown-fade-enter-active,\r\n.dropdown-fade-leave-active {\r\n transition: opacity 0.15s ease, transform 0.15s ease;\r\n}\r\n\r\n.dropdown-fade-enter-from {\r\n opacity: 0;\r\n transform: translateY(-8px);\r\n}\r\n\r\n.dropdown-fade-leave-to {\r\n opacity: 0;\r\n transform: translateY(-8px);\r\n}\r\n</style>\r\n","<template>\r\n <div class=\"language-selector\">\r\n <button \r\n class=\"lang-btn\" \r\n @click=\"toggleDropdown\"\r\n :class=\"{ active: isOpen }\"\r\n :title=\"t('configPanel.languageSettings')\"\r\n >\r\n <div class=\"btn-content\">\r\n <div class=\"btn-icon\">\r\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z\"/>\r\n </svg>\r\n </div>\r\n <span class=\"btn-text\">{{ currentLocaleLabel }}</span>\r\n <div class=\"btn-arrow\" :class=\"{ rotated: isOpen }\">\r\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M7 10l5 5 5-5z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n </button>\r\n\r\n <transition name=\"dropdown-fade\">\r\n <div v-if=\"isOpen\" class=\"lang-dropdown\">\r\n <div\r\n v-for=\"locale in locales\"\r\n :key=\"locale.value\"\r\n class=\"lang-option\"\r\n :class=\"{ active: currentLocale === locale.value }\"\r\n @click=\"selectLocale(locale.value)\"\r\n >\r\n <span class=\"lang-label\">{{ locale.label }}</span>\r\n <div v-if=\"currentLocale === locale.value\" class=\"lang-check\">\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\r\n <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/>\r\n </svg>\r\n </div>\r\n </div>\r\n </div>\r\n </transition>\r\n\r\n <div v-if=\"isOpen\" class=\"dropdown-overlay\" @click=\"closeDropdown\"></div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed, onMounted, onUnmounted } from 'vue';\r\nimport { useI18n, type Locale } from './i18n';\r\n\r\nexport default defineComponent({\r\n name: 'LanguageSelector',\r\n setup() {\r\n const { locale, t, setLocale, getLocales } = useI18n();\r\n const isOpen = ref(false);\r\n\r\n const currentLocale = computed(() => locale.value);\r\n const locales = computed(() => getLocales());\r\n \r\n const currentLocaleLabel = computed(() => {\r\n const current = locales.value.find((l: { value: Locale; label: string }) => l.value === currentLocale.value);\r\n return current?.label || 'Language';\r\n });\r\n\r\n const toggleDropdown = () => {\r\n isOpen.value = !isOpen.value;\r\n };\r\n\r\n const closeDropdown = () => {\r\n isOpen.value = false;\r\n };\r\n\r\n const selectLocale = (localeValue: Locale) => {\r\n setLocale(localeValue);\r\n closeDropdown();\r\n };\r\n\r\n // 点击外部关闭下拉菜单\r\n const handleClickOutside = (event: MouseEvent) => {\r\n const target = event.target as HTMLElement;\r\n if (!target.closest('.language-selector')) {\r\n closeDropdown();\r\n }\r\n };\r\n\r\n onMounted(() => {\r\n document.addEventListener('click', handleClickOutside);\r\n });\r\n\r\n onUnmounted(() => {\r\n document.removeEventListener('click', handleClickOutside);\r\n });\r\n\r\n return {\r\n isOpen,\r\n currentLocale,\r\n currentLocaleLabel,\r\n locales,\r\n t,\r\n toggleDropdown,\r\n closeDropdown,\r\n selectLocale\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.language-selector {\r\n position: relative;\r\n}\r\n\r\n.lang-btn {\r\n background: var(--bg-metal-normal, linear-gradient(145deg, #f5f5f5, #e8e8e8));\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: var(--shadow-inset, inset 0 1px 0 rgba(255, 255, 255, 0.8));\r\n padding: 8px 12px;\r\n cursor: pointer;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n font-family: var(--font-family);\r\n display: flex;\r\n align-items: center;\r\n min-width: 140px;\r\n\r\n &:hover {\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n }\r\n\r\n &:active,\r\n &.active {\r\n background: var(--bg-active, linear-gradient(145deg, #0078d4, #106ebe));\r\n\r\n .btn-icon,\r\n .btn-text,\r\n .btn-arrow {\r\n color: var(--text-white, #ffffff);\r\n }\r\n }\r\n\r\n .btn-content {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n width: 100%;\r\n }\r\n\r\n .btn-icon {\r\n color: var(--text-secondary, #666666);\r\n display: flex;\r\n align-items: center;\r\n transition: color var(--transition-fast, 0.15s ease);\r\n }\r\n\r\n .btn-text {\r\n flex: 1;\r\n font-size: 12px;\r\n font-weight: 600;\r\n color: var(--text-primary, #333333);\r\n transition: color var(--transition-fast, 0.15s ease);\r\n text-align: left;\r\n }\r\n\r\n .btn-arrow {\r\n color: var(--text-secondary, #666666);\r\n display: flex;\r\n align-items: center;\r\n transition: transform var(--transition-fast, 0.15s ease), color var(--transition-fast, 0.15s ease);\r\n\r\n &.rotated {\r\n transform: rotate(180deg);\r\n }\r\n }\r\n}\r\n\r\n.dropdown-overlay {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n z-index: 998;\r\n}\r\n\r\n.lang-dropdown {\r\n position: absolute;\r\n top: calc(100% + 4px);\r\n left: 0;\r\n right: 0;\r\n background: var(--bg-content, #ffffff);\r\n border: 1px solid var(--border, #d0d0d0);\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n z-index: 999;\r\n min-width: 140px;\r\n color: var(--text-primary, #333333);\r\n}\r\n\r\n.lang-option {\r\n padding: 10px 12px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n transition: all var(--transition-fast, 0.15s ease);\r\n border-bottom: 1px solid var(--border, #e8e8e8);\r\n color: var(--text-primary, #333333);\r\n\r\n &:last-child {\r\n border-bottom: none;\r\n }\r\n\r\n &:hover {\r\n background: var(--bg-metal-light, linear-gradient(145deg, #ffffff, #f5f5f5));\r\n }\r\n\r\n &.active {\r\n background: var(--bg-active-hover, linear-gradient(145deg, #e3f2fd, #bbdefb));\r\n color: var(--primary, #0078d4);\r\n font-weight: 600;\r\n }\r\n\r\n .lang-label {\r\n font-size: 12px;\r\n }\r\n\r\n .lang-check {\r\n color: var(--primary, #0078d4);\r\n display: flex;\r\n align-items: center;\r\n }\r\n}\r\n\r\n.dropdown-fade-enter-active,\r\n.dropdown-fade-leave-active {\r\n transition: opacity 0.15s ease, transform 0.15s ease;\r\n}\r\n\r\n.dropdown-fade-enter-from {\r\n opacity: 0;\r\n transform: translateY(-8px);\r\n}\r\n\r\n.dropdown-fade-leave-to {\r\n opacity: 0;\r\n transform: translateY(-8px);\r\n}\r\n</style>\r\n","<template>\r\n <div class=\"link-config-panel\">\r\n <div class=\"panel-header\">\r\n <h3>连线配置</h3>\r\n <button class=\"close-btn\" @click=\"$emit('close')\" title=\"关闭\">×</button>\r\n </div>\r\n \r\n <div class=\"panel-content\">\r\n <!-- 路径类型选择 -->\r\n <div class=\"config-section\">\r\n <h4>路径类型</h4>\r\n <div class=\"path-type-selector\">\r\n <label \r\n v-for=\"pathType in pathTypes\" \r\n :key=\"pathType.value\"\r\n class=\"path-type-option\"\r\n :class=\"{ active: config.pathType === pathType.value }\"\r\n >\r\n <input \r\n type=\"radio\" \r\n :value=\"pathType.value\" \r\n v-model=\"config.pathType\"\r\n @change=\"updateConfig\"\r\n />\r\n <div class=\"path-preview\">\r\n <svg width=\"60\" height=\"40\" viewBox=\"0 0 60 40\">\r\n <path \r\n :d=\"pathType.preview\" \r\n stroke=\"#3498db\" \r\n stroke-width=\"2\" \r\n fill=\"none\"\r\n />\r\n </svg>\r\n </div>\r\n <span>{{ pathType.name }}</span>\r\n </label>\r\n </div>\r\n </div>\r\n \r\n <!-- 基础样式配置 -->\r\n <div class=\"config-section\">\r\n <h4>基础样式</h4>\r\n <div class=\"config-row\">\r\n <label>颜色:</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"config.color\" \r\n @change=\"updateConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>线宽:</label>\r\n <input \r\n type=\"range\" \r\n min=\"1\" \r\n max=\"5\" \r\n step=\"0.5\"\r\n v-model.number=\"config.width\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.width }}px</span>\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>虚线样式:</label>\r\n <select v-model=\"config.dashArray\" @change=\"updateConfig\" class=\"select-input\">\r\n <option :value=\"undefined\">实线</option>\r\n <option value=\"3,3\">短虚线</option>\r\n <option value=\"5,5\">中虚线</option>\r\n <option value=\"8,4\">长虚线</option>\r\n <option value=\"2,2,8,2\">点划线</option>\r\n </select>\r\n </div>\r\n </div>\r\n \r\n <!-- 路径特定配置 -->\r\n <div class=\"config-section\" v-if=\"config.pathType === 'bezier'\">\r\n <h4>贝塞尔曲线配置</h4>\r\n <div class=\"config-row\">\r\n <label>弯曲度:</label>\r\n <input \r\n type=\"range\" \r\n min=\"0.1\" \r\n max=\"1\" \r\n step=\"0.1\"\r\n v-model.number=\"config.bezierCurvature\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.bezierCurvature }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"config-section\" v-if=\"config.pathType === 'right-angle'\">\r\n <h4>直角连线配置</h4>\r\n <div class=\"config-row\">\r\n <label>偏移距离:</label>\r\n <input \r\n type=\"range\" \r\n min=\"10\" \r\n max=\"80\" \r\n step=\"5\"\r\n v-model.number=\"config.rightAngleOffset\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.rightAngleOffset }}px</span>\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"config.smoothCorners\" \r\n @change=\"updateConfig\"\r\n />\r\n 平滑转角\r\n </label>\r\n </div>\r\n \r\n <div class=\"config-row\" v-if=\"config.smoothCorners\">\r\n <label>转角半径:</label>\r\n <input \r\n type=\"range\" \r\n min=\"0\" \r\n max=\"15\" \r\n step=\"1\"\r\n v-model.number=\"config.cornerRadius\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.cornerRadius }}px</span>\r\n </div>\r\n </div>\r\n \r\n <!-- 箭头配置 -->\r\n <div class=\"config-section\">\r\n <h4>箭头配置</h4>\r\n <div class=\"config-row\">\r\n <label>\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"config.showArrow\" \r\n @change=\"updateConfig\"\r\n />\r\n 显示箭头\r\n </label>\r\n </div>\r\n \r\n <div v-if=\"config.showArrow\">\r\n <div class=\"config-row\">\r\n <label>箭头大小:</label>\r\n <input \r\n type=\"range\" \r\n min=\"4\" \r\n max=\"16\" \r\n step=\"1\"\r\n v-model.number=\"config.arrowSize\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.arrowSize }}px</span>\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>箭头颜色:</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"config.arrowColor\" \r\n @change=\"updateConfig\"\r\n class=\"color-input\"\r\n :placeholder=\"config.color\"\r\n />\r\n <button \r\n @click=\"config.arrowColor = config.color; updateConfig()\" \r\n class=\"sync-btn\"\r\n title=\"与线条颜色同步\"\r\n >\r\n 同步\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- 虚线动画配置 -->\r\n <div class=\"config-section\">\r\n <h4>虚线动画</h4>\r\n <div class=\"config-row\">\r\n <label>\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"config.enableDashAnimation\" \r\n @change=\"updateConfig\"\r\n />\r\n 启用虚线流动动画\r\n </label>\r\n </div>\r\n \r\n <div v-if=\"config.enableDashAnimation\">\r\n <div class=\"config-row\">\r\n <label>动画速度:</label>\r\n <input \r\n type=\"range\" \r\n min=\"0.2\" \r\n max=\"3\" \r\n step=\"0.2\"\r\n v-model.number=\"config.dashAnimationSpeed\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.dashAnimationSpeed }}s</span>\r\n </div>\r\n \r\n <div class=\"config-info\">\r\n <small>💡 虚线动画只在连线设置为虚线样式时显示</small>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- 标签配置 -->\r\n <div class=\"config-section\">\r\n <h4>标签配置</h4>\r\n <div class=\"config-row\">\r\n <label>\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"config.showLabels\" \r\n @change=\"updateConfig\"\r\n />\r\n 显示标签\r\n </label>\r\n </div>\r\n \r\n <div v-if=\"config.showLabels\">\r\n <div class=\"config-row\">\r\n <label>标签颜色:</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"config.labelColor\" \r\n @change=\"updateConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>字体大小:</label>\r\n <input \r\n type=\"range\" \r\n min=\"8\" \r\n max=\"16\" \r\n step=\"1\"\r\n v-model.number=\"config.labelFontSize\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.labelFontSize }}px</span>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- 父子关系样式 -->\r\n <div class=\"config-section\">\r\n <h4>父子关系样式</h4>\r\n <div class=\"config-row\">\r\n <label>颜色:</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"config.parentChildStyle.color\" \r\n @change=\"updateConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>线宽:</label>\r\n <input \r\n type=\"range\" \r\n min=\"1\" \r\n max=\"3\" \r\n step=\"0.5\"\r\n v-model.number=\"config.parentChildStyle.width\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.parentChildStyle.width }}px</span>\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>虚线样式:</label>\r\n <select v-model=\"config.parentChildStyle.dashArray\" @change=\"updateConfig\" class=\"select-input\">\r\n <option :value=\"undefined\">实线</option>\r\n <option value=\"3,3\">短虚线</option>\r\n <option value=\"5,5\">中虚线</option>\r\n <option value=\"8,4\">长虚线</option>\r\n </select>\r\n </div>\r\n </div>\r\n \r\n <!-- 预设主题 -->\r\n <div class=\"config-section\">\r\n <h4>预设主题</h4>\r\n <div class=\"theme-selector\">\r\n <button \r\n v-for=\"(theme, name) in themes\" \r\n :key=\"name\"\r\n @click=\"applyTheme(name)\"\r\n class=\"theme-btn\"\r\n :class=\"{ active: isCurrentTheme(name) }\"\r\n >\r\n {{ getThemeName(name) }}\r\n </button>\r\n </div>\r\n </div>\r\n \r\n <!-- 操作按钮 -->\r\n <div class=\"config-section\">\r\n <div class=\"action-buttons\">\r\n <button @click=\"resetConfig\" class=\"reset-btn\">重置为默认</button>\r\n <button @click=\"exportConfig\" class=\"export-btn\">导出配置</button>\r\n <button @click=\"showImportDialog = true\" class=\"import-btn\">导入配置</button>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- 导入配置对话框 -->\r\n <div v-if=\"showImportDialog\" class=\"import-dialog-overlay\" @click=\"showImportDialog = false\">\r\n <div class=\"import-dialog\" @click.stop>\r\n <h4>导入配置</h4>\r\n <textarea \r\n v-model=\"importText\" \r\n placeholder=\"粘贴配置JSON...\"\r\n class=\"import-textarea\"\r\n ></textarea>\r\n <div class=\"import-actions\">\r\n <button @click=\"importConfig\" class=\"confirm-btn\">导入</button>\r\n <button @click=\"showImportDialog = false\" class=\"cancel-btn\">取消</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed } from 'vue';\r\nimport { LinkPathType, LinkThemes, useLinkConfig } from './LinkConfig';\r\n\r\nexport default defineComponent({\r\n name: 'LinkConfigPanel',\r\n emits: ['close', 'configChange'],\r\n setup(_, { emit }) {\r\n const { \r\n config, \r\n setTheme, \r\n updateConfig: updateLinkConfig, \r\n reset, \r\n exportConfig: exportLinkConfig, \r\n importConfig: importLinkConfig,\r\n themes \r\n } = useLinkConfig();\r\n \r\n const showImportDialog = ref(false);\r\n const importText = ref('');\r\n \r\n // 路径类型选项\r\n const pathTypes = [\r\n {\r\n value: LinkPathType.STRAIGHT,\r\n name: '直线',\r\n preview: 'M 10 20 L 50 20'\r\n },\r\n {\r\n value: LinkPathType.BEZIER,\r\n name: '贝塞尔曲线',\r\n preview: 'M 10 20 C 25 20 35 20 50 20'\r\n },\r\n {\r\n value: LinkPathType.RIGHT_ANGLE,\r\n name: '直角连线',\r\n preview: 'M 10 20 L 30 20 L 30 30 L 50 30'\r\n }\r\n ];\r\n \r\n // 主题名称映射\r\n const themeNames = {\r\n default: '默认',\r\n business: '商务',\r\n modern: '现代',\r\n minimal: '简约',\r\n colorful: '彩色'\r\n };\r\n \r\n const getThemeName = (name: string) => {\r\n return themeNames[name as keyof typeof themeNames] || name;\r\n };\r\n \r\n // 检查是否为当前主题\r\n const isCurrentTheme = (themeName: string) => {\r\n const theme = themes[themeName as keyof typeof themes];\r\n if (!theme) return false;\r\n \r\n return Object.keys(theme).every(key => {\r\n const themeValue = theme[key as keyof typeof theme];\r\n const configValue = config[key as keyof typeof config];\r\n \r\n if (typeof themeValue === 'object' && typeof configValue === 'object') {\r\n return JSON.stringify(themeValue) === JSON.stringify(configValue);\r\n }\r\n \r\n return themeValue === configValue;\r\n });\r\n };\r\n \r\n // 更新配置\r\n const updateConfig = () => {\r\n updateLinkConfig(config);\r\n emit('configChange', config);\r\n };\r\n \r\n // 应用主题\r\n const applyTheme = (themeName: string) => {\r\n setTheme(themeName as keyof typeof LinkThemes);\r\n emit('configChange', config);\r\n };\r\n \r\n // 重置配置\r\n const resetConfig = () => {\r\n reset();\r\n emit('configChange', config);\r\n };\r\n \r\n // 导出配置\r\n const exportConfig = () => {\r\n const configJson = exportLinkConfig();\r\n navigator.clipboard.writeText(configJson).then(() => {\r\n alert('配置已复制到剪贴板');\r\n }).catch(() => {\r\n // 降级方案:显示配置内容\r\n const textarea = document.createElement('textarea');\r\n textarea.value = configJson;\r\n document.body.appendChild(textarea);\r\n textarea.select();\r\n document.execCommand('copy');\r\n document.body.removeChild(textarea);\r\n alert('配置已复制到剪贴板');\r\n });\r\n };\r\n \r\n // 导入配置\r\n const importConfig = () => {\r\n try {\r\n const success = importLinkConfig(importText.value);\r\n if (success) {\r\n showImportDialog.value = false;\r\n importText.value = '';\r\n emit('configChange', config);\r\n alert('配置导入成功');\r\n } else {\r\n alert('配置格式错误,请检查JSON格式');\r\n }\r\n } catch (error) {\r\n alert('配置导入失败:' + error);\r\n }\r\n };\r\n \r\n return {\r\n config,\r\n pathTypes,\r\n themes,\r\n showImportDialog,\r\n importText,\r\n getThemeName,\r\n isCurrentTheme,\r\n updateConfig,\r\n applyTheme,\r\n resetConfig,\r\n exportConfig,\r\n importConfig\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.link-config-panel {\r\n width: 320px;\r\n background: white;\r\n border: 1px solid #ddd;\r\n border-radius: 8px;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n max-height: 80vh;\r\n overflow: hidden;\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n.panel-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 16px 20px;\r\n border-bottom: 1px solid #eee;\r\n background: #f8f9fa;\r\n \r\n h3 {\r\n margin: 0;\r\n font-size: 16px;\r\n font-weight: 600;\r\n color: #333;\r\n }\r\n \r\n .close-btn {\r\n background: none;\r\n border: none;\r\n font-size: 20px;\r\n cursor: pointer;\r\n color: #666;\r\n padding: 0;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: 4px;\r\n \r\n &:hover {\r\n background: #e9ecef;\r\n color: #333;\r\n }\r\n }\r\n}\r\n\r\n.panel-content {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 16px 20px;\r\n}\r\n\r\n.config-section {\r\n margin-bottom: 24px;\r\n \r\n h4 {\r\n margin: 0 0 12px 0;\r\n font-size: 14px;\r\n font-weight: 600;\r\n color: #495057;\r\n }\r\n}\r\n\r\n.path-type-selector {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n.path-type-option {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n padding: 8px 12px;\r\n border: 2px solid #e9ecef;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n \r\n &:hover {\r\n border-color: #3498db;\r\n background: #f8f9ff;\r\n }\r\n \r\n &.active {\r\n border-color: #3498db;\r\n background: #e3f2fd;\r\n }\r\n \r\n input[type=\"radio\"] {\r\n display: none;\r\n }\r\n \r\n .path-preview {\r\n flex-shrink: 0;\r\n }\r\n \r\n span {\r\n font-size: 13px;\r\n color: #495057;\r\n }\r\n}\r\n\r\n.config-row {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n margin-bottom: 12px;\r\n \r\n label {\r\n font-size: 13px;\r\n color: #495057;\r\n min-width: 80px;\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n }\r\n \r\n .value {\r\n font-size: 12px;\r\n color: #6c757d;\r\n min-width: 40px;\r\n text-align: right;\r\n }\r\n}\r\n\r\n.color-input {\r\n width: 40px;\r\n height: 32px;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n padding: 0;\r\n \r\n &::-webkit-color-swatch-wrapper {\r\n padding: 0;\r\n }\r\n \r\n &::-webkit-color-swatch {\r\n border: none;\r\n border-radius: 3px;\r\n }\r\n}\r\n\r\n.range-input {\r\n flex: 1;\r\n height: 6px;\r\n background: #e9ecef;\r\n border-radius: 3px;\r\n outline: none;\r\n \r\n &::-webkit-slider-thumb {\r\n appearance: none;\r\n width: 16px;\r\n height: 16px;\r\n background: #3498db;\r\n border-radius: 50%;\r\n cursor: pointer;\r\n }\r\n \r\n &::-moz-range-thumb {\r\n width: 16px;\r\n height: 16px;\r\n background: #3498db;\r\n border-radius: 50%;\r\n cursor: pointer;\r\n border: none;\r\n }\r\n}\r\n\r\n.select-input {\r\n flex: 1;\r\n padding: 6px 8px;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n font-size: 13px;\r\n background: white;\r\n \r\n &:focus {\r\n outline: none;\r\n border-color: #3498db;\r\n }\r\n}\r\n\r\n.sync-btn {\r\n padding: 4px 8px;\r\n font-size: 11px;\r\n background: #f8f9fa;\r\n border: 1px solid #ddd;\r\n border-radius: 3px;\r\n cursor: pointer;\r\n \r\n &:hover {\r\n background: #e9ecef;\r\n }\r\n}\r\n\r\n.theme-selector {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr;\r\n gap: 8px;\r\n}\r\n\r\n.theme-btn {\r\n padding: 8px 12px;\r\n font-size: 12px;\r\n background: #f8f9fa;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n \r\n &:hover {\r\n background: #e9ecef;\r\n border-color: #adb5bd;\r\n }\r\n \r\n &.active {\r\n background: #3498db;\r\n color: white;\r\n border-color: #3498db;\r\n }\r\n}\r\n\r\n.action-buttons {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n.reset-btn, .export-btn, .import-btn {\r\n padding: 8px 16px;\r\n font-size: 13px;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n}\r\n\r\n.reset-btn {\r\n background: #f8f9fa;\r\n color: #495057;\r\n \r\n &:hover {\r\n background: #e9ecef;\r\n }\r\n}\r\n\r\n.export-btn {\r\n background: #28a745;\r\n color: white;\r\n border-color: #28a745;\r\n \r\n &:hover {\r\n background: #218838;\r\n }\r\n}\r\n\r\n.import-btn {\r\n background: #17a2b8;\r\n color: white;\r\n border-color: #17a2b8;\r\n \r\n &:hover {\r\n background: #138496;\r\n }\r\n}\r\n\r\n.import-dialog-overlay {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n z-index: 1000;\r\n}\r\n\r\n.import-dialog {\r\n background: white;\r\n border-radius: 8px;\r\n padding: 20px;\r\n width: 400px;\r\n max-width: 90vw;\r\n \r\n h4 {\r\n margin: 0 0 16px 0;\r\n font-size: 16px;\r\n color: #333;\r\n }\r\n}\r\n\r\n.import-textarea {\r\n width: 100%;\r\n height: 120px;\r\n padding: 8px;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n font-family: monospace;\r\n font-size: 12px;\r\n resize: vertical;\r\n \r\n &:focus {\r\n outline: none;\r\n border-color: #3498db;\r\n }\r\n}\r\n\r\n.import-actions {\r\n display: flex;\r\n gap: 8px;\r\n margin-top: 16px;\r\n justify-content: flex-end;\r\n}\r\n\r\n.confirm-btn {\r\n padding: 8px 16px;\r\n background: #28a745;\r\n color: white;\r\n border: none;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n \r\n &:hover {\r\n background: #218838;\r\n }\r\n}\r\n\r\n.cancel-btn {\r\n padding: 8px 16px;\r\n background: #6c757d;\r\n color: white;\r\n border: none;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n \r\n &:hover {\r\n background: #5a6268;\r\n }\r\n}\r\n\r\n/* 滚动条样式 */\r\n.panel-content::-webkit-scrollbar {\r\n width: 6px;\r\n}\r\n\r\n.panel-content::-webkit-scrollbar-track {\r\n background: #f1f1f1;\r\n}\r\n\r\n.panel-content::-webkit-scrollbar-thumb {\r\n background: #c1c1c1;\r\n border-radius: 3px;\r\n}\r\n\r\n.panel-content::-webkit-scrollbar-thumb:hover {\r\n background: #a8a8a8;\r\n}\r\n</style>","<template>\r\n <div class=\"link-config-panel\">\r\n <div class=\"panel-header\">\r\n <h3>连线配置</h3>\r\n <button class=\"close-btn\" @click=\"$emit('close')\" title=\"关闭\">×</button>\r\n </div>\r\n \r\n <div class=\"panel-content\">\r\n <!-- 路径类型选择 -->\r\n <div class=\"config-section\">\r\n <h4>路径类型</h4>\r\n <div class=\"path-type-selector\">\r\n <label \r\n v-for=\"pathType in pathTypes\" \r\n :key=\"pathType.value\"\r\n class=\"path-type-option\"\r\n :class=\"{ active: config.pathType === pathType.value }\"\r\n >\r\n <input \r\n type=\"radio\" \r\n :value=\"pathType.value\" \r\n v-model=\"config.pathType\"\r\n @change=\"updateConfig\"\r\n />\r\n <div class=\"path-preview\">\r\n <svg width=\"60\" height=\"40\" viewBox=\"0 0 60 40\">\r\n <path \r\n :d=\"pathType.preview\" \r\n stroke=\"#3498db\" \r\n stroke-width=\"2\" \r\n fill=\"none\"\r\n />\r\n </svg>\r\n </div>\r\n <span>{{ pathType.name }}</span>\r\n </label>\r\n </div>\r\n </div>\r\n \r\n <!-- 基础样式配置 -->\r\n <div class=\"config-section\">\r\n <h4>基础样式</h4>\r\n <div class=\"config-row\">\r\n <label>颜色:</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"config.color\" \r\n @change=\"updateConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>线宽:</label>\r\n <input \r\n type=\"range\" \r\n min=\"1\" \r\n max=\"5\" \r\n step=\"0.5\"\r\n v-model.number=\"config.width\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.width }}px</span>\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>虚线样式:</label>\r\n <select v-model=\"config.dashArray\" @change=\"updateConfig\" class=\"select-input\">\r\n <option :value=\"undefined\">实线</option>\r\n <option value=\"3,3\">短虚线</option>\r\n <option value=\"5,5\">中虚线</option>\r\n <option value=\"8,4\">长虚线</option>\r\n <option value=\"2,2,8,2\">点划线</option>\r\n </select>\r\n </div>\r\n </div>\r\n \r\n <!-- 路径特定配置 -->\r\n <div class=\"config-section\" v-if=\"config.pathType === 'bezier'\">\r\n <h4>贝塞尔曲线配置</h4>\r\n <div class=\"config-row\">\r\n <label>弯曲度:</label>\r\n <input \r\n type=\"range\" \r\n min=\"0.1\" \r\n max=\"1\" \r\n step=\"0.1\"\r\n v-model.number=\"config.bezierCurvature\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.bezierCurvature }}</span>\r\n </div>\r\n </div>\r\n \r\n <div class=\"config-section\" v-if=\"config.pathType === 'right-angle'\">\r\n <h4>直角连线配置</h4>\r\n <div class=\"config-row\">\r\n <label>偏移距离:</label>\r\n <input \r\n type=\"range\" \r\n min=\"10\" \r\n max=\"80\" \r\n step=\"5\"\r\n v-model.number=\"config.rightAngleOffset\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.rightAngleOffset }}px</span>\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"config.smoothCorners\" \r\n @change=\"updateConfig\"\r\n />\r\n 平滑转角\r\n </label>\r\n </div>\r\n \r\n <div class=\"config-row\" v-if=\"config.smoothCorners\">\r\n <label>转角半径:</label>\r\n <input \r\n type=\"range\" \r\n min=\"0\" \r\n max=\"15\" \r\n step=\"1\"\r\n v-model.number=\"config.cornerRadius\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.cornerRadius }}px</span>\r\n </div>\r\n </div>\r\n \r\n <!-- 箭头配置 -->\r\n <div class=\"config-section\">\r\n <h4>箭头配置</h4>\r\n <div class=\"config-row\">\r\n <label>\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"config.showArrow\" \r\n @change=\"updateConfig\"\r\n />\r\n 显示箭头\r\n </label>\r\n </div>\r\n \r\n <div v-if=\"config.showArrow\">\r\n <div class=\"config-row\">\r\n <label>箭头大小:</label>\r\n <input \r\n type=\"range\" \r\n min=\"4\" \r\n max=\"16\" \r\n step=\"1\"\r\n v-model.number=\"config.arrowSize\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.arrowSize }}px</span>\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>箭头颜色:</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"config.arrowColor\" \r\n @change=\"updateConfig\"\r\n class=\"color-input\"\r\n :placeholder=\"config.color\"\r\n />\r\n <button \r\n @click=\"config.arrowColor = config.color; updateConfig()\" \r\n class=\"sync-btn\"\r\n title=\"与线条颜色同步\"\r\n >\r\n 同步\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- 虚线动画配置 -->\r\n <div class=\"config-section\">\r\n <h4>虚线动画</h4>\r\n <div class=\"config-row\">\r\n <label>\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"config.enableDashAnimation\" \r\n @change=\"updateConfig\"\r\n />\r\n 启用虚线流动动画\r\n </label>\r\n </div>\r\n \r\n <div v-if=\"config.enableDashAnimation\">\r\n <div class=\"config-row\">\r\n <label>动画速度:</label>\r\n <input \r\n type=\"range\" \r\n min=\"0.2\" \r\n max=\"3\" \r\n step=\"0.2\"\r\n v-model.number=\"config.dashAnimationSpeed\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.dashAnimationSpeed }}s</span>\r\n </div>\r\n \r\n <div class=\"config-info\">\r\n <small>💡 虚线动画只在连线设置为虚线样式时显示</small>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- 标签配置 -->\r\n <div class=\"config-section\">\r\n <h4>标签配置</h4>\r\n <div class=\"config-row\">\r\n <label>\r\n <input \r\n type=\"checkbox\" \r\n v-model=\"config.showLabels\" \r\n @change=\"updateConfig\"\r\n />\r\n 显示标签\r\n </label>\r\n </div>\r\n \r\n <div v-if=\"config.showLabels\">\r\n <div class=\"config-row\">\r\n <label>标签颜色:</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"config.labelColor\" \r\n @change=\"updateConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>字体大小:</label>\r\n <input \r\n type=\"range\" \r\n min=\"8\" \r\n max=\"16\" \r\n step=\"1\"\r\n v-model.number=\"config.labelFontSize\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.labelFontSize }}px</span>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- 父子关系样式 -->\r\n <div class=\"config-section\">\r\n <h4>父子关系样式</h4>\r\n <div class=\"config-row\">\r\n <label>颜色:</label>\r\n <input \r\n type=\"color\" \r\n v-model=\"config.parentChildStyle.color\" \r\n @change=\"updateConfig\"\r\n class=\"color-input\"\r\n />\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>线宽:</label>\r\n <input \r\n type=\"range\" \r\n min=\"1\" \r\n max=\"3\" \r\n step=\"0.5\"\r\n v-model.number=\"config.parentChildStyle.width\" \r\n @input=\"updateConfig\"\r\n class=\"range-input\"\r\n />\r\n <span class=\"value\">{{ config.parentChildStyle.width }}px</span>\r\n </div>\r\n \r\n <div class=\"config-row\">\r\n <label>虚线样式:</label>\r\n <select v-model=\"config.parentChildStyle.dashArray\" @change=\"updateConfig\" class=\"select-input\">\r\n <option :value=\"undefined\">实线</option>\r\n <option value=\"3,3\">短虚线</option>\r\n <option value=\"5,5\">中虚线</option>\r\n <option value=\"8,4\">长虚线</option>\r\n </select>\r\n </div>\r\n </div>\r\n \r\n <!-- 预设主题 -->\r\n <div class=\"config-section\">\r\n <h4>预设主题</h4>\r\n <div class=\"theme-selector\">\r\n <button \r\n v-for=\"(theme, name) in themes\" \r\n :key=\"name\"\r\n @click=\"applyTheme(name)\"\r\n class=\"theme-btn\"\r\n :class=\"{ active: isCurrentTheme(name) }\"\r\n >\r\n {{ getThemeName(name) }}\r\n </button>\r\n </div>\r\n </div>\r\n \r\n <!-- 操作按钮 -->\r\n <div class=\"config-section\">\r\n <div class=\"action-buttons\">\r\n <button @click=\"resetConfig\" class=\"reset-btn\">重置为默认</button>\r\n <button @click=\"exportConfig\" class=\"export-btn\">导出配置</button>\r\n <button @click=\"showImportDialog = true\" class=\"import-btn\">导入配置</button>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <!-- 导入配置对话框 -->\r\n <div v-if=\"showImportDialog\" class=\"import-dialog-overlay\" @click=\"showImportDialog = false\">\r\n <div class=\"import-dialog\" @click.stop>\r\n <h4>导入配置</h4>\r\n <textarea \r\n v-model=\"importText\" \r\n placeholder=\"粘贴配置JSON...\"\r\n class=\"import-textarea\"\r\n ></textarea>\r\n <div class=\"import-actions\">\r\n <button @click=\"importConfig\" class=\"confirm-btn\">导入</button>\r\n <button @click=\"showImportDialog = false\" class=\"cancel-btn\">取消</button>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed } from 'vue';\r\nimport { LinkPathType, LinkThemes, useLinkConfig } from './LinkConfig';\r\n\r\nexport default defineComponent({\r\n name: 'LinkConfigPanel',\r\n emits: ['close', 'configChange'],\r\n setup(_, { emit }) {\r\n const { \r\n config, \r\n setTheme, \r\n updateConfig: updateLinkConfig, \r\n reset, \r\n exportConfig: exportLinkConfig, \r\n importConfig: importLinkConfig,\r\n themes \r\n } = useLinkConfig();\r\n \r\n const showImportDialog = ref(false);\r\n const importText = ref('');\r\n \r\n // 路径类型选项\r\n const pathTypes = [\r\n {\r\n value: LinkPathType.STRAIGHT,\r\n name: '直线',\r\n preview: 'M 10 20 L 50 20'\r\n },\r\n {\r\n value: LinkPathType.BEZIER,\r\n name: '贝塞尔曲线',\r\n preview: 'M 10 20 C 25 20 35 20 50 20'\r\n },\r\n {\r\n value: LinkPathType.RIGHT_ANGLE,\r\n name: '直角连线',\r\n preview: 'M 10 20 L 30 20 L 30 30 L 50 30'\r\n }\r\n ];\r\n \r\n // 主题名称映射\r\n const themeNames = {\r\n default: '默认',\r\n business: '商务',\r\n modern: '现代',\r\n minimal: '简约',\r\n colorful: '彩色'\r\n };\r\n \r\n const getThemeName = (name: string) => {\r\n return themeNames[name as keyof typeof themeNames] || name;\r\n };\r\n \r\n // 检查是否为当前主题\r\n const isCurrentTheme = (themeName: string) => {\r\n const theme = themes[themeName as keyof typeof themes];\r\n if (!theme) return false;\r\n \r\n return Object.keys(theme).every(key => {\r\n const themeValue = theme[key as keyof typeof theme];\r\n const configValue = config[key as keyof typeof config];\r\n \r\n if (typeof themeValue === 'object' && typeof configValue === 'object') {\r\n return JSON.stringify(themeValue) === JSON.stringify(configValue);\r\n }\r\n \r\n return themeValue === configValue;\r\n });\r\n };\r\n \r\n // 更新配置\r\n const updateConfig = () => {\r\n updateLinkConfig(config);\r\n emit('configChange', config);\r\n };\r\n \r\n // 应用主题\r\n const applyTheme = (themeName: string) => {\r\n setTheme(themeName as keyof typeof LinkThemes);\r\n emit('configChange', config);\r\n };\r\n \r\n // 重置配置\r\n const resetConfig = () => {\r\n reset();\r\n emit('configChange', config);\r\n };\r\n \r\n // 导出配置\r\n const exportConfig = () => {\r\n const configJson = exportLinkConfig();\r\n navigator.clipboard.writeText(configJson).then(() => {\r\n alert('配置已复制到剪贴板');\r\n }).catch(() => {\r\n // 降级方案:显示配置内容\r\n const textarea = document.createElement('textarea');\r\n textarea.value = configJson;\r\n document.body.appendChild(textarea);\r\n textarea.select();\r\n document.execCommand('copy');\r\n document.body.removeChild(textarea);\r\n alert('配置已复制到剪贴板');\r\n });\r\n };\r\n \r\n // 导入配置\r\n const importConfig = () => {\r\n try {\r\n const success = importLinkConfig(importText.value);\r\n if (success) {\r\n showImportDialog.value = false;\r\n importText.value = '';\r\n emit('configChange', config);\r\n alert('配置导入成功');\r\n } else {\r\n alert('配置格式错误,请检查JSON格式');\r\n }\r\n } catch (error) {\r\n alert('配置导入失败:' + error);\r\n }\r\n };\r\n \r\n return {\r\n config,\r\n pathTypes,\r\n themes,\r\n showImportDialog,\r\n importText,\r\n getThemeName,\r\n isCurrentTheme,\r\n updateConfig,\r\n applyTheme,\r\n resetConfig,\r\n exportConfig,\r\n importConfig\r\n };\r\n }\r\n});\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n.link-config-panel {\r\n width: 320px;\r\n background: white;\r\n border: 1px solid #ddd;\r\n border-radius: 8px;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\r\n max-height: 80vh;\r\n overflow: hidden;\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n.panel-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n padding: 16px 20px;\r\n border-bottom: 1px solid #eee;\r\n background: #f8f9fa;\r\n \r\n h3 {\r\n margin: 0;\r\n font-size: 16px;\r\n font-weight: 600;\r\n color: #333;\r\n }\r\n \r\n .close-btn {\r\n background: none;\r\n border: none;\r\n font-size: 20px;\r\n cursor: pointer;\r\n color: #666;\r\n padding: 0;\r\n width: 24px;\r\n height: 24px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n border-radius: 4px;\r\n \r\n &:hover {\r\n background: #e9ecef;\r\n color: #333;\r\n }\r\n }\r\n}\r\n\r\n.panel-content {\r\n flex: 1;\r\n overflow-y: auto;\r\n padding: 16px 20px;\r\n}\r\n\r\n.config-section {\r\n margin-bottom: 24px;\r\n \r\n h4 {\r\n margin: 0 0 12px 0;\r\n font-size: 14px;\r\n font-weight: 600;\r\n color: #495057;\r\n }\r\n}\r\n\r\n.path-type-selector {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n.path-type-option {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n padding: 8px 12px;\r\n border: 2px solid #e9ecef;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n \r\n &:hover {\r\n border-color: #3498db;\r\n background: #f8f9ff;\r\n }\r\n \r\n &.active {\r\n border-color: #3498db;\r\n background: #e3f2fd;\r\n }\r\n \r\n input[type=\"radio\"] {\r\n display: none;\r\n }\r\n \r\n .path-preview {\r\n flex-shrink: 0;\r\n }\r\n \r\n span {\r\n font-size: 13px;\r\n color: #495057;\r\n }\r\n}\r\n\r\n.config-row {\r\n display: flex;\r\n align-items: center;\r\n gap: 12px;\r\n margin-bottom: 12px;\r\n \r\n label {\r\n font-size: 13px;\r\n color: #495057;\r\n min-width: 80px;\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n }\r\n \r\n .value {\r\n font-size: 12px;\r\n color: #6c757d;\r\n min-width: 40px;\r\n text-align: right;\r\n }\r\n}\r\n\r\n.color-input {\r\n width: 40px;\r\n height: 32px;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n padding: 0;\r\n \r\n &::-webkit-color-swatch-wrapper {\r\n padding: 0;\r\n }\r\n \r\n &::-webkit-color-swatch {\r\n border: none;\r\n border-radius: 3px;\r\n }\r\n}\r\n\r\n.range-input {\r\n flex: 1;\r\n height: 6px;\r\n background: #e9ecef;\r\n border-radius: 3px;\r\n outline: none;\r\n \r\n &::-webkit-slider-thumb {\r\n appearance: none;\r\n width: 16px;\r\n height: 16px;\r\n background: #3498db;\r\n border-radius: 50%;\r\n cursor: pointer;\r\n }\r\n \r\n &::-moz-range-thumb {\r\n width: 16px;\r\n height: 16px;\r\n background: #3498db;\r\n border-radius: 50%;\r\n cursor: pointer;\r\n border: none;\r\n }\r\n}\r\n\r\n.select-input {\r\n flex: 1;\r\n padding: 6px 8px;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n font-size: 13px;\r\n background: white;\r\n \r\n &:focus {\r\n outline: none;\r\n border-color: #3498db;\r\n }\r\n}\r\n\r\n.sync-btn {\r\n padding: 4px 8px;\r\n font-size: 11px;\r\n background: #f8f9fa;\r\n border: 1px solid #ddd;\r\n border-radius: 3px;\r\n cursor: pointer;\r\n \r\n &:hover {\r\n background: #e9ecef;\r\n }\r\n}\r\n\r\n.theme-selector {\r\n display: grid;\r\n grid-template-columns: 1fr 1fr;\r\n gap: 8px;\r\n}\r\n\r\n.theme-btn {\r\n padding: 8px 12px;\r\n font-size: 12px;\r\n background: #f8f9fa;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n \r\n &:hover {\r\n background: #e9ecef;\r\n border-color: #adb5bd;\r\n }\r\n \r\n &.active {\r\n background: #3498db;\r\n color: white;\r\n border-color: #3498db;\r\n }\r\n}\r\n\r\n.action-buttons {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n.reset-btn, .export-btn, .import-btn {\r\n padding: 8px 16px;\r\n font-size: 13px;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n}\r\n\r\n.reset-btn {\r\n background: #f8f9fa;\r\n color: #495057;\r\n \r\n &:hover {\r\n background: #e9ecef;\r\n }\r\n}\r\n\r\n.export-btn {\r\n background: #28a745;\r\n color: white;\r\n border-color: #28a745;\r\n \r\n &:hover {\r\n background: #218838;\r\n }\r\n}\r\n\r\n.import-btn {\r\n background: #17a2b8;\r\n color: white;\r\n border-color: #17a2b8;\r\n \r\n &:hover {\r\n background: #138496;\r\n }\r\n}\r\n\r\n.import-dialog-overlay {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n background: rgba(0, 0, 0, 0.5);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n z-index: 1000;\r\n}\r\n\r\n.import-dialog {\r\n background: white;\r\n border-radius: 8px;\r\n padding: 20px;\r\n width: 400px;\r\n max-width: 90vw;\r\n \r\n h4 {\r\n margin: 0 0 16px 0;\r\n font-size: 16px;\r\n color: #333;\r\n }\r\n}\r\n\r\n.import-textarea {\r\n width: 100%;\r\n height: 120px;\r\n padding: 8px;\r\n border: 1px solid #ddd;\r\n border-radius: 4px;\r\n font-family: monospace;\r\n font-size: 12px;\r\n resize: vertical;\r\n \r\n &:focus {\r\n outline: none;\r\n border-color: #3498db;\r\n }\r\n}\r\n\r\n.import-actions {\r\n display: flex;\r\n gap: 8px;\r\n margin-top: 16px;\r\n justify-content: flex-end;\r\n}\r\n\r\n.confirm-btn {\r\n padding: 8px 16px;\r\n background: #28a745;\r\n color: white;\r\n border: none;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n \r\n &:hover {\r\n background: #218838;\r\n }\r\n}\r\n\r\n.cancel-btn {\r\n padding: 8px 16px;\r\n background: #6c757d;\r\n color: white;\r\n border: none;\r\n border-radius: 4px;\r\n cursor: pointer;\r\n \r\n &:hover {\r\n background: #5a6268;\r\n }\r\n}\r\n\r\n/* 滚动条样式 */\r\n.panel-content::-webkit-scrollbar {\r\n width: 6px;\r\n}\r\n\r\n.panel-content::-webkit-scrollbar-track {\r\n background: #f1f1f1;\r\n}\r\n\r\n.panel-content::-webkit-scrollbar-thumb {\r\n background: #c1c1c1;\r\n border-radius: 3px;\r\n}\r\n\r\n.panel-content::-webkit-scrollbar-thumb:hover {\r\n background: #a8a8a8;\r\n}\r\n</style>","import type { App } from 'vue';\r\nimport Gantt from './components/gantt/Gantt.vue';\r\n\r\n// 导出组件\r\nexport { default as Gantt } from './components/gantt/Gantt.vue';\r\nexport { default } from './components/gantt/Gantt.vue';\r\n\r\n// 导出辅助组件\r\nexport { default as DatePicker } from './components/gantt/DatePicker.vue';\r\nexport { default as GanttThemeSelector } from './components/gantt/GanttThemeSelector.vue';\r\nexport { default as LanguageSelector } from './components/gantt/LanguageSelector.vue';\r\nexport { default as GanttConfigPanel } from './components/gantt/GanttConfigPanel.vue';\r\nexport { default as LinkConfigPanel } from './components/gantt/LinkConfigPanel.vue';\r\n\r\n// 导出类型定义\r\nexport type {\r\n DataConfig,\r\n StyleConfig,\r\n EventConfig,\r\n TaskHeader,\r\n LinkConfig,\r\n TaskLink,\r\n TaskDependency,\r\n ProgressUpdateDetail,\r\n LinkTypeColors,\r\n LinkTypeVisibility\r\n} from './components/gantt/Types';\r\n\r\n// 导出枚举\r\nexport { LinkType, LinkPathType } from './components/gantt/Types';\r\n\r\n// 导出主题系统\r\nexport { ganttThemes, type GanttTheme } from './components/gantt/themes/GanttThemes.ts';\r\n\r\n// 导出连线配置\r\nexport { LinkThemes, useLinkConfig, linkDataManager } from './components/gantt/LinkConfig';\r\n\r\n// 导出国际化系统\r\nexport { useI18n, setLocale, type Locale } from './components/gantt/i18n';\r\n\r\n// 导出 Store (可选,高级用户可能需要)\r\nexport { store, mutations } from './components/gantt/Store';\r\n\r\n// 支持 Vue.use() 安装\r\nexport const install = (app: App) => {\r\n app.component('Gantt', Gantt);\r\n app.component('Vue3Gantt', Gantt);\r\n};\r\n\r\n// 版本信息\r\nexport const version = '1.0.0';\r\n"],"names":["e","t","module","this","n","r","i","o","s","a","f","h","u","d","c","l","m","M","Y","p","v","D","w","g","y","L","_","require$$0","SetBarColorSymbol","AddRootTaskSymbol","Symbols","LinkType","LinkPathType","LinkThemes","LinkTypeConfig","LinkConfigManager","__publicField","reactive","stored","parsedConfig","error","themeName","newConfig","linkType","typeConfig","configJson","importedConfig","linkConfigManager","useLinkConfig","LinkDataManager","parsedDependencies","dependency","id","index","dep","taskId","sourceId","targetId","visited","recursionStack","hasCycle","nodeId","dependencies","result","linkDataManager","zhCN","enUS","jaJP","koKR","frFR","deDE","esES","ruRU","messages","currentLocale","ref","savedLocale","key","keys","value","k","setLocale","locale","getLocale","getLocales","useI18n","computed","_sfc_main$h","defineComponent","props","emit","getDayjsLocale","getWeekNames","dayjsLocale","weekNames","day","dayjs","getMonthName","month","selectDate","showDate","copyMinDate","copyMaxDate","fadeXType","nextMonthClick","prevMonthClick","showYear","showMonth","yearListRef","monthListRef","showCalendar","selectedDateText","calendarRef","inputRef","hoveredYearIndex","hoveredMonthIndex","hoveredDayIndex","yearList","monthList","rows","year","months","row","weekValue","addRowEmptyValue","addRowDayValue","keepDoubleDigit","number","splitDate","date","addStr","splitValue","initDatePicker","splitResult","dateObj","dateFormat","watchEffect","onBeforeMount","count","showDateValue","newValue","isMinLimitMonth","isMaxLimitMonth","prevMonth","nextMonth","resetSelectDate","dayValue","selectDay","days","week","weekStr","monthStr","selectMonth","type","daysInMonth","selectYear","openYearList","openMonthList","openCalendarList","clearDate","handleClickOutside","event","isYearHovered","isMonthHovered","isDayHovered","col","handleYearMouseEnter","handleYearMouseLeave","handleMonthMouseEnter","handleMonthMouseLeave","handleDayMouseEnter","handleDayMouseLeave","onMounted","onUnmounted","_hoisted_2","_hoisted_3","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_15","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_sfc_render","_ctx","_cache","$props","$setup","$data","$options","_createElementBlock","_createElementVNode","_hoisted_1","_withDirectives","$event","_vModelText","_openBlock","args","_createCommentVNode","_hoisted_4","_hoisted_5","_createVNode","_Transition","_normalizeClass","_toDisplayString","_hoisted_6","_createTextVNode","_hoisted_7","_withCtx","_Fragment","_renderList","weekName","dayIndex","_vShow","item","_sfc_main$g","splitPane","trigger","triggerLeftOffset","triggerBackGroud","lengthType","triggerDefaultColor","triggerMoveColor","paneLengthValue","triggerLengthValue","nextTick","handleMouseLeave","handleMouseOver","handleMouseDown","handleMouseMove","handleMouseUp","clientRect","paneLengthPercent","direction","_normalizeStyle","_sfc_main$f","resizing","resizingIndex","startX","startWidth","currentHeaderElement","getHeaderTitle","header","translationKey","startResize","target","rafId","deltaX","newWidth","cell","finalWidth","initialStore","store","mutations","monthHeaders","dayHeaders","tasks","taskHeaders","weekHeaders","hourHeaders","scale","mapFields","timelineCellCount","startGanttDate","endGanttDate","scrollFlag","mode","expandRow","rootTask","subTask","editTask","removeTask","barDate","task","sharedState","scrollTop","setScrollTop","setScrollFlag","useScrollState","_sfc_main$e","showRow","hover","addTips","removeTips","collapsedTasks","inject","addRootTask","hasChildren","currentId","isCollapsed","isLastChild","parentId","siblings","getAncestorLines","lines","treeLevel","currentLineLevel","path","currentTask","parent","node","nodeTreeLevel","toggleCollapse","setSubTask","setEditTask","setRemoveTask","checkField","property","watch","newId","headerIndex","rowHeight","level","_withModifiers","_sfc_main$d","TaskRow","hiddenTask","getAllCollapsedChildren","collapsedChildren","collectChildren","pid","child","childId","hiddenTaskIds","obj","filterTask","hiddenIds","allCollapsedIds","collapsedId","newVal","recursionRow","findRows","_resolveComponent","headers","_createBlock","_component_TaskRow","_sfc_main$c","TaskRecursionRow","taskContent","contentHeight","getRootNode","scroll","mouseover","syncScrollHeight","rightContent","handleResize","isBetween","_sfc_main$b","TaskHeader","TaskContent","setRootTask","_component_TaskHeader","_component_TaskContent","_sfc_main$a","toRefs","title","isToday","isoWeek","_sfc_main$9","bar","barHeight","oldBarDataX","oldBarWidth","barColor","isBarInteracted","themeVersion","isProgressDragging","progress","progressValue","setBarColor","emitProgressUpdate","newProgress","detail","hoverActive","hoverInactive","WeekEndColor","bgContent","bgSecondary","element","currentDate","setBarDate","setAllowChangeTaskDate","drowBar","barElement","dataX","fromPlanStartDays","spendDays","startGanttWeek","taskStartWeek","fromPlanStartWeeks","spendWeeks","fromPlanStartHours","spendHours","svg","SVG","borderColor","innerRect","outerRect","text","progressHandle","add","innerRectWidth","textBBox","handleWidth","handleHeight","handleX","handleY","lineX","getThemeColors","primary","primaryDark","primaryLight","guideLineEl","themeColors","line","handleElement","trianglePoints","currentHandleX","colors","interact","newLineX","x","currentX","alignedX","parentIdField","currentParentId","parentTask","parentStartX","ganttStartWeek","cellsMoved","daysOffset","hoursOffset","startWeek","endWeek","newParentStartDate","currentTaskId","getAllChildren","children","childTasks","widthCells","startCellIndex","endCellIndex","newStartDate","newEndDate","childOffset","ganttContainer","observer","onBeforeUnmount","onDeactivated","_sfc_main$8","componentKey","allTask","setExpandRow","Bar","_component_Bar","_sfc_main$7","links","getTaskPosition","svgBar","rightTableContent","barWidth","barRowRect","containerRect","relativeY","getChildIndex","getRowHeight","firstBarRow","alignToGridCenter","getChildRowCenter","parentY","childIndex","getSafeBypassY","childY","gap","minBypassY","getLinkTypeColor","getLinkStyle","generateLinkPath","source","linkId","pathType","generateParentChildPath","generateFinishToStartPath","generateStartToStartPath","generateFinishToFinishPath","generateStartToFinishPath","_linkId","startY","arrowSize","endX","endY","generateParentToChildPath","deltaY","generateBezierPath","generateRightAnglePath","_childIndex","bezierCurvature","curvature","cp1X","cp2X","bypassY","rightAngleOffset","smoothCorners","cornerRadius","midX","midX1","midX2","generateConnectionPath","connectionType","generateBezierConnectionPath","generateRightAngleConnectionPath","curvatureOffset","leftGap","leftOffsetX","leftCurvature","midY","rightGap","rightOffsetX","rightCurvature","crossCurvature","crossCp1X","crossCp2X","offset","crossMidX","generateArrowPoints","childPos","_linkType","tipX","tipY","baseX","baseY1","baseY2","generateDependencyArrowPoints","sourcePos","targetPos","arrowPoint1X","arrowPoint1Y","arrowPoint2X","arrowPoint2Y","isTaskCollapsed","updateLinks","newLinks","visibility","parentPos","parentPosWithId","childPosWithId","arrowPoints","shouldShowLinkType","sourcePosWithId","targetPosWithId","labelMap","resizeObserver","mutationObserver","container","shouldUpdate","mutation","attrName","_a","_b","isDashedLine","style","link","speed","adjustedSpeed","dashLength","sum","part","getDashAnimationStyle","linkConfig","_sfc_main$6","BarRecursionRow","TaskLinks","barContent","containerWidth","containerHeight","_component_TaskLinks","_component_BarRecursionRow","_sfc_main$5","TimelineHeader","TableContent","tableBar","scrollToToday","currentWeekStart","ganttWeekStart","_component_TimelineHeader","ganttThemes","_GanttThemeManager","themeId","theme","savedTheme","config","GanttThemeManager","ganttThemeManager","_sfc_main$4","isOpen","themes","currentTheme","locales","selectLocale","localeValue","updateLinkConfigManager","_c","_d","_e","_f","_g","_h","_i","_j","_k","_l","pathTypes","togglePanel","closePanel","selectTheme","selectPathType","updateLinkConfig","_hoisted_14","_hoisted_20","_hoisted_21","_hoisted_25","_hoisted_26","_hoisted_28","_hoisted_30","_hoisted_31","_hoisted_32","_hoisted_34","_hoisted_35","_hoisted_36","_hoisted_37","_hoisted_38","_hoisted_39","_hoisted_40","_hoisted_41","_hoisted_44","_hoisted_45","_hoisted_46","_hoisted_47","_hoisted_48","_hoisted_50","_hoisted_51","_hoisted_52","_hoisted_53","_hoisted_54","_hoisted_55","_hoisted_56","_hoisted_57","_hoisted_58","_hoisted_59","_hoisted_60","_hoisted_62","_hoisted_63","_hoisted_64","_hoisted_65","_hoisted_66","_hoisted_67","_hoisted_68","_hoisted_72","_hoisted_73","_hoisted_74","_hoisted_76","_hoisted_77","_hoisted_78","_hoisted_79","_hoisted_80","_hoisted_83","_hoisted_84","_hoisted_85","_hoisted_86","_hoisted_87","_hoisted_90","_hoisted_91","_hoisted_92","_hoisted_93","_hoisted_94","_hoisted_97","_hoisted_98","_hoisted_99","_hoisted_100","_hoisted_104","_hoisted_105","_hoisted_106","_hoisted_107","_hoisted_108","_hoisted_109","_hoisted_110","_hoisted_111","_hoisted_112","_hoisted_113","_hoisted_114","_hoisted_115","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_27","_hoisted_29","_hoisted_42","_hoisted_43","_hoisted_49","_vModelCheckbox","_hoisted_61","_hoisted_69","_hoisted_70","_hoisted_71","_hoisted_75","_hoisted_81","_hoisted_82","_hoisted_88","_hoisted_89","_hoisted_95","_hoisted_96","_hoisted_101","_hoisted_102","_hoisted_103","_hoisted_116","z","customParseFormat","_sfc_main$3","DatePicker","SplitPane","TaskTable","RightTable","GanttConfigPanel","dataSource","linkTypeVisibility","updateLinkVisibility","initData","buttonClass","startDate","minStartDate","maxStartDate","showStartDatePicker","selectedStartDate","endDate","minEndDate","maxEndDate","showEndDatePicker","selectedEndDate","allowChangeTaskDate","setTimeLineHeaders","start","end","current","endOfMonth","startOfMonth","caption","fullDate","monthCurrent","monthStart","monthEnd","weekCount","weekCurrent","weekStart","weekEnd","monthTitle","weekTitle","endOfEndDay","needsHourSuffix","FindAllParent","targetData","RecursionData","findResult","timeMode","_mode","barContentEl","confirmStart","confirmEnd","newMode","oldMode","oldStartDate","oldEndDate","newScale","newHeaders","newMonth","newDay","newWeek","newHour","newFields","newCount","handleProgressUpdate","customEvent","updateTimer","provide","newDependencies","onLinkConfigChange","linkTypeColors","_hoisted_33","_component_SplitPane","_component_DatePicker","styleConfig","_component_RightTable","_sfc_main$2","previewTheme","fileInput","availableThemes","toggleSelector","closeSelector","onCancelPreview","injectThemeStyles","pageElement","onPreviewTheme","exportConfig","blob","url","importConfig","handleFileImport","file","reader","content","existingStyle","cssRules","initTheme","_sfc_main$1","currentLocaleLabel","toggleDropdown","closeDropdown","_sfc_main","setTheme","reset","exportLinkConfig","importLinkConfig","showImportDialog","importText","themeNames","name","themeValue","configValue","textarea","_vModelRadio","applyTheme","getThemeName","install","app","Gantt","version"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4,5,6,7,8,35,40]}
|