| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691 |
- <template>
- <Water></Water>
- <scroll-view
- class="detail-page"
- :style="{ height: pageHeight }"
- :scroll-top="scrollTopValue"
- :scroll-into-view="scrollIntoViewId"
- scroll-y="true"
- scroll-with-animation
- lower-threshold="80"
- @scroll="onPageScroll"
- @scrolltolower="onTimelineScrollToLower"
- v-if="!!data && !loading"
- >
- <view id="detailPageTopAnchor"></view>
- <view
- class="detail-card detail-bg"
- :style="{ backgroundImage: 'url(' + bg + ')' }"
- >
- <view class="detail-drug-title">{{ data.physicName }}</view>
- <view class="detail-row detail-traceability">
- <view class="detail-label">追溯码:</view>
- <view class="detail-value detail-wrap">{{
- formatTraceCode(traceCode)
- }}</view>
- <view class="detail-copy-btn" @click="copy(traceCode)">
- <image
- src="../../../static/images/copy.png"
- mode="scaleToFill"
- :style="{ width: '30rpx', height: '30rpx' }"
- />
- </view>
- </view>
- <view class="detail-row">
- <view class="detail-label">生产企业:</view>
- <view
- class="detail-value detail-wrap detail-company-value"
- :class="{ 'detail-clamp': !companyExpanded }"
- :style="{ marginBottom: needCompanyToggle ? '40rpx' : undefined }"
- id="companyValue"
- >
- <text>{{ data.produceEntName }}</text>
- </view>
- <text
- v-if="needCompanyToggle"
- class="detail-expand-tag"
- @click="toggleCompanyExpand"
- >{{ companyExpanded ? "收起" : "展开" }}</text
- >
- </view>
- <view class="detail-row">
- <view class="detail-label">批准文号:</view>
- <view class="detail-value">{{ data.approveNo }}</view>
- </view>
- <view class="detail-row">
- <view class="detail-label">生产日期:</view>
- <view class="detail-value">{{ data.produceDate }}</view>
- </view>
- <view class="detail-row" v-show="cardExpanded">
- <view class="detail-label">产品批号:</view>
- <view class="detail-value">{{ data.produceBatchNo }}</view>
- </view>
- <view class="detail-row" v-show="cardExpanded">
- <view class="detail-label">
- 剂<text :style="{ opacity: 0 }">剂型</text>型:</view
- >
- <view class="detail-value">{{ data.prepnDesc }}</view>
- </view>
- <view class="detail-row" v-show="cardExpanded">
- <view class="detail-label">包装规格:</view>
- <view class="detail-value">{{ data.prepnSpec }}</view>
- </view>
- <view class="detail-row" v-show="cardExpanded">
- <view class="detail-label">有效期至:</view>
- <view class="detail-value">{{ data.validEndDate }}</view>
- </view>
- <view class="detail-card-toggle" @click="toggleCardExpand">
- <uni-icons
- :type="cardExpanded ? 'up' : 'down'"
- size="18"
- color="#9aa4b2"
- ></uni-icons>
- </view>
- </view>
- <view
- class="detail-timeline detail-bg"
- :style="{ backgroundImage: 'url(' + bg + ')' }"
- >
- <view class="detail-section-header">
- <view class="detail-section-title">扫码跟踪</view>
- <!-- <view class="detail-section-actions">
- <view class="detail-section-action" @tap="toggleTimelineView">
- <uni-icons
- :type="timelineView === 'text' ? 'image' : 'list'"
- size="20"
- color="#59a8f2"
- ></uni-icons>
- <text>{{ timelineView === "text" ? "查看图形" : "查看文字" }}</text>
- </view>
- <view class="detail-section-action" @tap="onSetDefaultView">
- <uni-icons type="gear" size="20" color="#59a8f2"></uni-icons>
- <text>设置默认</text>
- </view>
- </view> -->
- </view>
- <!-- <view class="detail-graph-panel" v-if="timelineView === 'graph'">
- <view class="graph-mode-row">
- <view class="graph-mode-left">
- <view class="graph-mode-title">货权流向模式</view>
- <view class="graph-mode-desc"
- >开启后则会按照码的实际实物货权关系,将委托企业(若有)还原到收发货企业上并绘制流向图。</view
- >
- </view>
- <switch
- :checked="ownershipFlowMode"
- color="#2c69ff"
- @change="onOwnershipModeChange"
- />
- </view>
- <view
- :style="{
- width: graphViewWidth + 'px',
- height: graphViewHeight + 'px',
- }"
- v-if="isShowGraph"
- >
- <l-echart
- ref="chartRef"
- :beforeDelay="180"
- :lStyle="`width:${graphViewWidth}px;height:${graphViewHeight}px;`"
- @finished="initChart"
- ></l-echart>
- </view>
- <view
- :style="{
- width: graphViewWidth + 'px',
- height: graphViewHeight + 'px',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- }"
- v-else
- >
- 链路过长无法展示
- </view>
- </view> -->
- <view class="detail-timeline-toolbar" v-if="timelineView === 'text'">
- <view class="detail-toolbar-btn" @tap.stop="setAllTimelineDetail(true)"
- >全部展示详情</view
- >
- <view class="detail-toolbar-btn" @tap.stop="setAllTimelineDetail(false)"
- >全部展示概要</view
- >
- </view>
- <view
- v-if="timelineView === 'text'"
- class="detail-timeline-item"
- :class="{ 'detail-timeline-item-first': i === 0 }"
- v-for="(value, i) in visibleBillDetailList"
- :key="i"
- >
- <view class="detail-left">
- <view class="detail-dot" :class="{ 'detail-fill': false }"></view>
- <view
- class="detail-line"
- v-if="i < visibleBillDetailList.length - 1 || hasMoreTimelineItems"
- ></view>
- </view>
- <view class="detail-right">
- <view class="detail-title-row">
- <view class="detail-title" :class="{ 'detail-bold': true }">
- {{ value.billTypeName || "--" }} {{ value.billCode || "" }}
- </view>
- <view class="detail-item-toggle" @tap.stop="toggleTimelineItem(i)">
- {{ value._showDetail ? "概要" : "详情" }}
- <uni-icons
- :type="value._showDetail ? 'up' : 'down'"
- size="14"
- color="#888"
- ></uni-icons>
- </view>
- </view>
- <view class="detail-info-row">
- <text class="detail-info-label">发货企业:</text>
- <text class="detail-info-value">{{
- value.fromEntName || "--"
- }}</text>
- </view>
- <view class="detail-tag-row">
- <text class="detail-tag" v-if="value.fromCustomerNature">{{
- value.fromCustomerNature
- }}</text>
- <text class="detail-tag" v-if="value.fromCustomerLevel">{{
- value.fromCustomerLevel
- }}</text>
- <text class="detail-tag" v-if="value.fromResponsibleManager">{{
- value.fromResponsibleManager
- }}</text>
- </view>
- <view class="detail-tag-row" v-if="value._showDetail">
- <text
- class="detail-tag"
- :style="getTagColorStyle(value.fromEntTypeName)"
- v-if="value.fromEntTypeName"
- >{{ value.fromEntTypeName }}</text
- >
- <text
- class="detail-tag detail-tag-region"
- v-if="getRegionByPrefix(value, 'from')"
- >{{ getRegionByPrefix(value, "from") }}</text
- >
- </view>
- <view class="detail-info-row">
- <text class="detail-info-label">收货企业:</text>
- <text class="detail-info-value">{{ value.toEntName || "--" }}</text>
- </view>
- <view class="detail-tag-row">
- <text class="detail-tag" v-if="value.toCustomerNature">{{
- value.toCustomerNature
- }}</text>
- <text class="detail-tag" v-if="value.toCustomerLevel">{{
- value.toCustomerLevel
- }}</text>
- <text class="detail-tag" v-if="value.toResponsibleManager">{{
- value.toResponsibleManager
- }}</text>
- </view>
- <view class="detail-tag-row" v-if="value._showDetail">
- <text
- class="detail-tag"
- :style="getTagColorStyle(value.toEntTypeName)"
- v-if="value.toEntTypeName"
- >{{ value.toEntTypeName }}</text
- >
- <text
- class="detail-tag detail-tag-region"
- v-if="getRegionByPrefix(value, 'to')"
- >{{ getRegionByPrefix(value, "to") }}</text
- >
- </view>
- <view class="detail-info-row">
- <text class="detail-info-label">入出库时间:</text>
- <text class="detail-info-value">{{ value.billTime || "--" }}</text>
- </view>
- <view
- class="detail-info-row"
- v-if="value._showDetail && value.uploadEntName"
- >
- <text class="detail-info-label">上传企业:</text>
- <text class="detail-info-value">{{ value.uploadEntName }}</text>
- </view>
- <view
- class="detail-tag-row"
- v-if="value._showDetail && value.uploadEntName"
- >
- <text class="detail-tag" v-if="value.uploadCustomerNature">{{
- value.uploadCustomerNature
- }}</text>
- <text class="detail-tag" v-if="value.uploadCustomerLevel">{{
- value.uploadCustomerLevel
- }}</text>
- <text class="detail-tag" v-if="value.uploadResponsibleManager">{{
- value.uploadResponsibleManager
- }}</text>
- </view>
- <view
- class="detail-tag-row"
- v-if="value._showDetail && value.uploadEntName"
- >
- <text
- class="detail-tag"
- :style="getTagColorStyle(value.uploadEntTypeName)"
- v-if="value.uploadEntTypeName"
- >{{ value.uploadEntTypeName }}</text
- >
- <text
- class="detail-tag detail-tag-region"
- v-if="getRegionByPrefix(value, 'upload')"
- >{{ getRegionByPrefix(value, "upload") }}</text
- >
- </view>
- <view
- class="detail-info-row"
- v-if="value._showDetail && value.uploadEntName"
- >
- <text class="detail-info-label">上传时间:</text>
- <text class="detail-info-value">{{
- value.uploadTime || "--"
- }}</text>
- </view>
- <view
- class="detail-info-row"
- v-if="value._showDetail && value.disEntName"
- >
- <text class="detail-info-label">配送企业:</text>
- <text class="detail-info-value">{{ value.disEntName }}</text>
- </view>
- <view
- class="detail-tag-row"
- v-if="
- value._showDetail &&
- value.disEntName &&
- !value.disEntName.includes(',')
- "
- >
- <text class="detail-tag" v-if="value.disCustomerNature">{{
- value.disCustomerNature
- }}</text>
- <text class="detail-tag" v-if="value.disCustomerLevel">{{
- value.disCustomerLevel
- }}</text>
- <text class="detail-tag" v-if="value.disResponsibleManager">{{
- value.disResponsibleManager
- }}</text>
- </view>
- <view
- class="detail-tag-row"
- v-if="
- value._showDetail &&
- value.disEntName &&
- !value.disEntName.includes(',')
- "
- >
- <text
- class="detail-tag"
- :style="getTagColorStyle(value.disEntTypeName)"
- v-if="value.disEntTypeName"
- >{{ value.disEntTypeName }}</text
- >
- <text
- class="detail-tag detail-tag-region"
- v-if="getRegionByPrefix(value, 'dis')"
- >{{ getRegionByPrefix(value, "dis") }}</text
- >
- </view>
- <view
- class="detail-info-row"
- v-if="value._showDetail && value.assEntName"
- >
- <text class="detail-info-label">委托企业:</text>
- <text class="detail-info-value">{{ value.assEntName }}</text>
- </view>
- <view
- class="detail-tag-row"
- v-if="value._showDetail && value.assEntName"
- >
- <text class="detail-tag" v-if="value.assCustomerNature">{{
- value.assCustomerNature
- }}</text>
- <text class="detail-tag" v-if="value.assCustomerLevel">{{
- value.assCustomerLevel
- }}</text>
- <text class="detail-tag" v-if="value.assResponsibleManager">{{
- value.assResponsibleManager
- }}</text>
- </view>
- <view
- class="detail-tag-row"
- v-if="value._showDetail && value.assEntName"
- >
- <text
- class="detail-tag"
- :style="getTagColorStyle(value.assEntTypeName)"
- v-if="value.assEntTypeName"
- >{{ value.assEntTypeName }}</text
- >
- <text
- class="detail-tag detail-tag-region"
- v-if="getRegionByPrefix(value, 'ass')"
- >{{ getRegionByPrefix(value, "ass") }}</text
- >
- </view>
- </view>
- </view>
- <view
- v-if="timelineView === 'text' && hasMoreTimelineItems"
- class="detail-timeline-loadmore"
- >
- 上拉加载更多({{ visibleBillDetailList.length }}/{{
- timelineTotalCount
- }})
- </view>
- </view>
- </scroll-view>
- <transition name="back-top-fade">
- <view
- v-if="!!data && !loading && showBackTopButton"
- class="detail-back-top-btn"
- @tap="backToTop"
- >
- <view class="detail-back-top-arrow"></view>
- </view>
- </transition>
- <view
- class="detail-page-empty"
- :style="{ height: pageHeight }"
- v-if="!data && !loading"
- >
- <image
- src="../../../static/images/empty.png"
- mode="scaleToFill"
- :style="{ width: '264rpx', height: '200rpx' }"
- />
- <text
- :style="{
- fontSize: '24rpx',
- color: '#99a1ad',
- marginTop: '60rpx',
- textAlign: 'center',
- }"
- >所查询药品所在生产企业尚未纳入扫码范围,后续将进一步扩大,敬请期待</text
- >
- </view>
- <view
- class="detail-page-empty"
- :style="{ height: pageHeight }"
- v-if="loading"
- >
- <image
- src="../../../static/images/loading.png"
- mode="scaleToFill"
- :style="{ width: '50rpx', height: '50rpx' }"
- class="detail-loading"
- />
- </view>
- </template>
- <script>
- import bg from "../../../static/images/bg.png";
- import { formatDate } from "../../../utils/utils.js";
- import request from "../../../request/index.js";
- import Water from "@/components/water/water.vue";
- // import lEchart from "../../../uni_modules/lime-echart/components/l-echart/l-echart.vue";
- // const echarts = require("../../../static/js/echarts.min.js");
- export default {
- components: {
- Water,
- // lEchart,
- },
- data() {
- return {
- data: null,
- loading: true,
- statusBarHeight: 20,
- traceCode: "",
- pageHeight: 0,
- bg,
- companyExpanded: true,
- needCompanyToggle: false,
- cardExpanded: false,
- allTimelineDetail: true,
- timelineView: "text",
- defaultTimelineViewKey:
- "traceabilityCodeQuery.detail.timelineDefaultView",
- imageData: [],
- graphViewWidth: 300,
- graphViewHeight: 480,
- chartInstance: null,
- chartOption: {},
- ownershipFlowMode: false,
- timelinePageSize: 20,
- timelineVisibleCount: 20,
- scrollTopValue: 0,
- scrollIntoViewId: "",
- backTopThreshold: 0,
- showBackTopButton: false,
- backTopHideTimer: null,
- };
- },
- onLoad(options) {
- const info = uni.getSystemInfoSync();
- this.statusBarHeight = info.statusBarHeight || 20;
- this.pageHeight = (info.windowHeight && info.windowHeight + "px") || "100%";
- this.backTopThreshold = info.windowHeight || 667;
- this.graphViewWidth = Math.max((info.windowWidth || 375) - 36, 280);
- this.graphViewHeight = Math.max((info.windowHeight || 667) - 200, 420);
- if (options.traceCode) {
- this.traceCode = options.traceCode;
- }
- // const defaultView = uni.getStorageSync(this.defaultTimelineViewKey);
- // if (defaultView === "graph" || defaultView === "text") {
- // this.timelineView = defaultView;
- // }
- // this.getData(options.traceCode);
- this.getData2(options.traceCode);
- },
- onReady() {
- this.$nextTick(() => {
- const info = uni.getSystemInfoSync();
- const lineHeightPx = (info.windowWidth / 750) * 40;
- this.companyExpanded = true; // 展开测量高度
- uni
- .createSelectorQuery()
- .in(this)
- .select("#companyValue")
- .boundingClientRect((rect) => {
- if (!rect || !lineHeightPx) return;
- const lines = Math.round(rect.height / lineHeightPx);
- this.needCompanyToggle = lines > 2;
- this.companyExpanded = !this.needCompanyToggle;
- })
- .exec();
- });
- },
- onReachBottom() {
- if (this.timelineView !== "text") return;
- this.loadMoreTimelineItems();
- },
- // 页面卸载时销毁图表实例
- // beforeUnmount() {
- // if (this.backTopHideTimer) {
- // clearTimeout(this.backTopHideTimer);
- // this.backTopHideTimer = null;
- // }
- // if (this.$refs.chartRef) {
- // this.$refs.chartRef.dispose();
- // }
- // },
- computed: {
- isShowGraph() {
- return this.data.billDetailList.length < 30;
- },
- timelineTotalCount() {
- if (!this.data || !Array.isArray(this.data.billDetailList)) return 0;
- return this.data.billDetailList.length;
- },
- visibleBillDetailList() {
- if (!this.data || !Array.isArray(this.data.billDetailList)) return [];
- const maxCount = Math.min(
- this.timelineVisibleCount,
- this.timelineTotalCount,
- );
- return this.data.billDetailList.slice(0, maxCount);
- },
- hasMoreTimelineItems() {
- return this.visibleBillDetailList.length < this.timelineTotalCount;
- },
- },
- methods: {
- getTagColorStyle(tag) {
- let color = "#57bfe1";
- if (tag.includes("生产")) color = "#f5c269";
- if (tag.includes("零售")) color = "#91c76d";
- return {
- color,
- borderColor: color + "80",
- };
- },
- // 初始化图表
- // async initChart() {
- // if (
- // !this.$refs.chartRef ||
- // !this.isShowGraph ||
- // this.timelineView !== "graph"
- // )
- // return;
- // let option = {};
- // const data = [];
- // const links = [];
- // const selfCurveness = 0.5;
- // const curveness = 0.7;
- // const lineWidth = 2;
- // const length = this.imageData.length;
- // const x = 350;
- // const offset = 200;
- // let i = 0;
- // this.imageData.forEach((item, index) => {
- // const { name, to } = item;
- // const toLen = to.length;
- // const y = index * 250 + 100;
- // const color = name.includes("生产")
- // ? "#fde58f"
- // : name.includes("零售")
- // ? "#b5ea8e"
- // : name.includes("消费者")
- // ? "#e0d3fe"
- // : "#a3e6ff";
- // data.push({
- // name,
- // x,
- // y,
- // itemStyle: {
- // color,
- // },
- // });
- // to.forEach((toItem, toIndex) => {
- // const { name: toName, text: toText } = toItem;
- // if (name.includes(toName)) {
- // data.push({
- // name: toText,
- // x,
- // y: y - 200,
- // itemStyle: {
- // color: "rgba(0,0,0,0)",
- // },
- // label: {
- // show: true,
- // color: "#c6c6c6",
- // },
- // tooltip: {
- // show: false,
- // },
- // });
- // links.push(
- // {
- // source: name,
- // target: toText,
- // label: {
- // show: false,
- // },
- // lineStyle: {
- // color: "#c6c6c6",
- // width: lineWidth,
- // curveness: selfCurveness,
- // },
- // },
- // {
- // source: toText,
- // target: name,
- // label: {
- // show: false,
- // },
- // lineStyle: {
- // color: "#c6c6c6",
- // width: lineWidth,
- // curveness: selfCurveness,
- // },
- // },
- // );
- // } else {
- // const isOut = toText.includes("出库");
- // links.push({
- // source: name,
- // target: toName,
- // label: {
- // show: true,
- // formatter: (params) => {
- // const text = toText;
- // if (!text) return "";
- // return text.split(/\s+/).filter(Boolean).join("\n");
- // },
- // color: isOut ? "#80a6fd" : "#aaaaaa",
- // fontSize: 12,
- // rotate: 0,
- // width: 100,
- // overflow: "breakAll",
- // },
- // lineStyle: {
- // color: isOut ? "#80a6fd" : "#aaaaaa",
- // width: lineWidth,
- // curveness: isOut ? curveness : -curveness,
- // },
- // });
- // }
- // });
- // });
- // console.log("this.imageData", this.imageData);
- // console.log("data", data);
- // console.log("links", links);
- // option = {
- // tooltip: {},
- // animationDurationUpdate: 1500,
- // animationEasingUpdate: "quinticInOut",
- // series: [
- // {
- // type: "graph",
- // layout: "none",
- // symbolSize: 80,
- // roam: true,
- // label: {
- // show: true,
- // formatter: (params) => {
- // const text = String((params && params.name) || "");
- // if (!text) return "";
- // return text.split(/\s+/).filter(Boolean).join("\n");
- // },
- // },
- // edgeSymbol: ["circle", "arrow"],
- // edgeSymbolSize: [4, 10],
- // data,
- // links,
- // lineStyle: {
- // opacity: 0.9,
- // width: 2,
- // curveness: 0,
- // },
- // },
- // ],
- // };
- // try {
- // await this.$nextTick();
- // // if (this.chartInstance) {
- // // this.chartInstance.setOption(option, true);
- // // return;
- // // }
- // this.chartInstance = await this.$refs.chartRef.init(echarts);
- // this.chartInstance.setOption(option, true);
- // } catch (error) {
- // console.error("图表初始化失败:", error);
- // }
- // },
- // 更新图表数据
- updateChart(newOption) {
- if (this.chartInstance) {
- this.chartInstance.setOption(newOption);
- } else if (this.$refs.chartRef) {
- this.$refs.chartRef.setOption(newOption);
- }
- },
- // 调整图表大小
- resizeChart() {
- if (this.$refs.chartRef) {
- this.$refs.chartRef.resize();
- }
- },
- formatDate(date) {
- return formatDate({ date }, "YYYY-MM-DD");
- },
- getRegion(value = {}) {
- const { provinceDesc, cityDesc, areaDesc } = value;
- return (
- [provinceDesc, cityDesc, areaDesc].filter(Boolean).join(",") || ""
- );
- },
- getRegionByPrefix(value = {}, prefix = "from") {
- const province = value[`${prefix}ProvinceDesc`];
- const city = value[`${prefix}CityDesc`];
- const area = value[`${prefix}AreaDesc`];
- return [province, city, area].filter(Boolean).join("-") || "";
- },
- initTimelineVisibleCount() {
- this.timelineVisibleCount = this.timelinePageSize;
- },
- onPageScroll(e) {
- const top = Number((e && e.detail && e.detail.scrollTop) || 0);
- if (top < this.backTopThreshold) {
- this.showBackTopButton = false;
- if (this.backTopHideTimer) {
- clearTimeout(this.backTopHideTimer);
- this.backTopHideTimer = null;
- }
- return;
- }
- this.showBackTopButton = true;
- if (this.backTopHideTimer) {
- clearTimeout(this.backTopHideTimer);
- }
- this.backTopHideTimer = setTimeout(() => {
- this.showBackTopButton = false;
- this.backTopHideTimer = null;
- }, 3000);
- },
- backToTop() {
- this.scrollTopValue = 0;
- this.scrollIntoViewId = "detailPageTopAnchor";
- this.showBackTopButton = false;
- if (this.backTopHideTimer) {
- clearTimeout(this.backTopHideTimer);
- this.backTopHideTimer = null;
- }
- this.$nextTick(() => {
- this.scrollIntoViewId = "";
- });
- },
- onTimelineScrollToLower() {
- if (this.timelineView !== "text") return;
- this.loadMoreTimelineItems();
- },
- loadMoreTimelineItems() {
- if (!this.hasMoreTimelineItems) return;
- this.timelineVisibleCount = Math.min(
- this.timelineVisibleCount + this.timelinePageSize,
- this.timelineTotalCount,
- );
- },
- toggleTimelineItem(index) {
- if (!this.data || !Array.isArray(this.data.billDetailList)) return;
- const item = this.data.billDetailList[index];
- if (!item) return;
- this.$set(item, "_showDetail", !item._showDetail);
- },
- setAllTimelineDetail(showDetail) {
- this.allTimelineDetail = !!showDetail;
- if (!this.data || !Array.isArray(this.data.billDetailList)) return;
- this.data.billDetailList.forEach((item) => {
- if (item) this.$set(item, "_showDetail", !!showDetail);
- });
- },
- toggleTimelineView() {
- this.timelineView = this.timelineView === "text" ? "graph" : "text";
- if (this.timelineView === "text") {
- this.initTimelineVisibleCount();
- }
- if (
- this.timelineView === "graph" &&
- this.data &&
- Array.isArray(this.data.billDetailList)
- ) {
- this.imageData = this.ownershipFlowMode
- ? this.buildImageData2(this.data.billDetailList)
- : this.buildImageData(this.data.billDetailList);
- this.updateGraphCanvasSize();
- this.$nextTick(() => this.initChart());
- }
- },
- onOwnershipModeChange(e) {
- this.ownershipFlowMode = !!(e && e.detail && e.detail.value);
- if (!this.data || !Array.isArray(this.data.billDetailList)) return;
- this.imageData = this.ownershipFlowMode
- ? this.buildImageData2(this.data.billDetailList)
- : this.buildImageData(this.data.billDetailList);
- this.updateGraphCanvasSize();
- if (this.timelineView === "graph") {
- this.$nextTick(() => this.initChart());
- }
- },
- onSetDefaultView() {
- uni.setStorageSync(this.defaultTimelineViewKey, this.timelineView);
- uni.showToast({
- title: "已设为默认",
- icon: "none",
- });
- },
- buildImageData2(data) {
- if (!data || !Array.isArray(data)) return [];
- const list = [];
- const buildTime = (time) => {
- return time.split(" ")[0];
- };
- const buildTo = (to, item) => {
- const hasAss = !!item.assEntName;
- const hasType = item.billTypeName && item.billTypeName !== "****";
- if (item.billTypeName === "使用出库") {
- to.push({
- name: "消费者",
- text: !hasType
- ? "****"
- : buildTime(item.billTime) + " " + item.billTypeName,
- });
- } else if (item.toEntName) {
- const address = [
- item.toProvinceDesc,
- item.toCityDesc,
- item.toAreaDesc,
- ]
- .filter(Boolean)
- .join(",");
- to.push({
- name: item.toEntTypeName + " " + item.toEntName + " " + address,
- text: !hasType
- ? "****"
- : buildTime(item.billTime) + " " + item.billTypeName,
- });
- if (hasAss && hasType) {
- to[to.length - 1].text += " 被委托:" + item.fromEntName;
- }
- }
- return to;
- };
- data.forEach((item, i) => {
- const hasAss = !!item.assEntName;
- const index = list.findIndex((i) =>
- i.name.includes(hasAss ? item.assEntName : item.fromEntName),
- );
- let to = [];
- if (index !== -1) {
- to = list[index].to;
- }
- to = buildTo(to, item);
- if (index === -1) {
- const address = (
- hasAss
- ? [item.assProvinceDesc, item.assCityDesc, item.assAreaDesc]
- : [item.fromProvinceDesc, item.fromCityDesc, item.fromAreaDesc]
- )
- .filter(Boolean)
- .join(",");
- const name = hasAss
- ? item.assEntTypeName + " " + item.assEntName + " " + address
- : item.fromEntTypeName + " " + item.fromEntName + " " + address;
- list.push({
- num: i,
- name,
- to,
- });
- } else {
- list[index].to = to;
- }
- if (
- item.toEntName &&
- list.findIndex((i) => i.name.includes(item.toEntName)) === -1
- ) {
- const address = [
- item.toProvinceDesc,
- item.toCityDesc,
- item.toAreaDesc,
- ]
- .filter(Boolean)
- .join(",");
- list.push({
- num: i + 9999,
- name: item.toEntTypeName + " " + item.toEntName + " " + address,
- to: [],
- });
- }
- });
- const lastItem = list[list.length - 1];
- if (lastItem?.to?.[0]?.name === "消费者") {
- list.push({
- num: 99999,
- name: "消费者",
- to: [],
- });
- }
- list.sort((a, b) => a.num - b.num);
- return list;
- },
- buildImageData(data) {
- if (!data || !Array.isArray(data)) return [];
- const list = [];
- const buildTime = (time) => {
- return time.split(" ")[0];
- };
- const buildTo = (to, item) => {
- const hasType = item.billTypeName && item.billTypeName !== "****";
- if (item.billTypeName === "使用出库") {
- to.push({
- name: "消费者",
- text: !hasType
- ? "****"
- : buildTime(item.billTime) + " " + item.billTypeName,
- });
- } else if (item.toEntName) {
- const address = [
- item.toProvinceDesc,
- item.toCityDesc,
- item.toAreaDesc,
- ]
- .filter(Boolean)
- .join(",");
- to.push({
- name: item.toEntTypeName + " " + item.toEntName + " " + address,
- text: !hasType
- ? "****"
- : buildTime(item.billTime) + " " + item.billTypeName,
- });
- if (item.assEntName && hasType) {
- to[to.length - 1].text += " 委托:" + item.assEntName;
- }
- }
- return to;
- };
- data.forEach((item, i) => {
- const index = list.findIndex((i) => i.name.includes(item.fromEntName));
- let to = [];
- if (index !== -1) {
- to = list[index].to;
- }
- to = buildTo(to, item);
- if (index === -1) {
- const address = [
- item.fromProvinceDesc,
- item.fromCityDesc,
- item.fromAreaDesc,
- ]
- .filter(Boolean)
- .join(",");
- list.push({
- num: i,
- name: item.fromEntTypeName + " " + item.fromEntName + " " + address,
- to,
- });
- } else {
- list[index].to = to;
- }
- if (
- item.toEntName &&
- list.findIndex((i) => i.name.includes(item.toEntName)) === -1
- ) {
- const address = [
- item.toProvinceDesc,
- item.toCityDesc,
- item.toAreaDesc,
- ]
- .filter(Boolean)
- .join(",");
- list.push({
- num: i + 9999,
- name: item.toEntTypeName + " " + item.toEntName + " " + address,
- to: [],
- });
- }
- });
- const lastItem = list[list.length - 1];
- if (lastItem?.to?.[0]?.name === "消费者") {
- list.push({
- num: 99999,
- name: "消费者",
- to: [],
- });
- }
- list.sort((a, b) => a.num - b.num);
- return list;
- },
- updateGraphCanvasSize() {
- if (!this.isShowGraph) {
- this.graphViewHeight = 50;
- return;
- }
- const list = this.imageData || [];
- const top = 90;
- const bottom = 90;
- const vGap = 170;
- const nodeCount = list.length || 1;
- this.graphViewHeight = Math.max(
- 520,
- top + bottom + (nodeCount - 1) * vGap,
- );
- },
- getData2(traceCode) {
- request("/bills/scanCode2", {
- tracCode: traceCode,
- path: "/traceabilityCodeQuery/pages/detail/index.vue",
- }).then((res) => {
- if (res.code == 200) {
- const _data = res.data;
- this.data = _data || null;
- if (this.data && Array.isArray(this.data.billDetailList)) {
- this.data.billDetailList = this.data.billDetailList.map((item) => ({
- ...item,
- _showDetail: !!this.allTimelineDetail,
- }));
- // this.initTimelineVisibleCount();
- // if (this.isShowGraph) {
- // this.imageData = this.ownershipFlowMode
- // ? this.buildImageData2(this.data.billDetailList)
- // : this.buildImageData(this.data.billDetailList);
- // }
- // this.updateGraphCanvasSize();
- // this.initChart();
- }
- if (
- typeof _data === "object" &&
- Object.values(_data).filter((i) => !!i).length == 0
- ) {
- this.data = null;
- }
- this.loading = false;
- } else {
- uni.showToast({ title: "查询失败", icon: "none" });
- }
- });
- },
- getData(traceCode) {
- request("/bills/scanCode", {
- tracCode: traceCode,
- path: "/traceabilityCodeQuery/pages/detail/index.vue",
- }).then((res) => {
- if (res.code == 200) {
- // const _data = res.data;
- // this.data = _data || null;
- // const defaultData = [
- // {
- // billTypeName: "生产入库",
- // billCode: "SYS_IN_2025041410194699357",
- // fromEntId: "00000000000000959808",
- // fromEntName: "惠州市九惠制药股份有限公司",
- // fromEntType: "1",
- // fromEntTypeName: "生产企业",
- // fromProvinceDesc: "广东省",
- // fromCityDesc: "惠州市",
- // fromAreaDesc: "惠城区",
- // toEntId: "00000000000000959808",
- // toEntName: "惠州市九惠制药股份有限公司",
- // toEntType: "1",
- // toEntTypeName: "生产企业",
- // toProvinceDesc: "广东省",
- // toCityDesc: "惠州市",
- // toAreaDesc: "惠城区",
- // billTime: "2025-04-12 00:00:00",
- // uploadEntId: "00000000000000959808",
- // uploadEntName: "惠州市九惠制药股份有限公司",
- // uploadEntType: "1",
- // uploadEntTypeName: "生产企业",
- // uploadProvinceDesc: "广东省",
- // uploadCityDesc: "惠州市",
- // uploadAreaDesc: "惠城区",
- // uploadTime: "2025-04-14 10:19:47",
- // },
- // {
- // billTypeName: "销售出库",
- // billCode: "20250414093811017995",
- // fromEntId: "00000000000000959808",
- // fromEntName: "惠州市九惠制药股份有限公司",
- // fromEntType: "1",
- // fromEntTypeName: "生产企业",
- // fromProvinceDesc: "广东省",
- // fromCityDesc: "惠州市",
- // fromAreaDesc: "惠城区",
- // toEntId: "00000000000012618117",
- // toEntName: "深圳华润三九医药贸易有限公司",
- // toEntType: "2",
- // toEntTypeName: "批发企业",
- // toProvinceDesc: "广东省",
- // toCityDesc: "深圳市",
- // toAreaDesc: "龙华区",
- // billTime: "2025-04-14 09:38:11",
- // uploadEntId: "00000000000000592642",
- // uploadEntName: "华润三九医药股份有限公司",
- // uploadEntType: "1",
- // uploadEntTypeName: "生产企业",
- // uploadProvinceDesc: "广东省",
- // uploadCityDesc: "深圳市",
- // uploadAreaDesc: "龙华区",
- // uploadTime: "2025-10-31 17:29:36",
- // },
- // {
- // billTypeName: "销售出库",
- // billCode: "2504032G-2",
- // fromEntId: "00000000000012618117",
- // fromEntName: "深圳华润三九医药贸易有限公司",
- // fromEntType: "2",
- // fromEntTypeName: "批发企业",
- // fromProvinceDesc: "广东省",
- // fromCityDesc: "深圳市",
- // fromAreaDesc: "龙华区",
- // toEntId: "8b63aa19a9a94cb6aa472ee69d309bb5",
- // toEntName: "国药控股福建有限公司",
- // toEntType: "5",
- // toEntTypeName: "物流企业",
- // toProvinceDesc: "福建省",
- // toCityDesc: "厦门市",
- // toAreaDesc: "思明区",
- // billTime: "2025-09-27 00:00:00",
- // uploadEntId: "00000000000012618117",
- // uploadEntName: "深圳华润三九医药贸易有限公司",
- // uploadEntType: "2",
- // uploadEntTypeName: "批发企业",
- // uploadProvinceDesc: "广东省",
- // uploadCityDesc: "深圳市",
- // uploadAreaDesc: "龙华区",
- // uploadTime: "2025-09-28 10:04:12",
- // },
- // {
- // billTypeName: "采购入库",
- // billCode: "2504032G-1",
- // fromEntId: "00000000000000592642",
- // fromEntName: "华润三九医药股份有限公司",
- // fromEntType: "1",
- // fromEntTypeName: "生产企业",
- // fromProvinceDesc: "广东省",
- // fromCityDesc: "深圳市",
- // fromAreaDesc: "龙华区",
- // toEntId: "00000000000012618117",
- // toEntName: "深圳华润三九医药贸易有限公司",
- // toEntType: "2",
- // toEntTypeName: "批发企业",
- // toProvinceDesc: "广东省",
- // toCityDesc: "深圳市",
- // toAreaDesc: "龙华区",
- // billTime: "2025-09-27 00:00:00",
- // uploadEntId: "00000000000000592642",
- // uploadEntName: "华润三九医药股份有限公司",
- // uploadEntType: "1",
- // uploadEntTypeName: "生产企业",
- // uploadProvinceDesc: "广东省",
- // uploadCityDesc: "深圳市",
- // uploadAreaDesc: "龙华区",
- // uploadTime: "2025-09-28 10:04:06",
- // },
- // {
- // billTypeName: "采购入库",
- // billCode: "FJASNP2509280580393",
- // fromEntId: "00000000000012618117",
- // fromEntName: "深圳华润三九医药贸易有限公司",
- // fromEntType: "2",
- // fromEntTypeName: "批发企业",
- // fromProvinceDesc: "广东省",
- // fromCityDesc: "深圳市",
- // fromAreaDesc: "龙华区",
- // toEntId: "8b63aa19a9a94cb6aa472ee69d309bb5",
- // toEntName: "国药控股福建有限公司",
- // toEntType: "5",
- // toEntTypeName: "物流企业",
- // toProvinceDesc: "福建省",
- // toCityDesc: "厦门市",
- // toAreaDesc: "思明区",
- // billTime: "2025-10-30 00:00:00",
- // uploadEntId: "00000000000012618117",
- // uploadEntName: "深圳华润三九医药贸易有限公司",
- // uploadEntType: "2",
- // uploadEntTypeName: "批发企业",
- // uploadProvinceDesc: "广东省",
- // uploadCityDesc: "深圳市",
- // uploadAreaDesc: "龙华区",
- // uploadTime: "2025-10-30 17:05:35",
- // },
- // {
- // billTypeName: "销售出库",
- // billCode: "FJS0CFFPHL",
- // fromEntId: "8b63aa19a9a94cb6aa472ee69d309bb5",
- // fromEntName: "国药控股福建有限公司",
- // fromEntType: "5",
- // fromEntTypeName: "物流企业",
- // fromProvinceDesc: "福建省",
- // fromCityDesc: "厦门市",
- // fromAreaDesc: "思明区",
- // toEntId: "00000000000001312166",
- // toEntName: "国药控股厦门有限公司",
- // toEntType: "2",
- // toEntTypeName: "批发企业",
- // toProvinceDesc: "福建省",
- // toCityDesc: "厦门市",
- // toAreaDesc: "同安区",
- // billTime: "2025-10-31 00:00:00",
- // uploadEntId: "8b63aa19a9a94cb6aa472ee69d309bb5",
- // uploadEntName: "国药控股福建有限公司",
- // uploadEntType: "5",
- // uploadEntTypeName: "物流企业",
- // uploadProvinceDesc: "福建省",
- // uploadCityDesc: "厦门市",
- // uploadAreaDesc: "思明区",
- // uploadTime: "2025-11-01 00:03:29",
- // },
- // {
- // billTypeName: "采购入库",
- // billCode: "XMASNP2510310469890",
- // fromEntId: "8b63aa19a9a94cb6aa472ee69d309bb5",
- // fromEntName: "国药控股福建有限公司",
- // fromEntType: "5",
- // fromEntTypeName: "物流企业",
- // fromProvinceDesc: "福建省",
- // fromCityDesc: "厦门市",
- // fromAreaDesc: "思明区",
- // toEntId: "00000000000001312166",
- // toEntName: "国药控股厦门有限公司",
- // toEntType: "2",
- // toEntTypeName: "批发企业",
- // toProvinceDesc: "福建省",
- // toCityDesc: "厦门市",
- // toAreaDesc: "同安区",
- // billTime: "2025-11-03 00:00:00",
- // uploadEntId: "8b63aa19a9a94cb6aa472ee69d309bb5",
- // uploadEntName: "国药控股福建有限公司",
- // uploadEntType: "5",
- // uploadEntTypeName: "物流企业",
- // uploadProvinceDesc: "福建省",
- // uploadCityDesc: "厦门市",
- // uploadAreaDesc: "思明区",
- // uploadTime: "2025-11-03 17:14:48",
- // },
- // ];
- // this.imageData = this.buildImageData(defaultData);
- // this.updateGraphCanvasSize();
- // this.initChart();
- // if (
- // typeof _data === "object" &&
- // Object.values(_data).filter((i) => !!i).length == 0
- // ) {
- // this.data = null;
- // }
- // this.loading = false;
- // } else {
- // uni.showToast({ title: "查询失败", icon: "none" });
- // }
- }
- });
- },
- copy(text) {
- const data = String(text || this.traceCode);
- uni.setClipboardData({
- data,
- success: () => {
- console.log(
- "packages/traceabilityCodeQuery/pages/detail/index.vue" +
- "storage" +
- "clipboardData",
- );
- uni.showToast({
- title: "已复制追溯码",
- icon: "none",
- duration: 2000,
- });
- },
- });
- },
- toggleCompanyExpand() {
- if (!this.needCompanyToggle) return;
- this.companyExpanded = !this.companyExpanded;
- },
- toggleCardExpand() {
- this.cardExpanded = !this.cardExpanded;
- },
- formatTraceCode(traceCode) {
- return String(traceCode || "")
- .replace(/(.{5})/g, "$1 ")
- .trim();
- },
- },
- };
- </script>
- <style>
- .detail-bg {
- background-position: center top;
- background-size: 100% auto;
- }
- .detail-page {
- box-sizing: border-box;
- background: rgb(226 226 226);
- padding-bottom: 50rpx;
- overflow: auto;
- }
- .detail-page-empty {
- box-sizing: border-box;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 0 136rpx 280rpx;
- }
- .detail-back-top-btn {
- position: fixed;
- right: 28rpx;
- bottom: 110rpx;
- width: 84rpx;
- height: 84rpx;
- border-radius: 50%;
- background: #fff;
- display: flex;
- align-items: center;
- justify-content: center;
- box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.18);
- z-index: 999;
- }
- .back-top-fade-enter-active,
- .back-top-fade-leave-active {
- transition:
- opacity 0.28s ease,
- transform 0.28s ease;
- }
- .back-top-fade-enter-from,
- .back-top-fade-leave-to {
- opacity: 0;
- transform: translateY(16rpx) scale(0.92);
- }
- .detail-back-top-arrow {
- width: 20rpx;
- height: 20rpx;
- border-top: 4rpx solid #5f6773;
- border-left: 4rpx solid #5f6773;
- transform: rotate(45deg);
- margin-top: 8rpx;
- }
- .detail-card {
- padding: 40rpx;
- }
- .detail-drug-title {
- font-size: 45rpx;
- font-weight: 800;
- color: #000;
- margin-bottom: 16rpx;
- }
- .detail-row {
- position: relative;
- display: flex;
- margin-top: 12rpx;
- align-items: baseline;
- }
- .detail-label {
- flex-shrink: 0;
- display: inline-block;
- vertical-align: baseline;
- width: 150rpx;
- font-size: 28rpx;
- }
- .detail-value {
- display: inline-block;
- vertical-align: baseline;
- font-size: 28rpx;
- }
- .detail-company-value {
- line-height: 40rpx;
- }
- .detail-company-value.detail-clamp {
- display: -webkit-box;
- -webkit-box-orient: vertical;
- -webkit-line-clamp: 2;
- overflow: hidden;
- }
- .detail-expand-tag {
- position: absolute;
- left: 150rpx;
- bottom: 0;
- color: #2c69ff;
- font-size: 28rpx;
- }
- .detail-value.detail-wrap {
- word-break: break-all;
- white-space: normal;
- }
- .detail-copy-btn {
- margin-left: 16rpx;
- display: flex;
- align-items: center;
- color: #2c69ff;
- }
- .detail-copy-text {
- margin-left: 6rpx;
- font-size: 26rpx;
- }
- .detail-traceability {
- font-size: 24rpx;
- margin: -10rpx 0 45rpx;
- }
- .detail-card-toggle {
- display: flex;
- justify-content: center;
- align-items: center;
- padding-top: 18rpx;
- }
- .detail-traceability .detail-label {
- width: auto;
- }
- .detail-section-header {
- padding: 30rpx 24rpx 20rpx 46rpx;
- border-bottom: 1rpx solid #55555526;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .detail-section-title {
- font-size: 35rpx;
- font-weight: 900;
- }
- .detail-section-actions {
- display: flex;
- align-items: center;
- gap: 12rpx;
- }
- .detail-section-action {
- font-size: 26rpx;
- color: #59a8f2;
- padding: 4rpx 6rpx;
- display: flex;
- align-items: center;
- gap: 6rpx;
- }
- .detail-section-action.active {
- color: #2c69ff;
- font-weight: 600;
- }
- .detail-timeline {
- margin-top: 20rpx;
- padding-bottom: 50rpx;
- }
- .detail-graph-placeholder {
- margin: 16rpx 20rpx 0;
- background: #fff;
- border-radius: 14rpx;
- font-size: 24rpx;
- text-align: center;
- color: #97a0ae;
- padding: 120rpx 20rpx;
- }
- .detail-graph-panel {
- margin: 16rpx 20rpx 0;
- background: #fff;
- border-radius: 14rpx;
- padding: 16rpx;
- }
- .graph-mode-row {
- display: flex;
- align-items: flex-start;
- justify-content: space-between;
- gap: 18rpx;
- margin-bottom: 18rpx;
- padding: 4rpx 6rpx 0;
- }
- .graph-mode-left {
- flex: 1;
- }
- .graph-mode-title {
- font-size: 30rpx;
- color: #333;
- font-weight: 600;
- }
- .graph-mode-desc {
- margin-top: 8rpx;
- font-size: 24rpx;
- color: #8d96a0;
- line-height: 1.45;
- }
- .detail-graph-canvas {
- width: 100%;
- height: 920rpx;
- background: #f8fafc;
- border-radius: 10rpx;
- }
- .detail-timeline-toolbar {
- display: flex;
- gap: 16rpx;
- padding: 20rpx 32rpx 10rpx;
- }
- .detail-toolbar-btn {
- padding: 8rpx 18rpx;
- border: 1rpx solid #d8dbe0;
- border-radius: 999rpx;
- color: #666;
- font-size: 24rpx;
- background: #fff;
- }
- .detail-timeline-item {
- position: relative;
- display: flex;
- margin-left: 36rpx;
- }
- .detail-timeline-item-first {
- margin-top: 20rpx;
- }
- .detail-timeline-loadmore {
- text-align: center;
- color: #8f98a3;
- font-size: 24rpx;
- padding: 18rpx 0 8rpx;
- }
- .detail-left {
- position: absolute;
- top: 34rpx;
- left: 0;
- height: 100%;
- display: flex;
- align-items: center;
- flex-direction: column;
- }
- .detail-dot {
- width: 16rpx;
- height: 16rpx;
- border-radius: 50%;
- border: 2rpx solid #2c69ff;
- }
- .detail-dot.detail-fill {
- background: #2c69ff;
- border-color: #2c69ff;
- }
- .detail-line {
- width: 2rpx;
- flex: 1;
- background: #8face68f;
- margin-right: 2rpx;
- }
- .detail-right {
- flex: 1;
- padding: 20rpx 0;
- margin-left: 45rpx;
- border-bottom: 1rpx solid #55555526;
- }
- .detail-title-row {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- gap: 16rpx;
- }
- .detail-title {
- font-size: 32rpx;
- color: #333;
- }
- .detail-title.detail-bold {
- font-weight: 800;
- }
- .detail-item-toggle {
- flex-shrink: 0;
- padding: 6rpx 12rpx;
- border: 1rpx solid #d8dbe0;
- border-radius: 999rpx;
- font-size: 22rpx;
- color: #666;
- display: flex;
- align-items: center;
- gap: 6rpx;
- margin-right: 16rpx;
- }
- .detail-info-row {
- display: flex;
- margin-top: 10rpx;
- font-size: 28rpx;
- color: #444;
- }
- .detail-info-label {
- color: #666;
- flex-shrink: 0;
- }
- .detail-info-value {
- color: #333;
- word-break: break-all;
- }
- .detail-tag-row {
- display: flex;
- flex-wrap: wrap;
- gap: 10rpx;
- margin-top: 8rpx;
- padding-left: 130rpx;
- }
- .detail-tag {
- color: #57bfe1;
- border-radius: 8rpx;
- padding: 5rpx 14rpx;
- font-size: 22rpx;
- border: 1rpx solid #57bfe180;
- }
- .detail-tag-region {
- color: #999;
- border: 1rpx solid #d8dbe0;
- }
- .detail-text-red {
- color: red;
- }
- .detail-loading {
- animation: spin 1s linear infinite;
- }
- @keyframes spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
- }
- </style>
|