藥品追溯碼(溯源碼)采集系統(二):門診發藥后端

????????門診發退藥追溯碼采集系統解析:

一、門診發退藥追溯碼數據表

1.1、Wm_ware_dispense_bill表:該表用于存儲處方信息

1.2 Wm_ware_dispense_tracecode:追溯碼采集表

二、發退藥后端代碼

? ? ? ? 后端代碼基于Springboot架構和mybatis-plus,先看主要接口信息:

1.1、該接口用于接收處方號、部門id和操作人三個參數,回參是處方單的藥品信息

/*** 接口名稱: WareDispenseBillController$* 功能描述:用于存儲處方單信息,以及查詢信息并輸出到頁面*/@RestController
@RequestMapping("/wareDispenseBill")
public class WareDispenseBillController {@Resourceprivate WmWareDispenseBillService wmWareDispenseBillService;@GetMapping("/split/{Rxno}/{departmentid}/{username}")@Transactional(rollbackFor = Exception.class)public R getWareBaseInfo_tz_v_split(@PathVariable String Rxno,@PathVariable String departmentid,@PathVariable String username) {try {AtomicInteger statusCode = new AtomicInteger(0);List<WareInfoSplit> wareInfo_t = wmWareDispenseBillService.querySplit(Rxno, departmentid, username, statusCode);// 已上傳醫保或查詢失敗時,返回空數組而非錯誤消息if (wareInfo_t == null) {return R.OK(new ArrayList<>());}return R.OK(wareInfo_t);} catch (Exception e) {return R.FAIL("系統錯誤");}}
}

其中回參WareInfoSplit,用于傳遞給前端渲染,供發藥醫師確定發藥情況:

  1. splitFlag代表拆零標志,如果 splitFlag=00 說明該藥品是非拆零藥品,非拆零藥品需要門診挨個掃碼,而拆零藥品需要藥庫提前掃碼,儲備子碼庫方表調用
  2. billid是處方表的主鍵
  3. wareid是商品id
  4. patientName是患者名
  5. spec是規格
  6. quantity是發藥數量
  7. manufacturer是生成廠家
  8. tracecodePrefix是藥品追溯碼前七位,也被稱為標識碼
  9. scanFlag是用于院內制劑,沒有追溯碼的藥品的標識
  10. enoughFlag是當藥品為拆零藥品,且儲備的剩余子碼不足發藥數量時,用于前端提示
  11. splitTracecode是待拆追溯碼
  12. subcodeids是存儲拆零子碼的codeid
@Data
@AllArgsConstructor
public class WareInfoSplit {private String splitFlag;private Long billid;private Integer wareid;private String patientName;private String wareName;private String spec;private Integer quantity;private String manufacturer;private String tracecodePrefix; //藥品標識碼,前七位private String scanFlag;  //是否需要掃碼private String enoughFlag; //庫存追溯碼數量,是否能覆蓋發藥需求,00是能覆蓋,10是不能覆蓋private String splitTracecode;  //待拆追溯碼private List<Integer> subcodeids; //存儲拆零子碼的codeid

1.2 上面的querySplit方法如下:

1.2.1 該方法首先需要對接his接口,該接口通過處方號來獲取藥品基本信息。

 @Transactional@Overridepublic List<WareInfoSplit> querySplit(String RecipeNo, String departmentid, String username, AtomicInteger statusCode) {// 1. 調用外部API獲取處方數據final String API_URL = "http://ip:post/QueryRxno";//創建一個 JSON 格式的字符串//這里用到了轉義字符,把雙引號轉義為普通的字符String requestJson = String.format("{\"RecipeNo\":\"%s\"}", RecipeNo);try {// 發送API請求RestTemplate restTemplate = new RestTemplate();HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);//HttpEntity封裝請求體和請求頭。HttpEntity<String> requestEntity = new HttpEntity<>(requestJson, headers);//返回的ResponseEntity<String>包含響應狀態碼和響應體ResponseEntity<String> response = restTemplate.exchange(API_URL, HttpMethod.POST, requestEntity, String.class);if (response.getStatusCode() != HttpStatus.OK) {statusCode.set(1);   //此時就是沒能成功調用接口return null;}//將 HTTP 響應中的 JSON 字符串轉換為 Java 的Map<String, Object>對象ObjectMapper objectMapper = new ObjectMapper();Map<String, Object> resultMap = objectMapper.readValue(response.getBody(), new TypeReference<Map<String, Object>>() {});if (!"1".equals(resultMap.get("ReturnCode"))) { //ReturnCode如果不等于1就一定不正常statusCode.set(2);return null;}//ReturnCode等于1,也有可能回傳空的列表List<Map<String, Object>> details = (List<Map<String, Object>>) resultMap.get("Details");if (details == null || details.isEmpty()) {statusCode.set(3);return null;  //未查詢到處方}

醫院his接口部分回參如下:

1.2.2? 第二段的代碼邏輯:

1)醫院只會傳藥品編碼,我需要通過維護的藥品基礎表來查詢對應的藥品基礎信息記錄,其中比較重要的是

tracecode_prefix:藥品標識碼

split_flag:拆零標志

split_ratio:拆零系數,若藥品為拆零藥品,假設追溯碼貼在藥盒上,一盒有10支,則拆零系數為10

2)源碼:

????????有些處方號可能之前已經掃過,這里存在兩種情況:一是醫生開具處方之后,患者沒有及時過來拿,而醫院沒有報道機的情況下,就會在打印處方單的同時掃碼;二是發藥醫師掃過處方單之后,又誤掃處方單,此時在處方表內就會有歷史記錄,需要找到記錄掃處方的記錄

// 2. 性能優化 - 批量收集藥品編碼并查詢Set<String> drugCodes = new HashSet<>();  //發藥的藥品編碼List<String> rxNos = new ArrayList<>();   //發藥的處方號List<String> rxSerialNos = new ArrayList<>();  //發藥的處方明細號for (Map<String, Object> item : details) {drugCodes.add(item.get("ware_code").toString());rxNos.add(item.get("rxno").toString());rxSerialNos.add(item.get("rx_serialno").toString());}// 批量查詢藥品基礎信息// 通過藥品編碼查詢藥品信息,并轉換為Map<ware_code, PubWareBase>的結構。Map<String, PubWareBase> wareBaseMap = drugCodes.isEmpty() ? new HashMap<>() :pubWareBaseMapper.selectList(new LambdaQueryWrapper<PubWareBase>().in(PubWareBase::getWareCode, drugCodes)).stream().collect(Collectors.toMap(PubWareBase::getWareCode,Function.identity(),(existing, replacement) -> existing));List<WmWareDispenseBill> billsToSave = new ArrayList<>();   //準備插入到WmWareDispenseBill表中的記錄List<WareInfoSplit> wareInfoList = new ArrayList<>();   //準備回傳的接口數據// 3. 批量查詢已存在的處方記錄// map對象的鍵是rxno|rxSerialno的組合字符串,值為對應的處方對象。Map<String, WmWareDispenseBill> existingBillsMap = new HashMap<>();  //記錄哪寫處方以前創建過if (!rxNos.isEmpty()) {  //根據處方號和處方明細號,查詢已有的處方記錄List<WmWareDispenseBill> existingBills = this.list(new LambdaQueryWrapper<WmWareDispenseBill>().in(WmWareDispenseBill::getRxno, rxNos).in(WmWareDispenseBill::getRxSerialno, rxSerialNos));existingBills.forEach(bill ->existingBillsMap.put(bill.getRxno() + "|" + bill.getRxSerialno(), bill));}

????????

1.2.3 對有掃碼記錄的處方單,我們區分了以下的幾種情況。

? ? ? ? (1)如果此處方號是第一次掃描,則在下表內新增處方信息

? ? ? ? (2)如果此處方之前掃過,但是并沒有掃描對應的追溯碼,則處方表內有記錄,且status為00,此時記錄billid,返回該記錄,并在高拍儀屏幕顯示

? ? ? ? (3)如果 此處方之前掃過,且已經掃過追溯碼并提交,則默認為該患者開方當天并未取藥,此時應重新掃描追溯碼并作廢之前已掃追溯碼

? ? ? ? (4)如果此處方之前掃過,且掃過追溯碼,且已提交醫保,則不返回任何回參。

for (Map<String, Object> item : details) {WareInfoSplit wareInfo = new WareInfoSplit(); //需上傳數據String rxno = item.get("rxno").toString();String rxSerialno = item.get("rx_serialno").toString();String key = rxno + "|" + rxSerialno;String drugCode = item.get("ware_code").toString();PubWareBase pubWareBase = wareBaseMap.get(drugCode);// 跳過無藥品信息的記錄if (pubWareBase == null) {continue;}// 這個處方記錄以前創建過if (existingBillsMap.containsKey(key)) {//獲取其對應的處方記錄對象WmWareDispenseBill existingBill = existingBillsMap.get(key);// 情況1: status = '00',這個已創建的記錄仍是待掃碼,if ("00".equals(existingBill.getStatus())) {//新增,現在這種情況,該記錄可能是從視圖抓取并插入進來的數據,要把他沒有但是接口給的數據補充上LambdaUpdateWrapper<WmWareDispenseBill> updateWrapper = new LambdaUpdateWrapper<>();updateWrapper.eq(WmWareDispenseBill::getBillid, existingBill.getBillid()).set(WmWareDispenseBill::getOperator, username).set(WmWareDispenseBill::getOperateTime, new Date());if (!this.update(updateWrapper)) {throw new RuntimeException("更新處方部門信息失敗,未找到對應記錄或更新失敗");}//創建最終回傳的一個WareInfo對象wareInfo = createWareInfo_split(item, pubWareBase,departmentid);wareInfo.setBillid(existingBill.getBillid());wareInfoList.add(wareInfo); //添加到最終回傳的數據中continue;}// 情況2: status = '10' 且 uploadStatus為null或'00',此時雖然已經掃過碼,但是還沒有上傳醫保,仍可以更改if ("10".equals(existingBill.getStatus()) &&(existingBill.getUploadStatus() == null || "00".equals(existingBill.getUploadStatus()))) {//把這條處方記錄的狀態值、上傳狀態值、操作員等信息通過billid來更新WmWareDispenseBill updateEntity = new WmWareDispenseBill();updateEntity.setBillid(existingBill.getBillid()); //billid取以前創建的billidupdateEntity.setStatus("00");updateEntity.setUploadStatus("00");updateEntity.setOperator(username);updateEntity.setOperateTime(new Date());//更新處方信息if (!this.updateById(updateEntity)) {throw new RuntimeException("處方單狀態重置失敗");}wareInfo = createWareInfo_split(item, pubWareBase,departmentid);wareInfo.setBillid(existingBill.getBillid());wareInfoList.add(wareInfo);//添加到最終回傳的數據中continue;}// 情況3: status = '10' 且 uploadStatus = '10'if ("10".equals(existingBill.getStatus()) && "10".equals(existingBill.getUploadStatus())) {statusCode.set(4);return null; //此時不可更改}}// 程序運行到這,說明這個處方是新處方,所以需要準備需要新建的處方數據WmWareDispenseBill bill = createNewBill_n(item, wareBaseMap, username, "patientId", departmentid);billsToSave.add(bill);  //添加到準備插入處方表的集合中wareInfoList.add(createWareInfo_split(item, pubWareBase,departmentid));}// 程序運行到這,說明這個處方是新處方,所以需要準備需要新建的處方數據WmWareDispenseBill bill = createNewBill_n(item, wareBaseMap, username, "patientId", departmentid);billsToSave.add(bill);  //添加到準備插入處方表的集合中wareInfoList.add(createWareInfo_split(item, pubWareBase,departmentid));}// 5. 新處方if (!billsToSave.isEmpty()) { //需要插入新處方if (!this.saveBatch(billsToSave)) { //保存到處方表throw new RuntimeException("保存處方數據失敗");}//遍歷wareInfoList,為billid為null的記錄設置正確的billidupdateWareInfoListWithBillIds_split(billsToSave, wareInfoList);}return wareInfoList;} catch (Exception e) {log.error("處方數據獲取失敗:", e);return null;}}

????????這里解釋下,情況2: status = '10' 且 uploadStatus為null或'00',此時雖然已經掃過碼,但是還沒有上傳醫保,也就是說無論是誤掃還是隔夜取藥,都認為是這種情況。此時并不在wm_ware_dispense_bill表中插入新的記錄,而是沿用之前的記錄,并且把狀態值復原。

????????這里用到的updateById是在 MyBatis(以及 MyBatis-Plus)中用于根據實體對象的主鍵(ID)更新對應的數據記錄

  • 它會根據傳入實體對象的?主鍵字段(通常是id?定位到數據庫中對應的記錄
  • 然后將實體對象中非空的字段值更新到數據庫表中對應的字段

? ? ? ? 情況3意味著該條記錄已經上傳醫保,此時不可再重新掃碼,因為已經被監管機構記錄,因此掃描該處方單時是不會出現藥品信息的。

1.2.4 如果wm_ware_dispense_bill表中沒有接口回傳的處方信息,則會用到下面的創建處方表記錄的代碼

//處方對象原先不存在時,創建一個新的WmWareDispenseBill對象private WmWareDispenseBill createNewBill_n(Map<String, Object> item, Map<String, PubWareBase> wareBaseMap,String username, String patientid, String departmentid) {WmWareDispenseBill bill = new WmWareDispenseBill();bill.setHospitalid(1L);bill.setDepartmentid(Long.valueOf(departmentid));bill.setBillType(item.get("type").toString());bill.setRxno(item.get("rxno").toString());bill.setRxSerialno(item.get("rx_serialno").toString());bill.setPatientName(item.get("patient_name").toString());String drugCode = item.get("ware_code").toString();PubWareBase pubWareBase = wareBaseMap.get(drugCode);bill.setWareId(pubWareBase != null ? pubWareBase.getWareid() : null);if (pubWareBase != null) {String description = String.format("[%s]%s(%s)/%s/%s/%s",pubWareBase.getWareCode(),pubWareBase.getFormalName(),pubWareBase.getWareName(),pubWareBase.getSpec(),pubWareBase.getUnitName(),pubWareBase.getManufacturer());bill.setDescription(description);}bill.setQuantity(Integer.parseInt(item.get("quantity").toString()));bill.setOperator(username);bill.setOperateTime(new Date());bill.setStatus("00");bill.setPatientid(patientid);try {String dateStr = item.get("rx_date").toString();Date date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").parse(dateStr);bill.setRxDate(date);} catch (ParseException e) {System.out.println(e);}bill.setDoctorName(item.get("doctor_name").toString());bill.setSettlementno(item.get("mdtrt_id").toString());return bill;}

1.2.5 拆零子碼的分配

????????掃描處方時,會有些藥是拆零藥品,發藥時按照1支1粒這種樣式,此時儲備相應的子碼就很有必要。

? ? ? ? 具體拆零子碼如何進表以后再講,這里只要知道一個拆零藥品的追溯碼會根據其拆零系數,在該表內拆分成相應數量的子碼。

? ? ? ? 有上面的子碼,就可以在掃描處方單時,分配需要的子碼:

private WareInfoSplit createWareInfo_split(Map<String, Object> item, PubWareBase pubWareBase,String departmentid) {WareInfoSplit wareInfo = new WareInfoSplit();if ("10".equals(pubWareBase.getSplitFlag()) && !"盒".equals(item.get("price_unit").toString())) {int quantitySplit = Integer.parseInt(item.get("quantity").toString());List<PubTracecodeSubcode> lockedSubcodes = pubTracecodeSubcodeMapper.selectList(new LambdaQueryWrapper<PubTracecodeSubcode>().eq(PubTracecodeSubcode::getTracecodePrefix, pubWareBase.getTracecodePrefix()).eq(PubTracecodeSubcode::getStatus, "00").eq(PubTracecodeSubcode::getLockedStatus, "00").eq(PubTracecodeSubcode::getDepartmentid, departmentid).orderByAsc(PubTracecodeSubcode::getCodeid) // 按固定順序避免死鎖.last("LIMIT " + quantitySplit + " FOR UPDATE") // 核心:鎖定指定數量記錄);// 檢查是否鎖定到足夠數量 ===if (lockedSubcodes.size() < quantitySplit) {wareInfo.setEnoughFlag("10"); // 數量不足}else {// 更新鎖定狀態 ===List<Integer> codeIdsToLock = lockedSubcodes.stream().map(PubTracecodeSubcode::getCodeid).collect(Collectors.toList());pubTracecodeSubcodeMapper.update(null, new LambdaUpdateWrapper<PubTracecodeSubcode>().in(PubTracecodeSubcode::getCodeid, codeIdsToLock).set(PubTracecodeSubcode::getLockedStatus, "10"));// 設置分配結果wareInfo.setEnoughFlag("00");wareInfo.setSubcodeids(codeIdsToLock);wareInfo.setSplitTracecode(lockedSubcodes.get(0).getTracecode());}}wareInfo.setSplitFlag(pubWareBase.getSplitFlag());wareInfo.setWareid(pubWareBase.getWareid().intValue());wareInfo.setPatientName(item.get("patient_name").toString());wareInfo.setWareName(pubWareBase.getWareName());wareInfo.setSpec(pubWareBase.getSpec());wareInfo.setQuantity(Integer.parseInt(item.get("quantity").toString()));wareInfo.setManufacturer(pubWareBase.getManufacturer());wareInfo.setTracecodePrefix(pubWareBase.getTracecodePrefix());wareInfo.setScanFlag(pubWareBase.getScanFlag());return wareInfo;}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/94169.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/94169.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/94169.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Unity編輯器相關

前言繼承EditorWindow。 GUILayout類與EditorGUILayout類的應用區別&#xff1a;//TODO創建窗口的方法1&#xff09;GetWindow<T>() 已開則聚焦、未開則創建。無需再手動調用 Show()。GetWindow<T>() 提供多個重載。2&#xff09;CreateInstance<T>()始終創建…

ES支持哪些數據類型,和MySQL之間的映射關系是怎么樣的?

Elasticsearch&#xff08;簡稱 ES&#xff09;是一個分布式搜索和分析引擎&#xff0c;支持豐富的數據類型來適應不同場景。MySQL 是一個關系型數據庫&#xff0c;兩者在數據類型上存在差異&#xff0c;但可以通過映射實現數據同步或集成。下面我將逐步解釋 ES 支持的數據類型…

8.21IPSEC安全基礎后篇,IKE工作過程

一、數據存儲完整性校驗數據存儲完整性校驗需通過加密密鑰實現。數據存儲前還需通過身份認證&#xff0c;該過程同樣依賴密鑰完成。二、對稱key的產生、傳遞、管理VPN中需使用多組對稱密鑰&#xff1a;數據加解密需獨立密鑰數據完整性校驗需獨立密鑰身份認證需獨立密鑰不同功能…

網絡連接的核心機制

一、網絡連接全流程拆解&#xff08;含7大步驟動態交互&#xff09; 1. 用戶輸入網址&#xff1a;從域名到IP的跨越 操作觸發&#xff1a;用戶在瀏覽器輸入 www.example.com&#xff0c;觸發 DNS域名解析。核心協議&#xff1a;DNS&#xff08;基于UDP/TCP&#xff09;。硬件設…

小程序個人信息安全檢測技術:從監管視角看加密與傳輸合規

1. 前言 在監管通報中&#xff0c;小程序因“未采取加密、去標識化等安全技術措施”被處罰的案例屢見不鮮。很多開發者疑惑&#xff1a;明明用了HTTPS&#xff0c;為什么還會被判定“未加密”&#xff1f;監管機構是如何通過技術手段發現這些問題的&#xff1f;本文將從技術原…

ansible playbook 實戰案例roles | 實現db2自動安裝

文章目錄一、核心功能描述二、roles內容2.1 文件結構2.2 主配置文件2.3 tasks文件內容三、files文件內容四、vars文件內容免費個人運維知識庫&#xff0c;歡迎您的訂閱&#xff1a;literator_ray.flowus.cn 一、核心功能描述 這個 Ansible Role 的核心功能是&#xff1a;?自動…

webrtc中win端音頻---windows Core Audio

一、Core Audio 系統內核框架 圖中顯示的是渲染的音頻數據如何從大多數應用程序流向揚聲器的簡化表示。對于采集來說,音頻數據的路徑是完全相同,但流向是相反的。從圖中可以看到,一些高階API(例如MME,DirectSound等),對 Core Audio APIs 進行了封裝,使用這些API能夠更容…

【數據可視化-96】使用 Pyecharts 繪制主題河流圖(ThemeRiver):步驟與數據組織形式

&#x1f9d1; 博主簡介&#xff1a;曾任某智慧城市類企業算法總監&#xff0c;目前在美國市場的物流公司從事高級算法工程師一職&#xff0c;深耕人工智能領域&#xff0c;精通python數據挖掘、可視化、機器學習等&#xff0c;發表過AI相關的專利并多次在AI類比賽中獲獎。CSDN…

【Android】Activity 如何進行數據傳輸

三三要成為安卓糕手 一&#xff1a;Activity之間的數據傳輸 問題&#xff1a;不同的Activity之間怎么進行數據傳輸呢? 比如第一個頁面中有一些字符串數據之類的要通過數據傳輸&#xff0c;傳遞給第二個頁面進行顯示的 1&#xff1a;MainActivity做處理 在定義一個按鈕&#xf…

C#語言的語法(數據類型)

數據類型 表2.1給出了C#的主要數據類型。注意&#xff0c;基本類型的長度與計算機或操作系統的類型無關。C# 中的字符是16位的寬度&#xff0c;可以表示非拉丁語言中的所有字符。它使用一種叫雙字節碼的字符編碼 系統&#xff0c;其中定義了絕大多數可書寫語言的數以千計的字符…

Vue3 + TypeScript全局阻止非輸入區域的Backspace鍵,防止回退頁面

main.ts/*** 應用程序主入口** 初始化 Vue 應用并掛載到 DOM*/ import "./assets/style/main.scss";import { createApp } from "vue"; // 全局引入element-plus&#xff0c;對打包后的文件大小不是很在乎&#xff0c;那么使用全局導入會更方便 import Ele…

01數據結構-堆排序

01數據結構-堆排序前言1.堆2.堆的操作邏輯3.堆的代碼實現前言 數據結構中的堆是一種結構&#xff0c;C語言的堆是空間管理的程序員malloc&#xff0c;free的空間&#xff0c;兩者沒多大關系。 1.堆 邏輯上 堆&#xff08;Heap&#xff09;是一類基于完全二叉樹的特殊數據結構…

在線課程|基于SprinBoot+vue的在線課程管理系統(源碼+數據庫+文檔)

在線課程 目錄 基于SprinBootvue的在線課程管理系統 一、前言 二、系統設計 三、系統功能設計 1 管理員模塊的實現 2在線課程 四、數據庫設計 五、核心代碼 六、論文參考 七、最新計算機畢設選題推薦 八、源碼獲取&#xff1a; 博主介紹&#xff1a;??大廠碼農|…

Python海象運算符:=

文章目錄簡介??條件判斷優化循環控制簡化?推導式高效計算?正則匹配與數據提取?性能對比參考文獻簡介 海象運算符 :&#xff0c;又稱??賦值表達式??&#xff08;Assignment Expression&#xff09;&#xff0c;Python 3.8 后可用&#xff0c;PEP 572 引入&#xff0c;…

Vue 2 項目中快速集成 Jest 單元測試(超詳細教程)

在 Vue 項目中編寫單元測試&#xff0c;是提升代碼質量和維護性的關鍵一步。本文將帶你從零開始&#xff0c;在一個 Vue 2 Vue CLI 項目中集成 Jest 作為單元測試框架&#xff0c;并運行第一個測試用例。? 適用于 Vue 2 項目&#xff08;如你使用的是 vue-cli-service&#x…

PostgreSQL15——管理表空間

管理表空間一、基本概念二、創建表空間三、修改表空間四、刪除表空間一、基本概念 在 PostgreSQL 中&#xff0c;它是通過表空間&#xff08;Tablespaces&#xff09;來實現邏輯對象&#xff08;表、索引等&#xff09;與物理文件之間的映射。創建數據庫或者數據表&#xff08…

趣打印高級版--手機打印軟件!軟件支持多種不同的連接方式,打印神器有這一個就夠了!

軟件介紹&#xff08;文末獲取&#xff09;趣打印高級版是一款手機打印軟件。軟件支持五種不同的連接方式&#xff0c;每種都有穩定且快速的反應&#xff0c;用戶均可通過手機進行打印機的遠程使用和設置。軟件還支持上傳不同格式的文檔類型進行打印&#xff0c;方便快捷&#…

【開源框架】7 款流行的 Vue 3 后臺管理框架對比

以下是 7 個流行的 Vue 3 后臺管理框架在 Star 數&#xff08;截至 2025 年 8 月21日的 GitHub 最新數據&#xff09;、框架特點、基于的技術棧及開源協議四個方面的詳細對比&#xff1a; 1. Vue-Vben-Admin GitHub 地址&#xff1a;https://github.com/vbenjs/vue-vben-admin…

Datawhale工作流自動化平臺n8n入門教程(一):n8n簡介與平臺部署

前言 在數字化時代&#xff0c;重復性的工作任務正在消耗著我們大量的時間和精力。從數據同步到營銷自動化&#xff0c;從客戶服務到內容管理&#xff0c;這些瑣碎但必要的任務往往讓我們疲于應對。而工作流自動化工具的出現&#xff0c;為我們提供了一個優雅的解決方案。 今天…

SRE - 定位與能力

僅為個人知識總結與記錄 Site Reliability Engineer&#xff1a;站點可靠性工程&#xff08;SRE 軟件工程師 運維專家 可靠性專家&#xff09; 相對傳統的運維工程師&#xff0c;SER 注重開發&#xff0c;效率&#xff0c;追求自動化。對于 SRE 工程師&#xff0c;追究的就是…