commit 7096db84e610aa71e2491d0aa96f1d0fb749232a
Author: SwTt29 <2055018491@qq.com>
Date: Mon Dec 1 17:18:59 2025 +0800
Initial commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules
diff --git a/app.js b/app.js
new file mode 100644
index 0000000..9662778
--- /dev/null
+++ b/app.js
@@ -0,0 +1,108 @@
+App({
+ onLaunch: function () {
+ // 初始化应用
+ console.log('App Launch')
+
+ // 初始化本地存储的标签和用户数据
+ if (!wx.getStorageSync('users')) {
+ wx.setStorageSync('users', {})
+ }
+ if (!wx.getStorageSync('tags')) {
+ wx.setStorageSync('tags', {})
+ }
+ if (!wx.getStorageSync('goods')) {
+ // 初始化空的商品列表,不预置默认数据,由服务器获取
+ wx.setStorageSync('goods', [])
+ }
+ if (!wx.getStorageSync('supplies')) {
+ // 初始化空的供应列表,不预置默认数据,由服务器获取
+ wx.setStorageSync('supplies', [])
+ }
+
+ // 检查是否是首次启动
+ const isFirstLaunch = !wx.getStorageSync('hasLaunched')
+ if (isFirstLaunch) {
+ // 标记应用已经启动过
+ wx.setStorageSync('hasLaunched', true)
+
+ // 只有在首次启动时才检查用户身份并可能跳转
+ const userId = wx.getStorageSync('userId')
+ if (userId) {
+ const users = wx.getStorageSync('users')
+ const user = users[userId]
+ if (user && user.type) {
+ // 延迟跳转,确保页面加载完成
+ setTimeout(() => {
+ try {
+ if (user.type === 'buyer') {
+ wx.switchTab({ url: '/pages/buyer/index' })
+ } else if (user.type === 'seller') {
+ wx.switchTab({ url: '/pages/seller/index' })
+ }
+ } catch (e) {
+ console.error('启动时页面跳转异常:', e)
+ // 即使跳转失败,也不影响应用正常启动
+ }
+ }, 100)
+ }
+ }
+ }
+
+ // 获取用户信息
+ wx.getSetting({
+ success: res => {
+ if (res.authSetting['scope.userInfo']) {
+ // 已经授权,可以直接调用 getUserInfo 获取头像昵称
+ wx.getUserInfo({
+ success: res => {
+ this.globalData.userInfo = res.userInfo
+ // 存储用户ID(实际项目中使用openid)
+ if (!wx.getStorageSync('userId')) {
+ const userId = 'user_' + Date.now()
+ wx.setStorageSync('userId', userId)
+ // 初始化用户数据
+ const users = wx.getStorageSync('users')
+ users[userId] = {
+ info: res.userInfo,
+ type: null
+ }
+ wx.setStorageSync('users', users)
+ }
+ }
+ })
+ }
+ }
+ })
+ },
+ onShow: function () {
+ console.log('App Show')
+ },
+ onHide: function () {
+ console.log('App Hide')
+ },
+
+ // 更新当前选中的tab
+ updateCurrentTab(tabKey) {
+ if (this.globalData) {
+ this.globalData.currentTab = tabKey
+ }
+ },
+
+ // 跳转到估价页面
+ goToEvaluatePage() {
+ wx.navigateTo({
+ url: '/pages/evaluate/index'
+ })
+ },
+
+ // 上传手机号数据
+ async uploadPhoneNumberData(phoneData) {
+ const API = require('./utils/api.js')
+ return await API.uploadPhoneNumberData(phoneData)
+ },
+
+ globalData: {
+ userInfo: null,
+ currentTab: 'index' // 当前选中的tab
+ }
+})
diff --git a/app.json b/app.json
new file mode 100644
index 0000000..b26f62d
--- /dev/null
+++ b/app.json
@@ -0,0 +1,76 @@
+{
+ "pages": [
+ "pages/index/index",
+ "pages/evaluate/index",
+ "pages/settlement/index",
+ "pages/publish/index",
+ "pages/buyer/index",
+ "pages/seller/index",
+ "pages/profile/index",
+ "pages/notopen/index"
+ ],
+ "subpackages": [
+ {
+ "root": "pages/debug",
+ "pages": [
+ "debug",
+ "debug-sold-out",
+ "debug-gross-weight"
+ ],
+ "independent": false
+ },
+ {
+ "root": "pages/test",
+ "pages": [
+ "undercarriage-test"
+ ],
+ "independent": false
+ },
+ {
+ "root": "pages/test-tools",
+ "pages": [
+ "test-mode-switch",
+ "connection-test",
+ "api-test",
+ "phone-test",
+ "clear-storage",
+ "gross-weight-tester",
+ "fix-connection"
+ ],
+ "independent": false
+ }
+ ],
+ "window": {
+ "backgroundTextStyle": "light",
+ "navigationBarBackgroundColor": "#fff",
+ "navigationBarTitleText": "又鸟蛋平台",
+ "navigationBarTextStyle": "black"
+ },
+ "tabBar": {
+ "custom": true,
+ "color": "#999999",
+ "selectedColor": "#FF6B81",
+ "backgroundColor": "#ffffff",
+ "borderStyle": "black",
+ "list": [
+ {
+ "pagePath": "pages/index/index",
+ "text": "首页"
+ },
+ {
+ "pagePath": "pages/buyer/index",
+ "text": "购物"
+ },
+ {
+ "pagePath": "pages/seller/index",
+ "text": "货源"
+ },
+ {
+ "pagePath": "pages/profile/index",
+ "text": "我的"
+ }
+ ]
+ },
+ "style": "v2",
+ "sitemapLocation": "sitemap.json"
+}
\ No newline at end of file
diff --git a/app.wxss b/app.wxss
new file mode 100644
index 0000000..770f3de
--- /dev/null
+++ b/app.wxss
@@ -0,0 +1,44 @@
+/**app.wxss**/
+.container {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+ background-color: #f5f5f5;
+ }
+
+ .btn {
+ width: 80%;
+ padding: 15rpx 0;
+ margin: 20rpx 0;
+ border-radius: 10rpx;
+ font-size: 32rpx;
+ }
+
+ .card {
+ width: 90%;
+ padding: 30rpx;
+ margin: 20rpx 0;
+ background-color: #fff;
+ border-radius: 10rpx;
+ box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.1);
+ }
+
+ .title {
+ font-size: 36rpx;
+ font-weight: bold;
+ margin-bottom: 20rpx;
+ }
+
+ .input {
+ width: 100%;
+ max-width: 100%;
+ padding: 20rpx;
+ margin: 15rpx 0;
+ border: 1px solid #eee;
+ border-radius: 5rpx;
+ font-size: 28rpx;
+ box-sizing: border-box;
+ }
\ No newline at end of file
diff --git a/components/navigation-bar/navigation-bar.js b/components/navigation-bar/navigation-bar.js
new file mode 100644
index 0000000..eb1770e
--- /dev/null
+++ b/components/navigation-bar/navigation-bar.js
@@ -0,0 +1,102 @@
+Component({
+ options: {
+ multipleSlots: true // 在组件定义时的选项中启用多slot支持
+ },
+ /**
+ * 组件的属性列表
+ */
+ properties: {
+ extClass: {
+ type: String,
+ value: ''
+ },
+ title: {
+ type: String,
+ value: ''
+ },
+ background: {
+ type: String,
+ value: ''
+ },
+ color: {
+ type: String,
+ value: ''
+ },
+ back: {
+ type: Boolean,
+ value: true
+ },
+ loading: {
+ type: Boolean,
+ value: false
+ },
+ homeButton: {
+ type: Boolean,
+ value: false,
+ },
+ animated: {
+ // 显示隐藏的时候opacity动画效果
+ type: Boolean,
+ value: true
+ },
+ show: {
+ // 显示隐藏导航,隐藏的时候navigation-bar的高度占位还在
+ type: Boolean,
+ value: true,
+ observer: '_showChange'
+ },
+ // back为true的时候,返回的页面深度
+ delta: {
+ type: Number,
+ value: 1
+ },
+ },
+ /**
+ * 组件的初始数据
+ */
+ data: {
+ displayStyle: ''
+ },
+ lifetimes: {
+ attached() {
+ const rect = wx.getMenuButtonBoundingClientRect()
+ const platform = (wx.getDeviceInfo() || wx.getSystemInfoSync()).platform
+ const isAndroid = platform === 'android'
+ const isDevtools = platform === 'devtools'
+ const { windowWidth, safeArea: { top = 0, bottom = 0 } = {} } = wx.getWindowInfo() || wx.getSystemInfoSync()
+ this.setData({
+ ios: !isAndroid,
+ innerPaddingRight: `padding-right: ${windowWidth - rect.left}px`,
+ leftWidth: `width: ${windowWidth - rect.left}px`,
+ safeAreaTop: isDevtools || isAndroid ? `height: calc(var(--height) + ${top}px); padding-top: ${top}px` : ``
+ })
+ },
+ },
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ _showChange(show) {
+ const animated = this.data.animated
+ let displayStyle = ''
+ if (animated) {
+ displayStyle = `opacity: ${show ? '1' : '0'
+ };transition:opacity 0.5s;`
+ } else {
+ displayStyle = `display: ${show ? '' : 'none'}`
+ }
+ this.setData({
+ displayStyle
+ })
+ },
+ back() {
+ const data = this.data
+ if (data.delta) {
+ wx.navigateBack({
+ delta: data.delta
+ })
+ }
+ this.triggerEvent('back', { delta: data.delta }, {})
+ }
+ },
+})
diff --git a/components/navigation-bar/navigation-bar.json b/components/navigation-bar/navigation-bar.json
new file mode 100644
index 0000000..4a20f17
--- /dev/null
+++ b/components/navigation-bar/navigation-bar.json
@@ -0,0 +1,5 @@
+{
+ "component": true,
+ "styleIsolation": "apply-shared",
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/components/navigation-bar/navigation-bar.wxml b/components/navigation-bar/navigation-bar.wxml
new file mode 100644
index 0000000..be9a663
--- /dev/null
+++ b/components/navigation-bar/navigation-bar.wxml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{title}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/navigation-bar/navigation-bar.wxss b/components/navigation-bar/navigation-bar.wxss
new file mode 100644
index 0000000..8bd379e
--- /dev/null
+++ b/components/navigation-bar/navigation-bar.wxss
@@ -0,0 +1,96 @@
+.weui-navigation-bar {
+ --weui-FG-0:rgba(0,0,0,.9);
+ --height: 44px;
+ --left: 16px;
+}
+.weui-navigation-bar .android {
+ --height: 48px;
+}
+
+.weui-navigation-bar {
+ overflow: hidden;
+ color: var(--weui-FG-0);
+ flex: none;
+}
+
+.weui-navigation-bar__inner {
+ position: relative;
+ top: 0;
+ left: 0;
+ height: calc(var(--height) + env(safe-area-inset-top));
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ padding-top: env(safe-area-inset-top);
+ width: 100%;
+ box-sizing: border-box;
+}
+
+.weui-navigation-bar__left {
+ position: relative;
+ padding-left: var(--left);
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+ height: 100%;
+ box-sizing: border-box;
+}
+
+.weui-navigation-bar__btn_goback_wrapper {
+ padding: 11px 18px 11px 16px;
+ margin: -11px -18px -11px -16px;
+}
+
+.weui-navigation-bar__btn_goback_wrapper.weui-active {
+ opacity: 0.5;
+}
+
+.weui-navigation-bar__btn_goback {
+ font-size: 12px;
+ width: 12px;
+ height: 24px;
+ -webkit-mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
+ mask: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='24' viewBox='0 0 12 24'%3E %3Cpath fill-opacity='.9' fill-rule='evenodd' d='M10 19.438L8.955 20.5l-7.666-7.79a1.02 1.02 0 0 1 0-1.42L8.955 3.5 10 4.563 2.682 12 10 19.438z'/%3E%3C/svg%3E") no-repeat 50% 50%;
+ -webkit-mask-size: cover;
+ mask-size: cover;
+ background-color: var(--weui-FG-0);
+}
+
+.weui-navigation-bar__center {
+ font-size: 17px;
+ text-align: center;
+ position: relative;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ font-weight: bold;
+ flex: 1;
+ height: 100%;
+}
+
+.weui-navigation-bar__loading {
+ margin-right: 4px;
+ align-items: center;
+}
+
+.weui-loading {
+ font-size: 16px;
+ width: 16px;
+ height: 16px;
+ display: block;
+ background: transparent url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='80px' height='80px' viewBox='0 0 80 80' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3Eloading%3C/title%3E%3Cdefs%3E%3ClinearGradient x1='94.0869141%25' y1='0%25' x2='94.0869141%25' y2='90.559082%25' id='linearGradient-1'%3E%3Cstop stop-color='%23606060' stop-opacity='0' offset='0%25'%3E%3C/stop%3E%3Cstop stop-color='%23606060' stop-opacity='0.3' offset='100%25'%3E%3C/stop%3E%3C/linearGradient%3E%3ClinearGradient x1='100%25' y1='8.67370605%25' x2='100%25' y2='90.6286621%25' id='linearGradient-2'%3E%3Cstop stop-color='%23606060' offset='0%25'%3E%3C/stop%3E%3Cstop stop-color='%23606060' stop-opacity='0.3' offset='100%25'%3E%3C/stop%3E%3C/linearGradient%3E%3C/defs%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' opacity='0.9'%3E%3Cg%3E%3Cpath d='M40,0 C62.09139,0 80,17.90861 80,40 C80,62.09139 62.09139,80 40,80 L40,73 C58.2253967,73 73,58.2253967 73,40 C73,21.7746033 58.2253967,7 40,7 L40,0 Z' fill='url(%23linearGradient-1)'%3E%3C/path%3E%3Cpath d='M40,0 L40,7 C21.7746033,7 7,21.7746033 7,40 C7,58.2253967 21.7746033,73 40,73 L40,80 C17.90861,80 0,62.09139 0,40 C0,17.90861 17.90861,0 40,0 Z' fill='url(%23linearGradient-2)'%3E%3C/path%3E%3Ccircle id='Oval' fill='%23606060' cx='40.5' cy='3.5' r='3.5'%3E%3C/circle%3E%3C/g%3E%3C/g%3E%3C/svg%3E%0A") no-repeat;
+ background-size: 100%;
+ margin-left: 0;
+ animation: loading linear infinite 1s;
+}
+
+@keyframes loading {
+ from {
+ transform: rotate(0);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
diff --git a/custom-tab-bar/index.js b/custom-tab-bar/index.js
new file mode 100644
index 0000000..a0fdcf1
--- /dev/null
+++ b/custom-tab-bar/index.js
@@ -0,0 +1,348 @@
+Component({
+ /**
+ * 组件的属性列表
+ */
+ properties: {
+ },
+
+ /**
+ * 组件的初始数据
+ */
+ data: {
+ selected: 'index',
+ show: true, // 控制tab-bar显示状态
+ // 记录tabBar数据,用于匹配
+ tabBarItems: [
+ { key: 'index', route: 'pages/index/index' },
+ { key: 'buyer', route: 'pages/buyer/index' },
+ { key: 'seller', route: 'pages/seller/index' },
+ { key: 'profile', route: 'pages/profile/index' }
+ ]
+ },
+
+ /**
+ * 组件的方法列表
+ */
+ methods: {
+ // 切换tab页面的方法 - 增强版,改进状态管理
+ switchTab(e) {
+ try {
+ const data = e.currentTarget.dataset
+ let url = data.path
+ const key = data.key
+
+ console.log('点击tab项:', key, '原始路径:', url)
+
+ // 确保路径格式正确 - 移除可能的前缀斜杠
+ if (url.startsWith('/')) {
+ url = url.substring(1)
+ }
+
+ console.log('修正后路径:', url)
+
+ // 更新全局数据 - 先更新全局状态,确保状态一致性
+ const app = getApp()
+ if (app && app.globalData) {
+ app.globalData.currentTab = key
+ console.log('同步选中状态到全局数据:', key)
+ }
+
+ // 立即更新UI选中状态
+ this.setData({
+ selected: key
+ })
+
+ // 无论跳转到哪个页面,先确保用户身份被正确设置
+ if (key === 'buyer' || key === 'seller') {
+ const userId = wx.getStorageSync('userId');
+ if (userId) {
+ // 更新用户类型
+ let users = wx.getStorageSync('users');
+ if (typeof users !== 'object' || users === null) {
+ users = {};
+ }
+ if (!users[userId]) {
+ users[userId] = {};
+ }
+ users[userId].type = key;
+ wx.setStorageSync('users', users);
+
+ // 更新标签
+ let tags = wx.getStorageSync('tags');
+ if (typeof tags !== 'object' || tags === null) {
+ tags = {};
+ }
+ tags[userId] = tags[userId] || [];
+ tags[userId] = tags[userId].filter(tag => !tag.startsWith('身份:'));
+ tags[userId].push(`身份:${key}`);
+ wx.setStorageSync('tags', tags);
+ }
+ }
+
+ // 特殊处理:点击货源页面时检查登录状态和入驻状态
+ if (key === 'seller' && url === 'pages/seller/index') {
+ console.log('点击货源页面,开始检查登录状态和入驻状态...');
+
+ // 首先检查登录状态
+ const userId = wx.getStorageSync('userId');
+ const userInfo = wx.getStorageSync('userInfo');
+
+ if (!userId || !userInfo) {
+ console.log('用户未登录,跳转到登录或入驻页面');
+ wx.navigateTo({
+ url: '/pages/settlement/index',
+ success: (res) => {
+ console.log('跳转到入驻页面成功:', res);
+ },
+ fail: (err) => {
+ console.error('跳转到入驻页面失败:', err);
+ this.navigateToTabPage(url);
+ }
+ });
+ } else {
+ // 用户已登录,检查合作商状态
+ const settlementStatus = wx.getStorageSync('settlement_status');
+ console.log('检查合作商状态:', settlementStatus);
+
+ if (!settlementStatus || settlementStatus === '') {
+ console.log('合作商状态不存在,用户未入驻');
+ wx.navigateTo({
+ url: '/pages/settlement/index'
+ });
+ } else if (settlementStatus === 'underreview') {
+ console.log('合作商状态为审核中,跳转到货源页面显示审核中内容');
+ this.navigateToTabPage(url);
+ } else if (settlementStatus === 'approved' || settlementStatus === 'incooperation') {
+ console.log('合作商状态为审核通过,正常跳转到货源页面');
+ this.navigateToTabPage(url);
+ } else {
+ console.log('其他状态,跳转到入驻页面');
+ wx.navigateTo({
+ url: '/pages/settlement/index'
+ });
+ }
+ }
+ } else {
+ // 其他tab页面正常跳转
+ this.navigateToTabPage(url)
+ }
+ } catch (e) {
+ console.error('switchTab方法执行错误:', e)
+ }
+ },
+
+ // 跳转到tab页面的通用方法
+ navigateToTabPage(url) {
+ console.log('使用switchTab跳转到tabbar页面:', url)
+ wx.switchTab({
+ url: '/' + url,
+ success: (res) => {
+ console.log('switchTab成功:', url, res)
+ },
+ fail: (err) => {
+ console.error('switchTab失败:', url, err)
+ console.log('尝试使用reLaunch跳转...')
+ wx.reLaunch({
+ url: '/' + url,
+ success: (res) => {
+ console.log('reLaunch成功:', url, res)
+ },
+ fail: (err) => {
+ console.error('reLaunch也失败:', url, err)
+ }
+ })
+ }
+ })
+ },
+
+ // 强制更新选中状态
+ forceUpdateSelectedState(key) {
+ try {
+ this.setData({
+ selected: key
+ })
+ console.log('强制更新选中状态:', key)
+ // 再次同步全局数据,确保双向一致性
+ const app = getApp()
+ if (app && app.globalData) {
+ app.globalData.currentTab = key
+ }
+ } catch (e) {
+ console.error('强制更新选中状态失败:', e)
+ }
+ },
+
+ // 恢复到之前的状态
+ restorePreviousState() {
+ try {
+ const app = getApp()
+ if (app && app.globalData && app.globalData.currentTab) {
+ this.setData({
+ selected: app.globalData.currentTab
+ })
+ console.log('恢复选中状态到:', app.globalData.currentTab)
+ }
+ } catch (e) {
+ console.error('恢复状态失败:', e)
+ }
+ },
+
+ // 跳转到鸡蛋估价页面 - 现已改为未开放页面
+ goToEvaluatePage() {
+ wx.navigateTo({
+ url: '/pages/notopen/index'
+ })
+ },
+
+ // 从全局数据同步状态的方法 - 增强版
+ syncFromGlobalData() {
+ try {
+ const app = getApp()
+ const pages = getCurrentPages()
+ let currentRoute = ''
+
+ // 获取当前页面路由
+ if (pages && pages.length > 0) {
+ const currentPage = pages[pages.length - 1]
+ currentRoute = currentPage.route
+ console.log('当前页面路由:', currentRoute)
+ }
+
+ // 根据当前页面路由确定应该选中的tab
+ let shouldSelect = 'index'
+ for (let item of this.data.tabBarItems) {
+ if (item.route === currentRoute) {
+ shouldSelect = item.key
+ break
+ }
+ }
+
+ // 检查全局数据中是否有控制tab-bar显示的状态
+ let showTabBar = true
+ if (app && app.globalData && typeof app.globalData.showTabBar !== 'undefined') {
+ showTabBar = app.globalData.showTabBar
+ }
+
+ // 更新全局数据和本地数据,确保一致性
+ if (app && app.globalData) {
+ app.globalData.currentTab = shouldSelect
+ }
+
+ // 只在状态不一致时更新,避免频繁重绘
+ const updates = {}
+ if (this.data.selected !== shouldSelect) {
+ updates.selected = shouldSelect
+ console.log('根据当前页面路由更新选中状态:', shouldSelect)
+ }
+
+ if (this.data.show !== showTabBar) {
+ updates.show = showTabBar
+ console.log('更新tab-bar显示状态:', showTabBar)
+ }
+
+ if (Object.keys(updates).length > 0) {
+ this.setData(updates)
+ }
+ } catch (e) {
+ console.error('从全局数据同步状态失败:', e)
+ }
+ },
+
+ // 开始监听全局tab-bar显示状态变化
+ startTabBarStatusListener() {
+ // 使用定时器定期检查全局状态
+ this.tabBarStatusTimer = setInterval(() => {
+ try {
+ const app = getApp()
+ if (app && app.globalData && typeof app.globalData.showTabBar !== 'undefined') {
+ const showTabBar = app.globalData.showTabBar
+ if (this.data.show !== showTabBar) {
+ this.setData({
+ show: showTabBar
+ })
+ console.log('tab-bar显示状态更新:', showTabBar)
+ }
+ }
+ } catch (e) {
+ console.error('监听tab-bar状态失败:', e)
+ }
+ }, 100) // 每100ms检查一次,确保响应迅速
+ }
+ },
+
+ // 组件生命周期
+ lifetimes: {
+ // 组件挂载时执行
+ attached() {
+ console.log('tabBar组件挂载')
+ // 初始化时从全局数据同步一次状态,使用较长延迟确保页面完全加载
+ setTimeout(() => {
+ this.syncFromGlobalData()
+ }, 100)
+
+ // 监听全局tab-bar显示状态变化
+ this.startTabBarStatusListener()
+ },
+
+ // 组件被移动到节点树另一个位置时执行
+ moved() {
+ console.log('tabBar组件移动')
+ // 组件移动时重新同步状态
+ this.syncFromGlobalData()
+ },
+
+ // 组件卸载时执行
+ detached() {
+ console.log('tabBar组件卸载')
+ // 清理定时器
+ if (this.tabBarStatusTimer) {
+ clearInterval(this.tabBarStatusTimer)
+ }
+ }
+ },
+
+ // 页面生命周期
+ pageLifetimes: {
+ // 页面显示时执行
+ show() {
+ console.log('页面显示')
+ const pages = getCurrentPages()
+ if (pages && pages.length > 0) {
+ const currentPage = pages[pages.length - 1]
+ // 对于profile页面,使用更长的延迟以避免服务器错误影响
+ if (currentPage.route === 'pages/profile/index') {
+ setTimeout(() => {
+ this.syncFromGlobalData()
+ // 额外确保profile页面状态正确
+ setTimeout(() => {
+ this.forceUpdateSelectedState('profile')
+ }, 200)
+ }, 200)
+ } else {
+ // 其他页面使用适当延迟
+ setTimeout(() => {
+ this.syncFromGlobalData()
+ }, 50)
+ }
+ }
+
+ // 页面显示时默认显示tab-bar,除非有全局控制
+ const app = getApp()
+ if (app && app.globalData && typeof app.globalData.showTabBar === 'undefined') {
+ this.setData({
+ show: true
+ })
+ }
+ },
+
+ // 页面隐藏时执行
+ hide() {
+ console.log('页面隐藏')
+ // 页面隐藏时保存当前选中状态到全局
+ const app = getApp()
+ if (app && app.globalData) {
+ app.globalData.currentTab = this.data.selected
+ }
+ }
+ }
+})
\ No newline at end of file
diff --git a/custom-tab-bar/index.json b/custom-tab-bar/index.json
new file mode 100644
index 0000000..e8cfaaf
--- /dev/null
+++ b/custom-tab-bar/index.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/custom-tab-bar/index.wxml b/custom-tab-bar/index.wxml
new file mode 100644
index 0000000..aaae602
--- /dev/null
+++ b/custom-tab-bar/index.wxml
@@ -0,0 +1,47 @@
+
+
+
+
+ 🏠
+ 首页
+
+
+
+ 🐥
+ 买蛋
+
+
+
+
+
+
+ 🥚
+ 估
+
+
+
+
+
+
+ 🐣
+ 卖蛋
+
+
+
+ 👤
+ 我的
+
+
+
\ No newline at end of file
diff --git a/custom-tab-bar/index.wxss b/custom-tab-bar/index.wxss
new file mode 100644
index 0000000..3b5b7e3
--- /dev/null
+++ b/custom-tab-bar/index.wxss
@@ -0,0 +1,176 @@
+.tab-bar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 140rpx;
+ background: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(20rpx);
+ -webkit-backdrop-filter: blur(20rpx);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ border-top: 1rpx solid rgba(255, 255, 255, 0.8);
+ padding: 0 20rpx;
+ box-shadow: 0 -8rpx 40rpx rgba(0, 0, 0, 0.08);
+ z-index: 1000;
+}
+
+/* 左侧按钮组 */
+.tab-bar-left {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ flex: 1;
+}
+
+/* 右侧按钮组 */
+.tab-bar-right {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ flex: 1;
+}
+
+/* 中间鸡蛋按钮区域 */
+.tab-bar-center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ width: 140rpx;
+ height: 100%;
+}
+
+.tab-bar-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ width: 120rpx;
+ height: 100%;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ position: relative;
+ border-radius: 20rpx;
+ margin: 0 10rpx;
+}
+
+.tab-bar-item:active {
+ transform: scale(0.92);
+ background: rgba(0, 0, 0, 0.05);
+}
+
+
+
+.tab-bar-icon {
+ font-size: 44rpx;
+ margin-bottom: 8rpx;
+ filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.1));
+}
+
+
+
+.tab-bar-text {
+ font-size: 22rpx;
+ color: #666;
+ font-weight: 500;
+}
+
+
+
+/* 鸡蛋估价按钮样式 */
+.egg-button {
+ position: relative;
+ width: 120rpx;
+ height: 120rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+ background: transparent;
+ border-radius: 50%;
+ margin-top: -40rpx;
+}
+
+.egg-button:active {
+ transform: scale(0.9);
+}
+
+.egg-icon {
+ font-size: 90rpx;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ animation: eggMagic 4s ease-in-out infinite;
+ text-shadow: 0 4rpx 12rpx rgba(255, 107, 0, 0.4);
+}
+
+@keyframes eggMagic {
+ 0%, 100% {
+ transform: translateY(0) rotate(0deg);
+ filter: brightness(1) saturate(1);
+ }
+ 25% {
+ transform: translateY(-12rpx) rotate(2deg);
+ filter: brightness(1.1) saturate(1.2);
+ }
+ 50% {
+ transform: translateY(-6rpx) rotate(-1deg);
+ filter: brightness(1.05) saturate(1.1);
+ }
+ 75% {
+ transform: translateY(-10rpx) rotate(1deg);
+ filter: brightness(1.15) saturate(1.3);
+ }
+}
+
+.egg-text {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ font-size: 30rpx;
+ font-weight: bold;
+ color: #FFFFFF;
+ text-shadow:
+ 0 2rpx 4rpx rgba(255, 107, 0, 0.8),
+ 0 4rpx 12rpx rgba(255, 107, 0, 0.4);
+ z-index: 2;
+ letter-spacing: 1rpx;
+}
+
+/* 移除发光效果 */
+
+/* 添加分隔线 */
+.tab-bar-left .tab-bar-item:last-child::after {
+ content: '';
+ position: absolute;
+ right: -15rpx;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 1rpx;
+ height: 40rpx;
+ background: linear-gradient(to bottom,
+ transparent,
+ rgba(0, 0, 0, 0.1),
+ transparent);
+}
+
+.tab-bar-right .tab-bar-item:first-child::before {
+ content: '';
+ position: absolute;
+ left: -15rpx;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 1rpx;
+ height: 40rpx;
+ background: linear-gradient(to bottom,
+ transparent,
+ rgba(0, 0, 0, 0.1),
+ transparent);
+}
\ No newline at end of file
diff --git a/images/logo.svg b/images/logo.svg
new file mode 100644
index 0000000..9e92c4c
--- /dev/null
+++ b/images/logo.svg
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/images/生成鸡蛋贸易平台图片.png b/images/生成鸡蛋贸易平台图片.png
new file mode 100644
index 0000000..c9f0212
Binary files /dev/null and b/images/生成鸡蛋贸易平台图片.png differ
diff --git a/miniprogram_npm/accepts/miniprogram_npm/mime-db/index.js b/miniprogram_npm/accepts/miniprogram_npm/mime-db/index.js
new file mode 100644
index 0000000..bcd7c6a
--- /dev/null
+++ b/miniprogram_npm/accepts/miniprogram_npm/mime-db/index.js
@@ -0,0 +1,9370 @@
+module.exports = (function() {
+var __MODS__ = {};
+var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
+var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
+var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
+var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
+__DEFINE__(1761637667903, function(require, module, exports) {
+/*!
+ * mime-db
+ * Copyright(c) 2014 Jonathan Ong
+ * Copyright(c) 2015-2022 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+/**
+ * Module exports.
+ */
+
+module.exports = require('./db.json')
+
+}, function(modId) {var map = {"./db.json":1761637667904}; return __REQUIRE__(map[modId], modId); })
+__DEFINE__(1761637667904, function(require, module, exports) {
+module.exports = {
+ "application/1d-interleaved-parityfec": {
+ "source": "iana"
+ },
+ "application/3gpdash-qoe-report+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/3gpp-ims+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/3gpphal+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/3gpphalforms+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/a2l": {
+ "source": "iana"
+ },
+ "application/ace+cbor": {
+ "source": "iana"
+ },
+ "application/ace+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/ace-groupcomm+cbor": {
+ "source": "iana"
+ },
+ "application/ace-trl+cbor": {
+ "source": "iana"
+ },
+ "application/activemessage": {
+ "source": "iana"
+ },
+ "application/activity+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/aif+cbor": {
+ "source": "iana"
+ },
+ "application/aif+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-cdni+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-cdnifilter+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-costmap+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-costmapfilter+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-directory+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-endpointcost+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-endpointcostparams+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-endpointprop+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-endpointpropparams+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-error+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-networkmap+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-networkmapfilter+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-propmap+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-propmapparams+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-tips+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-tipsparams+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-updatestreamcontrol+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/alto-updatestreamparams+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/aml": {
+ "source": "iana"
+ },
+ "application/andrew-inset": {
+ "source": "iana",
+ "extensions": ["ez"]
+ },
+ "application/appinstaller": {
+ "compressible": false,
+ "extensions": ["appinstaller"]
+ },
+ "application/applefile": {
+ "source": "iana"
+ },
+ "application/applixware": {
+ "source": "apache",
+ "extensions": ["aw"]
+ },
+ "application/appx": {
+ "compressible": false,
+ "extensions": ["appx"]
+ },
+ "application/appxbundle": {
+ "compressible": false,
+ "extensions": ["appxbundle"]
+ },
+ "application/at+jwt": {
+ "source": "iana"
+ },
+ "application/atf": {
+ "source": "iana"
+ },
+ "application/atfx": {
+ "source": "iana"
+ },
+ "application/atom+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["atom"]
+ },
+ "application/atomcat+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["atomcat"]
+ },
+ "application/atomdeleted+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["atomdeleted"]
+ },
+ "application/atomicmail": {
+ "source": "iana"
+ },
+ "application/atomsvc+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["atomsvc"]
+ },
+ "application/atsc-dwd+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["dwd"]
+ },
+ "application/atsc-dynamic-event-message": {
+ "source": "iana"
+ },
+ "application/atsc-held+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["held"]
+ },
+ "application/atsc-rdt+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/atsc-rsat+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rsat"]
+ },
+ "application/atxml": {
+ "source": "iana"
+ },
+ "application/auth-policy+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/automationml-aml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["aml"]
+ },
+ "application/automationml-amlx+zip": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["amlx"]
+ },
+ "application/bacnet-xdd+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/batch-smtp": {
+ "source": "iana"
+ },
+ "application/bdoc": {
+ "compressible": false,
+ "extensions": ["bdoc"]
+ },
+ "application/beep+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/bufr": {
+ "source": "iana"
+ },
+ "application/c2pa": {
+ "source": "iana"
+ },
+ "application/calendar+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/calendar+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xcs"]
+ },
+ "application/call-completion": {
+ "source": "iana"
+ },
+ "application/cals-1840": {
+ "source": "iana"
+ },
+ "application/captive+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/cbor": {
+ "source": "iana"
+ },
+ "application/cbor-seq": {
+ "source": "iana"
+ },
+ "application/cccex": {
+ "source": "iana"
+ },
+ "application/ccmp+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/ccxml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["ccxml"]
+ },
+ "application/cda+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/cdfx+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["cdfx"]
+ },
+ "application/cdmi-capability": {
+ "source": "iana",
+ "extensions": ["cdmia"]
+ },
+ "application/cdmi-container": {
+ "source": "iana",
+ "extensions": ["cdmic"]
+ },
+ "application/cdmi-domain": {
+ "source": "iana",
+ "extensions": ["cdmid"]
+ },
+ "application/cdmi-object": {
+ "source": "iana",
+ "extensions": ["cdmio"]
+ },
+ "application/cdmi-queue": {
+ "source": "iana",
+ "extensions": ["cdmiq"]
+ },
+ "application/cdni": {
+ "source": "iana"
+ },
+ "application/ce+cbor": {
+ "source": "iana"
+ },
+ "application/cea": {
+ "source": "iana"
+ },
+ "application/cea-2018+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/cellml+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/cfw": {
+ "source": "iana"
+ },
+ "application/cid-edhoc+cbor-seq": {
+ "source": "iana"
+ },
+ "application/city+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/city+json-seq": {
+ "source": "iana"
+ },
+ "application/clr": {
+ "source": "iana"
+ },
+ "application/clue+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/clue_info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/cms": {
+ "source": "iana"
+ },
+ "application/cnrp+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/coap-eap": {
+ "source": "iana"
+ },
+ "application/coap-group+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/coap-payload": {
+ "source": "iana"
+ },
+ "application/commonground": {
+ "source": "iana"
+ },
+ "application/concise-problem-details+cbor": {
+ "source": "iana"
+ },
+ "application/conference-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/cose": {
+ "source": "iana"
+ },
+ "application/cose-key": {
+ "source": "iana"
+ },
+ "application/cose-key-set": {
+ "source": "iana"
+ },
+ "application/cose-x509": {
+ "source": "iana"
+ },
+ "application/cpl+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["cpl"]
+ },
+ "application/csrattrs": {
+ "source": "iana"
+ },
+ "application/csta+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/cstadata+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/csvm+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/cu-seeme": {
+ "source": "apache",
+ "extensions": ["cu"]
+ },
+ "application/cwl": {
+ "source": "iana",
+ "extensions": ["cwl"]
+ },
+ "application/cwl+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/cwl+yaml": {
+ "source": "iana"
+ },
+ "application/cwt": {
+ "source": "iana"
+ },
+ "application/cybercash": {
+ "source": "iana"
+ },
+ "application/dart": {
+ "compressible": true
+ },
+ "application/dash+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mpd"]
+ },
+ "application/dash-patch+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mpp"]
+ },
+ "application/dashdelta": {
+ "source": "iana"
+ },
+ "application/davmount+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["davmount"]
+ },
+ "application/dca-rft": {
+ "source": "iana"
+ },
+ "application/dcd": {
+ "source": "iana"
+ },
+ "application/dec-dx": {
+ "source": "iana"
+ },
+ "application/dialog-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/dicom": {
+ "source": "iana",
+ "extensions": ["dcm"]
+ },
+ "application/dicom+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/dicom+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/dii": {
+ "source": "iana"
+ },
+ "application/dit": {
+ "source": "iana"
+ },
+ "application/dns": {
+ "source": "iana"
+ },
+ "application/dns+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/dns-message": {
+ "source": "iana"
+ },
+ "application/docbook+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["dbk"]
+ },
+ "application/dots+cbor": {
+ "source": "iana"
+ },
+ "application/dpop+jwt": {
+ "source": "iana"
+ },
+ "application/dskpp+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/dssc+der": {
+ "source": "iana",
+ "extensions": ["dssc"]
+ },
+ "application/dssc+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xdssc"]
+ },
+ "application/dvcs": {
+ "source": "iana"
+ },
+ "application/eat+cwt": {
+ "source": "iana"
+ },
+ "application/eat+jwt": {
+ "source": "iana"
+ },
+ "application/eat-bun+cbor": {
+ "source": "iana"
+ },
+ "application/eat-bun+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/eat-ucs+cbor": {
+ "source": "iana"
+ },
+ "application/eat-ucs+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/ecmascript": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["ecma"]
+ },
+ "application/edhoc+cbor-seq": {
+ "source": "iana"
+ },
+ "application/edi-consent": {
+ "source": "iana"
+ },
+ "application/edi-x12": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/edifact": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/efi": {
+ "source": "iana"
+ },
+ "application/elm+json": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/elm+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/emergencycalldata.cap+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/emergencycalldata.comment+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/emergencycalldata.control+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/emergencycalldata.deviceinfo+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/emergencycalldata.ecall.msd": {
+ "source": "iana"
+ },
+ "application/emergencycalldata.legacyesn+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/emergencycalldata.providerinfo+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/emergencycalldata.serviceinfo+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/emergencycalldata.subscriberinfo+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/emergencycalldata.veds+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/emma+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["emma"]
+ },
+ "application/emotionml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["emotionml"]
+ },
+ "application/encaprtp": {
+ "source": "iana"
+ },
+ "application/entity-statement+jwt": {
+ "source": "iana"
+ },
+ "application/epp+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/epub+zip": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["epub"]
+ },
+ "application/eshop": {
+ "source": "iana"
+ },
+ "application/exi": {
+ "source": "iana",
+ "extensions": ["exi"]
+ },
+ "application/expect-ct-report+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/express": {
+ "source": "iana",
+ "extensions": ["exp"]
+ },
+ "application/fastinfoset": {
+ "source": "iana"
+ },
+ "application/fastsoap": {
+ "source": "iana"
+ },
+ "application/fdf": {
+ "source": "iana",
+ "extensions": ["fdf"]
+ },
+ "application/fdt+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["fdt"]
+ },
+ "application/fhir+json": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/fhir+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/fido.trusted-apps+json": {
+ "compressible": true
+ },
+ "application/fits": {
+ "source": "iana"
+ },
+ "application/flexfec": {
+ "source": "iana"
+ },
+ "application/font-sfnt": {
+ "source": "iana"
+ },
+ "application/font-tdpfr": {
+ "source": "iana",
+ "extensions": ["pfr"]
+ },
+ "application/font-woff": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/framework-attributes+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/geo+json": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["geojson"]
+ },
+ "application/geo+json-seq": {
+ "source": "iana"
+ },
+ "application/geopackage+sqlite3": {
+ "source": "iana"
+ },
+ "application/geopose+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/geoxacml+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/geoxacml+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/gltf-buffer": {
+ "source": "iana"
+ },
+ "application/gml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["gml"]
+ },
+ "application/gnap-binding-jws": {
+ "source": "iana"
+ },
+ "application/gnap-binding-jwsd": {
+ "source": "iana"
+ },
+ "application/gnap-binding-rotation-jws": {
+ "source": "iana"
+ },
+ "application/gnap-binding-rotation-jwsd": {
+ "source": "iana"
+ },
+ "application/gpx+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["gpx"]
+ },
+ "application/grib": {
+ "source": "iana"
+ },
+ "application/gxf": {
+ "source": "apache",
+ "extensions": ["gxf"]
+ },
+ "application/gzip": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["gz"]
+ },
+ "application/h224": {
+ "source": "iana"
+ },
+ "application/held+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/hjson": {
+ "extensions": ["hjson"]
+ },
+ "application/hl7v2+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/http": {
+ "source": "iana"
+ },
+ "application/hyperstudio": {
+ "source": "iana",
+ "extensions": ["stk"]
+ },
+ "application/ibe-key-request+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/ibe-pkg-reply+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/ibe-pp-data": {
+ "source": "iana"
+ },
+ "application/iges": {
+ "source": "iana"
+ },
+ "application/im-iscomposing+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/index": {
+ "source": "iana"
+ },
+ "application/index.cmd": {
+ "source": "iana"
+ },
+ "application/index.obj": {
+ "source": "iana"
+ },
+ "application/index.response": {
+ "source": "iana"
+ },
+ "application/index.vnd": {
+ "source": "iana"
+ },
+ "application/inkml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["ink","inkml"]
+ },
+ "application/iotp": {
+ "source": "iana"
+ },
+ "application/ipfix": {
+ "source": "iana",
+ "extensions": ["ipfix"]
+ },
+ "application/ipp": {
+ "source": "iana"
+ },
+ "application/isup": {
+ "source": "iana"
+ },
+ "application/its+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["its"]
+ },
+ "application/java-archive": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["jar","war","ear"]
+ },
+ "application/java-serialized-object": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["ser"]
+ },
+ "application/java-vm": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["class"]
+ },
+ "application/javascript": {
+ "source": "apache",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["js"]
+ },
+ "application/jf2feed+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/jose": {
+ "source": "iana"
+ },
+ "application/jose+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/jrd+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/jscalendar+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/jscontact+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/json": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["json","map"]
+ },
+ "application/json-patch+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/json-seq": {
+ "source": "iana"
+ },
+ "application/json5": {
+ "extensions": ["json5"]
+ },
+ "application/jsonml+json": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["jsonml"]
+ },
+ "application/jsonpath": {
+ "source": "iana"
+ },
+ "application/jwk+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/jwk-set+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/jwk-set+jwt": {
+ "source": "iana"
+ },
+ "application/jwt": {
+ "source": "iana"
+ },
+ "application/kpml-request+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/kpml-response+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/ld+json": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["jsonld"]
+ },
+ "application/lgr+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["lgr"]
+ },
+ "application/link-format": {
+ "source": "iana"
+ },
+ "application/linkset": {
+ "source": "iana"
+ },
+ "application/linkset+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/load-control+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/logout+jwt": {
+ "source": "iana"
+ },
+ "application/lost+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["lostxml"]
+ },
+ "application/lostsync+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/lpf+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/lxf": {
+ "source": "iana"
+ },
+ "application/mac-binhex40": {
+ "source": "iana",
+ "extensions": ["hqx"]
+ },
+ "application/mac-compactpro": {
+ "source": "apache",
+ "extensions": ["cpt"]
+ },
+ "application/macwriteii": {
+ "source": "iana"
+ },
+ "application/mads+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mads"]
+ },
+ "application/manifest+json": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["webmanifest"]
+ },
+ "application/marc": {
+ "source": "iana",
+ "extensions": ["mrc"]
+ },
+ "application/marcxml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mrcx"]
+ },
+ "application/mathematica": {
+ "source": "iana",
+ "extensions": ["ma","nb","mb"]
+ },
+ "application/mathml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mathml"]
+ },
+ "application/mathml-content+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mathml-presentation+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-associated-procedure-description+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-deregister+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-envelope+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-msk+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-msk-response+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-protection-description+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-reception-report+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-register+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-register-response+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-schedule+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbms-user-service-description+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mbox": {
+ "source": "iana",
+ "extensions": ["mbox"]
+ },
+ "application/media-policy-dataset+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mpf"]
+ },
+ "application/media_control+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mediaservercontrol+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mscml"]
+ },
+ "application/merge-patch+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/metalink+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["metalink"]
+ },
+ "application/metalink4+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["meta4"]
+ },
+ "application/mets+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mets"]
+ },
+ "application/mf4": {
+ "source": "iana"
+ },
+ "application/mikey": {
+ "source": "iana"
+ },
+ "application/mipc": {
+ "source": "iana"
+ },
+ "application/missing-blocks+cbor-seq": {
+ "source": "iana"
+ },
+ "application/mmt-aei+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["maei"]
+ },
+ "application/mmt-usd+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["musd"]
+ },
+ "application/mods+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mods"]
+ },
+ "application/moss-keys": {
+ "source": "iana"
+ },
+ "application/moss-signature": {
+ "source": "iana"
+ },
+ "application/mosskey-data": {
+ "source": "iana"
+ },
+ "application/mosskey-request": {
+ "source": "iana"
+ },
+ "application/mp21": {
+ "source": "iana",
+ "extensions": ["m21","mp21"]
+ },
+ "application/mp4": {
+ "source": "iana",
+ "extensions": ["mp4","mpg4","mp4s","m4p"]
+ },
+ "application/mpeg4-generic": {
+ "source": "iana"
+ },
+ "application/mpeg4-iod": {
+ "source": "iana"
+ },
+ "application/mpeg4-iod-xmt": {
+ "source": "iana"
+ },
+ "application/mrb-consumer+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/mrb-publish+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/msc-ivr+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/msc-mixer+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/msix": {
+ "compressible": false,
+ "extensions": ["msix"]
+ },
+ "application/msixbundle": {
+ "compressible": false,
+ "extensions": ["msixbundle"]
+ },
+ "application/msword": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["doc","dot"]
+ },
+ "application/mud+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/multipart-core": {
+ "source": "iana"
+ },
+ "application/mxf": {
+ "source": "iana",
+ "extensions": ["mxf"]
+ },
+ "application/n-quads": {
+ "source": "iana",
+ "extensions": ["nq"]
+ },
+ "application/n-triples": {
+ "source": "iana",
+ "extensions": ["nt"]
+ },
+ "application/nasdata": {
+ "source": "iana"
+ },
+ "application/news-checkgroups": {
+ "source": "iana",
+ "charset": "US-ASCII"
+ },
+ "application/news-groupinfo": {
+ "source": "iana",
+ "charset": "US-ASCII"
+ },
+ "application/news-transmission": {
+ "source": "iana"
+ },
+ "application/nlsml+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/node": {
+ "source": "iana",
+ "extensions": ["cjs"]
+ },
+ "application/nss": {
+ "source": "iana"
+ },
+ "application/oauth-authz-req+jwt": {
+ "source": "iana"
+ },
+ "application/oblivious-dns-message": {
+ "source": "iana"
+ },
+ "application/ocsp-request": {
+ "source": "iana"
+ },
+ "application/ocsp-response": {
+ "source": "iana"
+ },
+ "application/octet-stream": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"]
+ },
+ "application/oda": {
+ "source": "iana",
+ "extensions": ["oda"]
+ },
+ "application/odm+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/odx": {
+ "source": "iana"
+ },
+ "application/oebps-package+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["opf"]
+ },
+ "application/ogg": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["ogx"]
+ },
+ "application/ohttp-keys": {
+ "source": "iana"
+ },
+ "application/omdoc+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["omdoc"]
+ },
+ "application/onenote": {
+ "source": "apache",
+ "extensions": ["onetoc","onetoc2","onetmp","onepkg","one","onea"]
+ },
+ "application/opc-nodeset+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/oscore": {
+ "source": "iana"
+ },
+ "application/oxps": {
+ "source": "iana",
+ "extensions": ["oxps"]
+ },
+ "application/p21": {
+ "source": "iana"
+ },
+ "application/p21+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/p2p-overlay+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["relo"]
+ },
+ "application/parityfec": {
+ "source": "iana"
+ },
+ "application/passport": {
+ "source": "iana"
+ },
+ "application/patch-ops-error+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xer"]
+ },
+ "application/pdf": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["pdf"]
+ },
+ "application/pdx": {
+ "source": "iana"
+ },
+ "application/pem-certificate-chain": {
+ "source": "iana"
+ },
+ "application/pgp-encrypted": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["pgp"]
+ },
+ "application/pgp-keys": {
+ "source": "iana",
+ "extensions": ["asc"]
+ },
+ "application/pgp-signature": {
+ "source": "iana",
+ "extensions": ["sig","asc"]
+ },
+ "application/pics-rules": {
+ "source": "apache",
+ "extensions": ["prf"]
+ },
+ "application/pidf+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/pidf-diff+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/pkcs10": {
+ "source": "iana",
+ "extensions": ["p10"]
+ },
+ "application/pkcs12": {
+ "source": "iana"
+ },
+ "application/pkcs7-mime": {
+ "source": "iana",
+ "extensions": ["p7m","p7c"]
+ },
+ "application/pkcs7-signature": {
+ "source": "iana",
+ "extensions": ["p7s"]
+ },
+ "application/pkcs8": {
+ "source": "iana",
+ "extensions": ["p8"]
+ },
+ "application/pkcs8-encrypted": {
+ "source": "iana"
+ },
+ "application/pkix-attr-cert": {
+ "source": "iana",
+ "extensions": ["ac"]
+ },
+ "application/pkix-cert": {
+ "source": "iana",
+ "extensions": ["cer"]
+ },
+ "application/pkix-crl": {
+ "source": "iana",
+ "extensions": ["crl"]
+ },
+ "application/pkix-pkipath": {
+ "source": "iana",
+ "extensions": ["pkipath"]
+ },
+ "application/pkixcmp": {
+ "source": "iana",
+ "extensions": ["pki"]
+ },
+ "application/pls+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["pls"]
+ },
+ "application/poc-settings+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/postscript": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["ai","eps","ps"]
+ },
+ "application/ppsp-tracker+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/private-token-issuer-directory": {
+ "source": "iana"
+ },
+ "application/private-token-request": {
+ "source": "iana"
+ },
+ "application/private-token-response": {
+ "source": "iana"
+ },
+ "application/problem+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/problem+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/provenance+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["provx"]
+ },
+ "application/provided-claims+jwt": {
+ "source": "iana"
+ },
+ "application/prs.alvestrand.titrax-sheet": {
+ "source": "iana"
+ },
+ "application/prs.cww": {
+ "source": "iana",
+ "extensions": ["cww"]
+ },
+ "application/prs.cyn": {
+ "source": "iana",
+ "charset": "7-BIT"
+ },
+ "application/prs.hpub+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/prs.implied-document+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/prs.implied-executable": {
+ "source": "iana"
+ },
+ "application/prs.implied-object+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/prs.implied-object+json-seq": {
+ "source": "iana"
+ },
+ "application/prs.implied-object+yaml": {
+ "source": "iana"
+ },
+ "application/prs.implied-structure": {
+ "source": "iana"
+ },
+ "application/prs.mayfile": {
+ "source": "iana"
+ },
+ "application/prs.nprend": {
+ "source": "iana"
+ },
+ "application/prs.plucker": {
+ "source": "iana"
+ },
+ "application/prs.rdf-xml-crypt": {
+ "source": "iana"
+ },
+ "application/prs.vcfbzip2": {
+ "source": "iana"
+ },
+ "application/prs.xsf+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xsf"]
+ },
+ "application/pskc+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["pskcxml"]
+ },
+ "application/pvd+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/qsig": {
+ "source": "iana"
+ },
+ "application/raml+yaml": {
+ "compressible": true,
+ "extensions": ["raml"]
+ },
+ "application/raptorfec": {
+ "source": "iana"
+ },
+ "application/rdap+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/rdf+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rdf","owl"]
+ },
+ "application/reginfo+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rif"]
+ },
+ "application/relax-ng-compact-syntax": {
+ "source": "iana",
+ "extensions": ["rnc"]
+ },
+ "application/remote-printing": {
+ "source": "apache"
+ },
+ "application/reputon+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/resolve-response+jwt": {
+ "source": "iana"
+ },
+ "application/resource-lists+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rl"]
+ },
+ "application/resource-lists-diff+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rld"]
+ },
+ "application/rfc+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/riscos": {
+ "source": "iana"
+ },
+ "application/rlmi+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/rls-services+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rs"]
+ },
+ "application/route-apd+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rapd"]
+ },
+ "application/route-s-tsid+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["sls"]
+ },
+ "application/route-usd+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rusd"]
+ },
+ "application/rpki-checklist": {
+ "source": "iana"
+ },
+ "application/rpki-ghostbusters": {
+ "source": "iana",
+ "extensions": ["gbr"]
+ },
+ "application/rpki-manifest": {
+ "source": "iana",
+ "extensions": ["mft"]
+ },
+ "application/rpki-publication": {
+ "source": "iana"
+ },
+ "application/rpki-roa": {
+ "source": "iana",
+ "extensions": ["roa"]
+ },
+ "application/rpki-signed-tal": {
+ "source": "iana"
+ },
+ "application/rpki-updown": {
+ "source": "iana"
+ },
+ "application/rsd+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["rsd"]
+ },
+ "application/rss+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["rss"]
+ },
+ "application/rtf": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rtf"]
+ },
+ "application/rtploopback": {
+ "source": "iana"
+ },
+ "application/rtx": {
+ "source": "iana"
+ },
+ "application/samlassertion+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/samlmetadata+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/sarif+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/sarif-external-properties+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/sbe": {
+ "source": "iana"
+ },
+ "application/sbml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["sbml"]
+ },
+ "application/scaip+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/scim+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/scvp-cv-request": {
+ "source": "iana",
+ "extensions": ["scq"]
+ },
+ "application/scvp-cv-response": {
+ "source": "iana",
+ "extensions": ["scs"]
+ },
+ "application/scvp-vp-request": {
+ "source": "iana",
+ "extensions": ["spq"]
+ },
+ "application/scvp-vp-response": {
+ "source": "iana",
+ "extensions": ["spp"]
+ },
+ "application/sdp": {
+ "source": "iana",
+ "extensions": ["sdp"]
+ },
+ "application/secevent+jwt": {
+ "source": "iana"
+ },
+ "application/senml+cbor": {
+ "source": "iana"
+ },
+ "application/senml+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/senml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["senmlx"]
+ },
+ "application/senml-etch+cbor": {
+ "source": "iana"
+ },
+ "application/senml-etch+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/senml-exi": {
+ "source": "iana"
+ },
+ "application/sensml+cbor": {
+ "source": "iana"
+ },
+ "application/sensml+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/sensml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["sensmlx"]
+ },
+ "application/sensml-exi": {
+ "source": "iana"
+ },
+ "application/sep+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/sep-exi": {
+ "source": "iana"
+ },
+ "application/session-info": {
+ "source": "iana"
+ },
+ "application/set-payment": {
+ "source": "iana"
+ },
+ "application/set-payment-initiation": {
+ "source": "iana",
+ "extensions": ["setpay"]
+ },
+ "application/set-registration": {
+ "source": "iana"
+ },
+ "application/set-registration-initiation": {
+ "source": "iana",
+ "extensions": ["setreg"]
+ },
+ "application/sgml": {
+ "source": "iana"
+ },
+ "application/sgml-open-catalog": {
+ "source": "iana"
+ },
+ "application/shf+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["shf"]
+ },
+ "application/sieve": {
+ "source": "iana",
+ "extensions": ["siv","sieve"]
+ },
+ "application/simple-filter+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/simple-message-summary": {
+ "source": "iana"
+ },
+ "application/simplesymbolcontainer": {
+ "source": "iana"
+ },
+ "application/sipc": {
+ "source": "iana"
+ },
+ "application/slate": {
+ "source": "iana"
+ },
+ "application/smil": {
+ "source": "apache"
+ },
+ "application/smil+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["smi","smil"]
+ },
+ "application/smpte336m": {
+ "source": "iana"
+ },
+ "application/soap+fastinfoset": {
+ "source": "iana"
+ },
+ "application/soap+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/sparql-query": {
+ "source": "iana",
+ "extensions": ["rq"]
+ },
+ "application/sparql-results+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["srx"]
+ },
+ "application/spdx+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/spirits-event+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/sql": {
+ "source": "iana",
+ "extensions": ["sql"]
+ },
+ "application/srgs": {
+ "source": "iana",
+ "extensions": ["gram"]
+ },
+ "application/srgs+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["grxml"]
+ },
+ "application/sru+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["sru"]
+ },
+ "application/ssdl+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["ssdl"]
+ },
+ "application/sslkeylogfile": {
+ "source": "iana"
+ },
+ "application/ssml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["ssml"]
+ },
+ "application/st2110-41": {
+ "source": "iana"
+ },
+ "application/stix+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/stratum": {
+ "source": "iana"
+ },
+ "application/swid+cbor": {
+ "source": "iana"
+ },
+ "application/swid+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["swidtag"]
+ },
+ "application/tamp-apex-update": {
+ "source": "iana"
+ },
+ "application/tamp-apex-update-confirm": {
+ "source": "iana"
+ },
+ "application/tamp-community-update": {
+ "source": "iana"
+ },
+ "application/tamp-community-update-confirm": {
+ "source": "iana"
+ },
+ "application/tamp-error": {
+ "source": "iana"
+ },
+ "application/tamp-sequence-adjust": {
+ "source": "iana"
+ },
+ "application/tamp-sequence-adjust-confirm": {
+ "source": "iana"
+ },
+ "application/tamp-status-query": {
+ "source": "iana"
+ },
+ "application/tamp-status-response": {
+ "source": "iana"
+ },
+ "application/tamp-update": {
+ "source": "iana"
+ },
+ "application/tamp-update-confirm": {
+ "source": "iana"
+ },
+ "application/tar": {
+ "compressible": true
+ },
+ "application/taxii+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/td+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/tei+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["tei","teicorpus"]
+ },
+ "application/tetra_isi": {
+ "source": "iana"
+ },
+ "application/thraud+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["tfi"]
+ },
+ "application/timestamp-query": {
+ "source": "iana"
+ },
+ "application/timestamp-reply": {
+ "source": "iana"
+ },
+ "application/timestamped-data": {
+ "source": "iana",
+ "extensions": ["tsd"]
+ },
+ "application/tlsrpt+gzip": {
+ "source": "iana"
+ },
+ "application/tlsrpt+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/tm+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/tnauthlist": {
+ "source": "iana"
+ },
+ "application/toc+cbor": {
+ "source": "iana"
+ },
+ "application/token-introspection+jwt": {
+ "source": "iana"
+ },
+ "application/toml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["toml"]
+ },
+ "application/trickle-ice-sdpfrag": {
+ "source": "iana"
+ },
+ "application/trig": {
+ "source": "iana",
+ "extensions": ["trig"]
+ },
+ "application/trust-chain+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/trust-mark+jwt": {
+ "source": "iana"
+ },
+ "application/trust-mark-delegation+jwt": {
+ "source": "iana"
+ },
+ "application/ttml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["ttml"]
+ },
+ "application/tve-trigger": {
+ "source": "iana"
+ },
+ "application/tzif": {
+ "source": "iana"
+ },
+ "application/tzif-leap": {
+ "source": "iana"
+ },
+ "application/ubjson": {
+ "compressible": false,
+ "extensions": ["ubj"]
+ },
+ "application/uccs+cbor": {
+ "source": "iana"
+ },
+ "application/ujcs+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/ulpfec": {
+ "source": "iana"
+ },
+ "application/urc-grpsheet+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/urc-ressheet+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rsheet"]
+ },
+ "application/urc-targetdesc+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["td"]
+ },
+ "application/urc-uisocketdesc+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vc": {
+ "source": "iana"
+ },
+ "application/vc+cose": {
+ "source": "iana"
+ },
+ "application/vc+jwt": {
+ "source": "iana"
+ },
+ "application/vcard+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vcard+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vemmi": {
+ "source": "iana"
+ },
+ "application/vividence.scriptfile": {
+ "source": "apache"
+ },
+ "application/vnd.1000minds.decision-model+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["1km"]
+ },
+ "application/vnd.1ob": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp-prose+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp-prose-pc3a+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp-prose-pc3ach+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp-prose-pc3ch+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp-prose-pc8+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp-v2x-local-service-information": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.5gnas": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.5gsa2x": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.5gsa2x-local-service-information": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.5gsv2x": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.5gsv2x-local-service-information": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.access-transfer-events+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.bsf+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.crs+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.current-location-discovery+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.gmop+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.gtpc": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.interworking-data": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.lpp": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.mc-signalling-ear": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.mcdata-affiliation-command+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcdata-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcdata-msgstore-ctrl-request+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcdata-payload": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.mcdata-regroup+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcdata-service-config+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcdata-signalling": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.mcdata-ue-config+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcdata-user-profile+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-affiliation-command+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-floor-request+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-location-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-mbms-usage-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-regroup+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-service-config+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-signed+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-ue-config+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-ue-init-config+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcptt-user-profile+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcvideo-affiliation-command+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcvideo-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcvideo-location-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcvideo-mbms-usage-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcvideo-regroup+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcvideo-service-config+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcvideo-transmission-request+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcvideo-ue-config+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mcvideo-user-profile+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.mid-call+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.ngap": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.pfcp": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.pic-bw-large": {
+ "source": "iana",
+ "extensions": ["plb"]
+ },
+ "application/vnd.3gpp.pic-bw-small": {
+ "source": "iana",
+ "extensions": ["psb"]
+ },
+ "application/vnd.3gpp.pic-bw-var": {
+ "source": "iana",
+ "extensions": ["pvb"]
+ },
+ "application/vnd.3gpp.pinapp-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.s1ap": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.seal-group-doc+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.seal-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.seal-location-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.seal-mbms-usage-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.seal-network-qos-management-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.seal-ue-config-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.seal-unicast-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.seal-user-profile-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.sms": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.sms+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.srvcc-ext+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.srvcc-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.state-and-event-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.ussd+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp.v2x": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp.vae-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp2.bcmcsinfo+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.3gpp2.sms": {
+ "source": "iana"
+ },
+ "application/vnd.3gpp2.tcap": {
+ "source": "iana",
+ "extensions": ["tcap"]
+ },
+ "application/vnd.3lightssoftware.imagescal": {
+ "source": "iana"
+ },
+ "application/vnd.3m.post-it-notes": {
+ "source": "iana",
+ "extensions": ["pwn"]
+ },
+ "application/vnd.accpac.simply.aso": {
+ "source": "iana",
+ "extensions": ["aso"]
+ },
+ "application/vnd.accpac.simply.imp": {
+ "source": "iana",
+ "extensions": ["imp"]
+ },
+ "application/vnd.acm.addressxfer+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.acm.chatbot+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.acucobol": {
+ "source": "iana",
+ "extensions": ["acu"]
+ },
+ "application/vnd.acucorp": {
+ "source": "iana",
+ "extensions": ["atc","acutc"]
+ },
+ "application/vnd.adobe.air-application-installer-package+zip": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["air"]
+ },
+ "application/vnd.adobe.flash.movie": {
+ "source": "iana"
+ },
+ "application/vnd.adobe.formscentral.fcdt": {
+ "source": "iana",
+ "extensions": ["fcdt"]
+ },
+ "application/vnd.adobe.fxp": {
+ "source": "iana",
+ "extensions": ["fxp","fxpl"]
+ },
+ "application/vnd.adobe.partial-upload": {
+ "source": "iana"
+ },
+ "application/vnd.adobe.xdp+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xdp"]
+ },
+ "application/vnd.adobe.xfdf": {
+ "source": "apache",
+ "extensions": ["xfdf"]
+ },
+ "application/vnd.aether.imp": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.afplinedata": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.afplinedata-pagedef": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.cmoca-cmresource": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.foca-charset": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.foca-codedfont": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.foca-codepage": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.modca": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.modca-cmtable": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.modca-formdef": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.modca-mediummap": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.modca-objectcontainer": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.modca-overlay": {
+ "source": "iana"
+ },
+ "application/vnd.afpc.modca-pagesegment": {
+ "source": "iana"
+ },
+ "application/vnd.age": {
+ "source": "iana",
+ "extensions": ["age"]
+ },
+ "application/vnd.ah-barcode": {
+ "source": "apache"
+ },
+ "application/vnd.ahead.space": {
+ "source": "iana",
+ "extensions": ["ahead"]
+ },
+ "application/vnd.airzip.filesecure.azf": {
+ "source": "iana",
+ "extensions": ["azf"]
+ },
+ "application/vnd.airzip.filesecure.azs": {
+ "source": "iana",
+ "extensions": ["azs"]
+ },
+ "application/vnd.amadeus+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.amazon.ebook": {
+ "source": "apache",
+ "extensions": ["azw"]
+ },
+ "application/vnd.amazon.mobi8-ebook": {
+ "source": "iana"
+ },
+ "application/vnd.americandynamics.acc": {
+ "source": "iana",
+ "extensions": ["acc"]
+ },
+ "application/vnd.amiga.ami": {
+ "source": "iana",
+ "extensions": ["ami"]
+ },
+ "application/vnd.amundsen.maze+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.android.ota": {
+ "source": "iana"
+ },
+ "application/vnd.android.package-archive": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["apk"]
+ },
+ "application/vnd.anki": {
+ "source": "iana"
+ },
+ "application/vnd.anser-web-certificate-issue-initiation": {
+ "source": "iana",
+ "extensions": ["cii"]
+ },
+ "application/vnd.anser-web-funds-transfer-initiation": {
+ "source": "apache",
+ "extensions": ["fti"]
+ },
+ "application/vnd.antix.game-component": {
+ "source": "iana",
+ "extensions": ["atx"]
+ },
+ "application/vnd.apache.arrow.file": {
+ "source": "iana"
+ },
+ "application/vnd.apache.arrow.stream": {
+ "source": "iana"
+ },
+ "application/vnd.apache.parquet": {
+ "source": "iana"
+ },
+ "application/vnd.apache.thrift.binary": {
+ "source": "iana"
+ },
+ "application/vnd.apache.thrift.compact": {
+ "source": "iana"
+ },
+ "application/vnd.apache.thrift.json": {
+ "source": "iana"
+ },
+ "application/vnd.apexlang": {
+ "source": "iana"
+ },
+ "application/vnd.api+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.aplextor.warrp+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.apothekende.reservation+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.apple.installer+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mpkg"]
+ },
+ "application/vnd.apple.keynote": {
+ "source": "iana",
+ "extensions": ["key"]
+ },
+ "application/vnd.apple.mpegurl": {
+ "source": "iana",
+ "extensions": ["m3u8"]
+ },
+ "application/vnd.apple.numbers": {
+ "source": "iana",
+ "extensions": ["numbers"]
+ },
+ "application/vnd.apple.pages": {
+ "source": "iana",
+ "extensions": ["pages"]
+ },
+ "application/vnd.apple.pkpass": {
+ "compressible": false,
+ "extensions": ["pkpass"]
+ },
+ "application/vnd.arastra.swi": {
+ "source": "apache"
+ },
+ "application/vnd.aristanetworks.swi": {
+ "source": "iana",
+ "extensions": ["swi"]
+ },
+ "application/vnd.artisan+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.artsquare": {
+ "source": "iana"
+ },
+ "application/vnd.astraea-software.iota": {
+ "source": "iana",
+ "extensions": ["iota"]
+ },
+ "application/vnd.audiograph": {
+ "source": "iana",
+ "extensions": ["aep"]
+ },
+ "application/vnd.autodesk.fbx": {
+ "extensions": ["fbx"]
+ },
+ "application/vnd.autopackage": {
+ "source": "iana"
+ },
+ "application/vnd.avalon+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.avistar+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.balsamiq.bmml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["bmml"]
+ },
+ "application/vnd.balsamiq.bmpr": {
+ "source": "iana"
+ },
+ "application/vnd.banana-accounting": {
+ "source": "iana"
+ },
+ "application/vnd.bbf.usp.error": {
+ "source": "iana"
+ },
+ "application/vnd.bbf.usp.msg": {
+ "source": "iana"
+ },
+ "application/vnd.bbf.usp.msg+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.bekitzur-stech+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.belightsoft.lhzd+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.belightsoft.lhzl+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.bint.med-content": {
+ "source": "iana"
+ },
+ "application/vnd.biopax.rdf+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.blink-idb-value-wrapper": {
+ "source": "iana"
+ },
+ "application/vnd.blueice.multipass": {
+ "source": "iana",
+ "extensions": ["mpm"]
+ },
+ "application/vnd.bluetooth.ep.oob": {
+ "source": "iana"
+ },
+ "application/vnd.bluetooth.le.oob": {
+ "source": "iana"
+ },
+ "application/vnd.bmi": {
+ "source": "iana",
+ "extensions": ["bmi"]
+ },
+ "application/vnd.bpf": {
+ "source": "iana"
+ },
+ "application/vnd.bpf3": {
+ "source": "iana"
+ },
+ "application/vnd.businessobjects": {
+ "source": "iana",
+ "extensions": ["rep"]
+ },
+ "application/vnd.byu.uapi+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.bzip3": {
+ "source": "iana"
+ },
+ "application/vnd.c3voc.schedule+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.cab-jscript": {
+ "source": "iana"
+ },
+ "application/vnd.canon-cpdl": {
+ "source": "iana"
+ },
+ "application/vnd.canon-lips": {
+ "source": "iana"
+ },
+ "application/vnd.capasystems-pg+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.cendio.thinlinc.clientconf": {
+ "source": "iana"
+ },
+ "application/vnd.century-systems.tcp_stream": {
+ "source": "iana"
+ },
+ "application/vnd.chemdraw+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["cdxml"]
+ },
+ "application/vnd.chess-pgn": {
+ "source": "iana"
+ },
+ "application/vnd.chipnuts.karaoke-mmd": {
+ "source": "iana",
+ "extensions": ["mmd"]
+ },
+ "application/vnd.ciedi": {
+ "source": "iana"
+ },
+ "application/vnd.cinderella": {
+ "source": "iana",
+ "extensions": ["cdy"]
+ },
+ "application/vnd.cirpack.isdn-ext": {
+ "source": "iana"
+ },
+ "application/vnd.citationstyles.style+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["csl"]
+ },
+ "application/vnd.claymore": {
+ "source": "iana",
+ "extensions": ["cla"]
+ },
+ "application/vnd.cloanto.rp9": {
+ "source": "iana",
+ "extensions": ["rp9"]
+ },
+ "application/vnd.clonk.c4group": {
+ "source": "iana",
+ "extensions": ["c4g","c4d","c4f","c4p","c4u"]
+ },
+ "application/vnd.cluetrust.cartomobile-config": {
+ "source": "iana",
+ "extensions": ["c11amc"]
+ },
+ "application/vnd.cluetrust.cartomobile-config-pkg": {
+ "source": "iana",
+ "extensions": ["c11amz"]
+ },
+ "application/vnd.cncf.helm.chart.content.v1.tar+gzip": {
+ "source": "iana"
+ },
+ "application/vnd.cncf.helm.chart.provenance.v1.prov": {
+ "source": "iana"
+ },
+ "application/vnd.cncf.helm.config.v1+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.coffeescript": {
+ "source": "iana"
+ },
+ "application/vnd.collabio.xodocuments.document": {
+ "source": "iana"
+ },
+ "application/vnd.collabio.xodocuments.document-template": {
+ "source": "iana"
+ },
+ "application/vnd.collabio.xodocuments.presentation": {
+ "source": "iana"
+ },
+ "application/vnd.collabio.xodocuments.presentation-template": {
+ "source": "iana"
+ },
+ "application/vnd.collabio.xodocuments.spreadsheet": {
+ "source": "iana"
+ },
+ "application/vnd.collabio.xodocuments.spreadsheet-template": {
+ "source": "iana"
+ },
+ "application/vnd.collection+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.collection.doc+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.collection.next+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.comicbook+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.comicbook-rar": {
+ "source": "iana"
+ },
+ "application/vnd.commerce-battelle": {
+ "source": "iana"
+ },
+ "application/vnd.commonspace": {
+ "source": "iana",
+ "extensions": ["csp"]
+ },
+ "application/vnd.contact.cmsg": {
+ "source": "iana",
+ "extensions": ["cdbcmsg"]
+ },
+ "application/vnd.coreos.ignition+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.cosmocaller": {
+ "source": "iana",
+ "extensions": ["cmc"]
+ },
+ "application/vnd.crick.clicker": {
+ "source": "iana",
+ "extensions": ["clkx"]
+ },
+ "application/vnd.crick.clicker.keyboard": {
+ "source": "iana",
+ "extensions": ["clkk"]
+ },
+ "application/vnd.crick.clicker.palette": {
+ "source": "iana",
+ "extensions": ["clkp"]
+ },
+ "application/vnd.crick.clicker.template": {
+ "source": "iana",
+ "extensions": ["clkt"]
+ },
+ "application/vnd.crick.clicker.wordbank": {
+ "source": "iana",
+ "extensions": ["clkw"]
+ },
+ "application/vnd.criticaltools.wbs+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["wbs"]
+ },
+ "application/vnd.cryptii.pipe+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.crypto-shade-file": {
+ "source": "iana"
+ },
+ "application/vnd.cryptomator.encrypted": {
+ "source": "iana"
+ },
+ "application/vnd.cryptomator.vault": {
+ "source": "iana"
+ },
+ "application/vnd.ctc-posml": {
+ "source": "iana",
+ "extensions": ["pml"]
+ },
+ "application/vnd.ctct.ws+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.cups-pdf": {
+ "source": "iana"
+ },
+ "application/vnd.cups-postscript": {
+ "source": "iana"
+ },
+ "application/vnd.cups-ppd": {
+ "source": "iana",
+ "extensions": ["ppd"]
+ },
+ "application/vnd.cups-raster": {
+ "source": "iana"
+ },
+ "application/vnd.cups-raw": {
+ "source": "iana"
+ },
+ "application/vnd.curl": {
+ "source": "iana"
+ },
+ "application/vnd.curl.car": {
+ "source": "apache",
+ "extensions": ["car"]
+ },
+ "application/vnd.curl.pcurl": {
+ "source": "apache",
+ "extensions": ["pcurl"]
+ },
+ "application/vnd.cyan.dean.root+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.cybank": {
+ "source": "iana"
+ },
+ "application/vnd.cyclonedx+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.cyclonedx+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.d2l.coursepackage1p0+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.d3m-dataset": {
+ "source": "iana"
+ },
+ "application/vnd.d3m-problem": {
+ "source": "iana"
+ },
+ "application/vnd.dart": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["dart"]
+ },
+ "application/vnd.data-vision.rdz": {
+ "source": "iana",
+ "extensions": ["rdz"]
+ },
+ "application/vnd.datalog": {
+ "source": "iana"
+ },
+ "application/vnd.datapackage+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dataresource+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dbf": {
+ "source": "iana",
+ "extensions": ["dbf"]
+ },
+ "application/vnd.dcmp+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["dcmp"]
+ },
+ "application/vnd.debian.binary-package": {
+ "source": "iana"
+ },
+ "application/vnd.dece.data": {
+ "source": "iana",
+ "extensions": ["uvf","uvvf","uvd","uvvd"]
+ },
+ "application/vnd.dece.ttml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["uvt","uvvt"]
+ },
+ "application/vnd.dece.unspecified": {
+ "source": "iana",
+ "extensions": ["uvx","uvvx"]
+ },
+ "application/vnd.dece.zip": {
+ "source": "iana",
+ "extensions": ["uvz","uvvz"]
+ },
+ "application/vnd.denovo.fcselayout-link": {
+ "source": "iana",
+ "extensions": ["fe_launch"]
+ },
+ "application/vnd.desmume.movie": {
+ "source": "iana"
+ },
+ "application/vnd.dir-bi.plate-dl-nosuffix": {
+ "source": "iana"
+ },
+ "application/vnd.dm.delegation+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dna": {
+ "source": "iana",
+ "extensions": ["dna"]
+ },
+ "application/vnd.document+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dolby.mlp": {
+ "source": "apache",
+ "extensions": ["mlp"]
+ },
+ "application/vnd.dolby.mobile.1": {
+ "source": "iana"
+ },
+ "application/vnd.dolby.mobile.2": {
+ "source": "iana"
+ },
+ "application/vnd.doremir.scorecloud-binary-document": {
+ "source": "iana"
+ },
+ "application/vnd.dpgraph": {
+ "source": "iana",
+ "extensions": ["dpg"]
+ },
+ "application/vnd.dreamfactory": {
+ "source": "iana",
+ "extensions": ["dfac"]
+ },
+ "application/vnd.drive+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ds-keypoint": {
+ "source": "apache",
+ "extensions": ["kpxx"]
+ },
+ "application/vnd.dtg.local": {
+ "source": "iana"
+ },
+ "application/vnd.dtg.local.flash": {
+ "source": "iana"
+ },
+ "application/vnd.dtg.local.html": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ait": {
+ "source": "iana",
+ "extensions": ["ait"]
+ },
+ "application/vnd.dvb.dvbisl+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dvb.dvbj": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.esgcontainer": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ipdcdftnotifaccess": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ipdcesgaccess": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ipdcesgaccess2": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ipdcesgpdd": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.ipdcroaming": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.iptv.alfec-base": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.iptv.alfec-enhancement": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.notif-aggregate-root+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dvb.notif-container+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dvb.notif-generic+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dvb.notif-ia-msglist+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dvb.notif-ia-registration-request+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dvb.notif-ia-registration-response+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dvb.notif-init+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.dvb.pfr": {
+ "source": "iana"
+ },
+ "application/vnd.dvb.service": {
+ "source": "iana",
+ "extensions": ["svc"]
+ },
+ "application/vnd.dxr": {
+ "source": "iana"
+ },
+ "application/vnd.dynageo": {
+ "source": "iana",
+ "extensions": ["geo"]
+ },
+ "application/vnd.dzr": {
+ "source": "iana"
+ },
+ "application/vnd.easykaraoke.cdgdownload": {
+ "source": "iana"
+ },
+ "application/vnd.ecdis-update": {
+ "source": "iana"
+ },
+ "application/vnd.ecip.rlp": {
+ "source": "iana"
+ },
+ "application/vnd.eclipse.ditto+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ecowin.chart": {
+ "source": "iana",
+ "extensions": ["mag"]
+ },
+ "application/vnd.ecowin.filerequest": {
+ "source": "iana"
+ },
+ "application/vnd.ecowin.fileupdate": {
+ "source": "iana"
+ },
+ "application/vnd.ecowin.series": {
+ "source": "iana"
+ },
+ "application/vnd.ecowin.seriesrequest": {
+ "source": "iana"
+ },
+ "application/vnd.ecowin.seriesupdate": {
+ "source": "iana"
+ },
+ "application/vnd.efi.img": {
+ "source": "iana"
+ },
+ "application/vnd.efi.iso": {
+ "source": "iana"
+ },
+ "application/vnd.eln+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.emclient.accessrequest+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.enliven": {
+ "source": "iana",
+ "extensions": ["nml"]
+ },
+ "application/vnd.enphase.envoy": {
+ "source": "iana"
+ },
+ "application/vnd.eprints.data+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.epson.esf": {
+ "source": "iana",
+ "extensions": ["esf"]
+ },
+ "application/vnd.epson.msf": {
+ "source": "iana",
+ "extensions": ["msf"]
+ },
+ "application/vnd.epson.quickanime": {
+ "source": "iana",
+ "extensions": ["qam"]
+ },
+ "application/vnd.epson.salt": {
+ "source": "iana",
+ "extensions": ["slt"]
+ },
+ "application/vnd.epson.ssf": {
+ "source": "iana",
+ "extensions": ["ssf"]
+ },
+ "application/vnd.ericsson.quickcall": {
+ "source": "iana"
+ },
+ "application/vnd.erofs": {
+ "source": "iana"
+ },
+ "application/vnd.espass-espass+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.eszigno3+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["es3","et3"]
+ },
+ "application/vnd.etsi.aoc+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.asic-e+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.etsi.asic-s+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.etsi.cug+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.iptvcommand+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.iptvdiscovery+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.iptvprofile+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.iptvsad-bc+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.iptvsad-cod+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.iptvsad-npvr+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.iptvservice+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.iptvsync+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.iptvueprofile+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.mcid+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.mheg5": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.overload-control-policy-dataset+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.pstn+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.sci+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.simservs+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.timestamp-token": {
+ "source": "iana"
+ },
+ "application/vnd.etsi.tsl+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.etsi.tsl.der": {
+ "source": "iana"
+ },
+ "application/vnd.eu.kasparian.car+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.eudora.data": {
+ "source": "iana"
+ },
+ "application/vnd.evolv.ecig.profile": {
+ "source": "iana"
+ },
+ "application/vnd.evolv.ecig.settings": {
+ "source": "iana"
+ },
+ "application/vnd.evolv.ecig.theme": {
+ "source": "iana"
+ },
+ "application/vnd.exstream-empower+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.exstream-package": {
+ "source": "iana"
+ },
+ "application/vnd.ezpix-album": {
+ "source": "iana",
+ "extensions": ["ez2"]
+ },
+ "application/vnd.ezpix-package": {
+ "source": "iana",
+ "extensions": ["ez3"]
+ },
+ "application/vnd.f-secure.mobile": {
+ "source": "iana"
+ },
+ "application/vnd.familysearch.gedcom+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.fastcopy-disk-image": {
+ "source": "iana"
+ },
+ "application/vnd.fdf": {
+ "source": "apache",
+ "extensions": ["fdf"]
+ },
+ "application/vnd.fdsn.mseed": {
+ "source": "iana",
+ "extensions": ["mseed"]
+ },
+ "application/vnd.fdsn.seed": {
+ "source": "iana",
+ "extensions": ["seed","dataless"]
+ },
+ "application/vnd.fdsn.stationxml+xml": {
+ "source": "iana",
+ "charset": "XML-BASED",
+ "compressible": true
+ },
+ "application/vnd.ffsns": {
+ "source": "iana"
+ },
+ "application/vnd.ficlab.flb+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.filmit.zfc": {
+ "source": "iana"
+ },
+ "application/vnd.fints": {
+ "source": "iana"
+ },
+ "application/vnd.firemonkeys.cloudcell": {
+ "source": "iana"
+ },
+ "application/vnd.flographit": {
+ "source": "iana",
+ "extensions": ["gph"]
+ },
+ "application/vnd.fluxtime.clip": {
+ "source": "iana",
+ "extensions": ["ftc"]
+ },
+ "application/vnd.font-fontforge-sfd": {
+ "source": "iana"
+ },
+ "application/vnd.framemaker": {
+ "source": "iana",
+ "extensions": ["fm","frame","maker","book"]
+ },
+ "application/vnd.freelog.comic": {
+ "source": "iana"
+ },
+ "application/vnd.frogans.fnc": {
+ "source": "apache",
+ "extensions": ["fnc"]
+ },
+ "application/vnd.frogans.ltf": {
+ "source": "apache",
+ "extensions": ["ltf"]
+ },
+ "application/vnd.fsc.weblaunch": {
+ "source": "iana",
+ "extensions": ["fsc"]
+ },
+ "application/vnd.fujifilm.fb.docuworks": {
+ "source": "iana"
+ },
+ "application/vnd.fujifilm.fb.docuworks.binder": {
+ "source": "iana"
+ },
+ "application/vnd.fujifilm.fb.docuworks.container": {
+ "source": "iana"
+ },
+ "application/vnd.fujifilm.fb.jfi+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.fujitsu.oasys": {
+ "source": "iana",
+ "extensions": ["oas"]
+ },
+ "application/vnd.fujitsu.oasys2": {
+ "source": "iana",
+ "extensions": ["oa2"]
+ },
+ "application/vnd.fujitsu.oasys3": {
+ "source": "iana",
+ "extensions": ["oa3"]
+ },
+ "application/vnd.fujitsu.oasysgp": {
+ "source": "iana",
+ "extensions": ["fg5"]
+ },
+ "application/vnd.fujitsu.oasysprs": {
+ "source": "iana",
+ "extensions": ["bh2"]
+ },
+ "application/vnd.fujixerox.art-ex": {
+ "source": "iana"
+ },
+ "application/vnd.fujixerox.art4": {
+ "source": "iana"
+ },
+ "application/vnd.fujixerox.ddd": {
+ "source": "iana",
+ "extensions": ["ddd"]
+ },
+ "application/vnd.fujixerox.docuworks": {
+ "source": "iana",
+ "extensions": ["xdw"]
+ },
+ "application/vnd.fujixerox.docuworks.binder": {
+ "source": "iana",
+ "extensions": ["xbd"]
+ },
+ "application/vnd.fujixerox.docuworks.container": {
+ "source": "iana"
+ },
+ "application/vnd.fujixerox.hbpl": {
+ "source": "iana"
+ },
+ "application/vnd.fut-misnet": {
+ "source": "iana"
+ },
+ "application/vnd.futoin+cbor": {
+ "source": "iana"
+ },
+ "application/vnd.futoin+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.fuzzysheet": {
+ "source": "iana",
+ "extensions": ["fzs"]
+ },
+ "application/vnd.ga4gh.passport+jwt": {
+ "source": "iana"
+ },
+ "application/vnd.genomatix.tuxedo": {
+ "source": "iana",
+ "extensions": ["txd"]
+ },
+ "application/vnd.genozip": {
+ "source": "iana"
+ },
+ "application/vnd.gentics.grd+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.gentoo.catmetadata+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.gentoo.ebuild": {
+ "source": "iana"
+ },
+ "application/vnd.gentoo.eclass": {
+ "source": "iana"
+ },
+ "application/vnd.gentoo.gpkg": {
+ "source": "iana"
+ },
+ "application/vnd.gentoo.manifest": {
+ "source": "iana"
+ },
+ "application/vnd.gentoo.pkgmetadata+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.gentoo.xpak": {
+ "source": "iana"
+ },
+ "application/vnd.geo+json": {
+ "source": "apache",
+ "compressible": true
+ },
+ "application/vnd.geocube+xml": {
+ "source": "apache",
+ "compressible": true
+ },
+ "application/vnd.geogebra.file": {
+ "source": "iana",
+ "extensions": ["ggb"]
+ },
+ "application/vnd.geogebra.pinboard": {
+ "source": "iana"
+ },
+ "application/vnd.geogebra.slides": {
+ "source": "iana",
+ "extensions": ["ggs"]
+ },
+ "application/vnd.geogebra.tool": {
+ "source": "iana",
+ "extensions": ["ggt"]
+ },
+ "application/vnd.geometry-explorer": {
+ "source": "iana",
+ "extensions": ["gex","gre"]
+ },
+ "application/vnd.geonext": {
+ "source": "iana",
+ "extensions": ["gxt"]
+ },
+ "application/vnd.geoplan": {
+ "source": "iana",
+ "extensions": ["g2w"]
+ },
+ "application/vnd.geospace": {
+ "source": "iana",
+ "extensions": ["g3w"]
+ },
+ "application/vnd.gerber": {
+ "source": "iana"
+ },
+ "application/vnd.globalplatform.card-content-mgt": {
+ "source": "iana"
+ },
+ "application/vnd.globalplatform.card-content-mgt-response": {
+ "source": "iana"
+ },
+ "application/vnd.gmx": {
+ "source": "iana",
+ "extensions": ["gmx"]
+ },
+ "application/vnd.gnu.taler.exchange+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.gnu.taler.merchant+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.google-apps.audio": {},
+ "application/vnd.google-apps.document": {
+ "compressible": false,
+ "extensions": ["gdoc"]
+ },
+ "application/vnd.google-apps.drawing": {
+ "compressible": false,
+ "extensions": ["gdraw"]
+ },
+ "application/vnd.google-apps.drive-sdk": {
+ "compressible": false
+ },
+ "application/vnd.google-apps.file": {},
+ "application/vnd.google-apps.folder": {
+ "compressible": false
+ },
+ "application/vnd.google-apps.form": {
+ "compressible": false,
+ "extensions": ["gform"]
+ },
+ "application/vnd.google-apps.fusiontable": {},
+ "application/vnd.google-apps.jam": {
+ "compressible": false,
+ "extensions": ["gjam"]
+ },
+ "application/vnd.google-apps.mail-layout": {},
+ "application/vnd.google-apps.map": {
+ "compressible": false,
+ "extensions": ["gmap"]
+ },
+ "application/vnd.google-apps.photo": {},
+ "application/vnd.google-apps.presentation": {
+ "compressible": false,
+ "extensions": ["gslides"]
+ },
+ "application/vnd.google-apps.script": {
+ "compressible": false,
+ "extensions": ["gscript"]
+ },
+ "application/vnd.google-apps.shortcut": {},
+ "application/vnd.google-apps.site": {
+ "compressible": false,
+ "extensions": ["gsite"]
+ },
+ "application/vnd.google-apps.spreadsheet": {
+ "compressible": false,
+ "extensions": ["gsheet"]
+ },
+ "application/vnd.google-apps.unknown": {},
+ "application/vnd.google-apps.video": {},
+ "application/vnd.google-earth.kml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["kml"]
+ },
+ "application/vnd.google-earth.kmz": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["kmz"]
+ },
+ "application/vnd.gov.sk.e-form+xml": {
+ "source": "apache",
+ "compressible": true
+ },
+ "application/vnd.gov.sk.e-form+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.gov.sk.xmldatacontainer+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xdcf"]
+ },
+ "application/vnd.gpxsee.map+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.grafeq": {
+ "source": "iana",
+ "extensions": ["gqf","gqs"]
+ },
+ "application/vnd.gridmp": {
+ "source": "iana"
+ },
+ "application/vnd.groove-account": {
+ "source": "iana",
+ "extensions": ["gac"]
+ },
+ "application/vnd.groove-help": {
+ "source": "iana",
+ "extensions": ["ghf"]
+ },
+ "application/vnd.groove-identity-message": {
+ "source": "iana",
+ "extensions": ["gim"]
+ },
+ "application/vnd.groove-injector": {
+ "source": "iana",
+ "extensions": ["grv"]
+ },
+ "application/vnd.groove-tool-message": {
+ "source": "iana",
+ "extensions": ["gtm"]
+ },
+ "application/vnd.groove-tool-template": {
+ "source": "iana",
+ "extensions": ["tpl"]
+ },
+ "application/vnd.groove-vcard": {
+ "source": "iana",
+ "extensions": ["vcg"]
+ },
+ "application/vnd.hal+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.hal+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["hal"]
+ },
+ "application/vnd.handheld-entertainment+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["zmm"]
+ },
+ "application/vnd.hbci": {
+ "source": "iana",
+ "extensions": ["hbci"]
+ },
+ "application/vnd.hc+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.hcl-bireports": {
+ "source": "iana"
+ },
+ "application/vnd.hdt": {
+ "source": "iana"
+ },
+ "application/vnd.heroku+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.hhe.lesson-player": {
+ "source": "iana",
+ "extensions": ["les"]
+ },
+ "application/vnd.hp-hpgl": {
+ "source": "iana",
+ "extensions": ["hpgl"]
+ },
+ "application/vnd.hp-hpid": {
+ "source": "iana",
+ "extensions": ["hpid"]
+ },
+ "application/vnd.hp-hps": {
+ "source": "iana",
+ "extensions": ["hps"]
+ },
+ "application/vnd.hp-jlyt": {
+ "source": "iana",
+ "extensions": ["jlt"]
+ },
+ "application/vnd.hp-pcl": {
+ "source": "iana",
+ "extensions": ["pcl"]
+ },
+ "application/vnd.hp-pclxl": {
+ "source": "iana",
+ "extensions": ["pclxl"]
+ },
+ "application/vnd.hsl": {
+ "source": "iana"
+ },
+ "application/vnd.httphone": {
+ "source": "iana"
+ },
+ "application/vnd.hydrostatix.sof-data": {
+ "source": "iana",
+ "extensions": ["sfd-hdstx"]
+ },
+ "application/vnd.hyper+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.hyper-item+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.hyperdrive+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.hzn-3d-crossword": {
+ "source": "iana"
+ },
+ "application/vnd.ibm.afplinedata": {
+ "source": "apache"
+ },
+ "application/vnd.ibm.electronic-media": {
+ "source": "iana"
+ },
+ "application/vnd.ibm.minipay": {
+ "source": "iana",
+ "extensions": ["mpy"]
+ },
+ "application/vnd.ibm.modcap": {
+ "source": "apache",
+ "extensions": ["afp","listafp","list3820"]
+ },
+ "application/vnd.ibm.rights-management": {
+ "source": "iana",
+ "extensions": ["irm"]
+ },
+ "application/vnd.ibm.secure-container": {
+ "source": "iana",
+ "extensions": ["sc"]
+ },
+ "application/vnd.iccprofile": {
+ "source": "iana",
+ "extensions": ["icc","icm"]
+ },
+ "application/vnd.ieee.1905": {
+ "source": "iana"
+ },
+ "application/vnd.igloader": {
+ "source": "iana",
+ "extensions": ["igl"]
+ },
+ "application/vnd.imagemeter.folder+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.imagemeter.image+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.immervision-ivp": {
+ "source": "iana",
+ "extensions": ["ivp"]
+ },
+ "application/vnd.immervision-ivu": {
+ "source": "iana",
+ "extensions": ["ivu"]
+ },
+ "application/vnd.ims.imsccv1p1": {
+ "source": "iana"
+ },
+ "application/vnd.ims.imsccv1p2": {
+ "source": "iana"
+ },
+ "application/vnd.ims.imsccv1p3": {
+ "source": "iana"
+ },
+ "application/vnd.ims.lis.v2.result+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ims.lti.v2.toolconsumerprofile+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ims.lti.v2.toolproxy+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ims.lti.v2.toolproxy.id+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ims.lti.v2.toolsettings+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ims.lti.v2.toolsettings.simple+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.informedcontrol.rms+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.informix-visionary": {
+ "source": "apache"
+ },
+ "application/vnd.infotech.project": {
+ "source": "iana"
+ },
+ "application/vnd.infotech.project+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.innopath.wamp.notification": {
+ "source": "iana"
+ },
+ "application/vnd.insors.igm": {
+ "source": "iana",
+ "extensions": ["igm"]
+ },
+ "application/vnd.intercon.formnet": {
+ "source": "iana",
+ "extensions": ["xpw","xpx"]
+ },
+ "application/vnd.intergeo": {
+ "source": "iana",
+ "extensions": ["i2g"]
+ },
+ "application/vnd.intertrust.digibox": {
+ "source": "iana"
+ },
+ "application/vnd.intertrust.nncp": {
+ "source": "iana"
+ },
+ "application/vnd.intu.qbo": {
+ "source": "iana",
+ "extensions": ["qbo"]
+ },
+ "application/vnd.intu.qfx": {
+ "source": "iana",
+ "extensions": ["qfx"]
+ },
+ "application/vnd.ipfs.ipns-record": {
+ "source": "iana"
+ },
+ "application/vnd.ipld.car": {
+ "source": "iana"
+ },
+ "application/vnd.ipld.dag-cbor": {
+ "source": "iana"
+ },
+ "application/vnd.ipld.dag-json": {
+ "source": "iana"
+ },
+ "application/vnd.ipld.raw": {
+ "source": "iana"
+ },
+ "application/vnd.iptc.g2.catalogitem+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.iptc.g2.conceptitem+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.iptc.g2.knowledgeitem+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.iptc.g2.newsitem+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.iptc.g2.newsmessage+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.iptc.g2.packageitem+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.iptc.g2.planningitem+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ipunplugged.rcprofile": {
+ "source": "iana",
+ "extensions": ["rcprofile"]
+ },
+ "application/vnd.irepository.package+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["irp"]
+ },
+ "application/vnd.is-xpr": {
+ "source": "iana",
+ "extensions": ["xpr"]
+ },
+ "application/vnd.isac.fcs": {
+ "source": "iana",
+ "extensions": ["fcs"]
+ },
+ "application/vnd.iso11783-10+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.jam": {
+ "source": "iana",
+ "extensions": ["jam"]
+ },
+ "application/vnd.japannet-directory-service": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-jpnstore-wakeup": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-payment-wakeup": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-registration": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-registration-wakeup": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-setstore-wakeup": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-verification": {
+ "source": "iana"
+ },
+ "application/vnd.japannet-verification-wakeup": {
+ "source": "iana"
+ },
+ "application/vnd.jcp.javame.midlet-rms": {
+ "source": "iana",
+ "extensions": ["rms"]
+ },
+ "application/vnd.jisp": {
+ "source": "iana",
+ "extensions": ["jisp"]
+ },
+ "application/vnd.joost.joda-archive": {
+ "source": "iana",
+ "extensions": ["joda"]
+ },
+ "application/vnd.jsk.isdn-ngn": {
+ "source": "iana"
+ },
+ "application/vnd.kahootz": {
+ "source": "iana",
+ "extensions": ["ktz","ktr"]
+ },
+ "application/vnd.kde.karbon": {
+ "source": "iana",
+ "extensions": ["karbon"]
+ },
+ "application/vnd.kde.kchart": {
+ "source": "iana",
+ "extensions": ["chrt"]
+ },
+ "application/vnd.kde.kformula": {
+ "source": "iana",
+ "extensions": ["kfo"]
+ },
+ "application/vnd.kde.kivio": {
+ "source": "iana",
+ "extensions": ["flw"]
+ },
+ "application/vnd.kde.kontour": {
+ "source": "iana",
+ "extensions": ["kon"]
+ },
+ "application/vnd.kde.kpresenter": {
+ "source": "iana",
+ "extensions": ["kpr","kpt"]
+ },
+ "application/vnd.kde.kspread": {
+ "source": "iana",
+ "extensions": ["ksp"]
+ },
+ "application/vnd.kde.kword": {
+ "source": "iana",
+ "extensions": ["kwd","kwt"]
+ },
+ "application/vnd.kdl": {
+ "source": "iana"
+ },
+ "application/vnd.kenameaapp": {
+ "source": "iana",
+ "extensions": ["htke"]
+ },
+ "application/vnd.keyman.kmp+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.keyman.kmx": {
+ "source": "iana"
+ },
+ "application/vnd.kidspiration": {
+ "source": "iana",
+ "extensions": ["kia"]
+ },
+ "application/vnd.kinar": {
+ "source": "iana",
+ "extensions": ["kne","knp"]
+ },
+ "application/vnd.koan": {
+ "source": "iana",
+ "extensions": ["skp","skd","skt","skm"]
+ },
+ "application/vnd.kodak-descriptor": {
+ "source": "iana",
+ "extensions": ["sse"]
+ },
+ "application/vnd.las": {
+ "source": "iana"
+ },
+ "application/vnd.las.las+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.las.las+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["lasxml"]
+ },
+ "application/vnd.laszip": {
+ "source": "iana"
+ },
+ "application/vnd.ldev.productlicensing": {
+ "source": "iana"
+ },
+ "application/vnd.leap+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.liberty-request+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.llamagraphics.life-balance.desktop": {
+ "source": "iana",
+ "extensions": ["lbd"]
+ },
+ "application/vnd.llamagraphics.life-balance.exchange+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["lbe"]
+ },
+ "application/vnd.logipipe.circuit+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.loom": {
+ "source": "iana"
+ },
+ "application/vnd.lotus-1-2-3": {
+ "source": "iana",
+ "extensions": ["123"]
+ },
+ "application/vnd.lotus-approach": {
+ "source": "iana",
+ "extensions": ["apr"]
+ },
+ "application/vnd.lotus-freelance": {
+ "source": "iana",
+ "extensions": ["pre"]
+ },
+ "application/vnd.lotus-notes": {
+ "source": "iana",
+ "extensions": ["nsf"]
+ },
+ "application/vnd.lotus-organizer": {
+ "source": "iana",
+ "extensions": ["org"]
+ },
+ "application/vnd.lotus-screencam": {
+ "source": "iana",
+ "extensions": ["scm"]
+ },
+ "application/vnd.lotus-wordpro": {
+ "source": "iana",
+ "extensions": ["lwp"]
+ },
+ "application/vnd.macports.portpkg": {
+ "source": "iana",
+ "extensions": ["portpkg"]
+ },
+ "application/vnd.mapbox-vector-tile": {
+ "source": "iana",
+ "extensions": ["mvt"]
+ },
+ "application/vnd.marlin.drm.actiontoken+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.marlin.drm.conftoken+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.marlin.drm.license+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.marlin.drm.mdcf": {
+ "source": "iana"
+ },
+ "application/vnd.mason+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.maxar.archive.3tz+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.maxmind.maxmind-db": {
+ "source": "iana"
+ },
+ "application/vnd.mcd": {
+ "source": "iana",
+ "extensions": ["mcd"]
+ },
+ "application/vnd.mdl": {
+ "source": "iana"
+ },
+ "application/vnd.mdl-mbsdf": {
+ "source": "iana"
+ },
+ "application/vnd.medcalcdata": {
+ "source": "iana",
+ "extensions": ["mc1"]
+ },
+ "application/vnd.mediastation.cdkey": {
+ "source": "iana",
+ "extensions": ["cdkey"]
+ },
+ "application/vnd.medicalholodeck.recordxr": {
+ "source": "iana"
+ },
+ "application/vnd.meridian-slingshot": {
+ "source": "iana"
+ },
+ "application/vnd.mermaid": {
+ "source": "iana"
+ },
+ "application/vnd.mfer": {
+ "source": "iana",
+ "extensions": ["mwf"]
+ },
+ "application/vnd.mfmp": {
+ "source": "iana",
+ "extensions": ["mfm"]
+ },
+ "application/vnd.micro+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.micrografx.flo": {
+ "source": "iana",
+ "extensions": ["flo"]
+ },
+ "application/vnd.micrografx.igx": {
+ "source": "iana",
+ "extensions": ["igx"]
+ },
+ "application/vnd.microsoft.portable-executable": {
+ "source": "iana"
+ },
+ "application/vnd.microsoft.windows.thumbnail-cache": {
+ "source": "iana"
+ },
+ "application/vnd.miele+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.mif": {
+ "source": "iana",
+ "extensions": ["mif"]
+ },
+ "application/vnd.minisoft-hp3000-save": {
+ "source": "iana"
+ },
+ "application/vnd.mitsubishi.misty-guard.trustweb": {
+ "source": "iana"
+ },
+ "application/vnd.mobius.daf": {
+ "source": "iana",
+ "extensions": ["daf"]
+ },
+ "application/vnd.mobius.dis": {
+ "source": "iana",
+ "extensions": ["dis"]
+ },
+ "application/vnd.mobius.mbk": {
+ "source": "iana",
+ "extensions": ["mbk"]
+ },
+ "application/vnd.mobius.mqy": {
+ "source": "iana",
+ "extensions": ["mqy"]
+ },
+ "application/vnd.mobius.msl": {
+ "source": "iana",
+ "extensions": ["msl"]
+ },
+ "application/vnd.mobius.plc": {
+ "source": "iana",
+ "extensions": ["plc"]
+ },
+ "application/vnd.mobius.txf": {
+ "source": "iana",
+ "extensions": ["txf"]
+ },
+ "application/vnd.modl": {
+ "source": "iana"
+ },
+ "application/vnd.mophun.application": {
+ "source": "iana",
+ "extensions": ["mpn"]
+ },
+ "application/vnd.mophun.certificate": {
+ "source": "iana",
+ "extensions": ["mpc"]
+ },
+ "application/vnd.motorola.flexsuite": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.adsi": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.fis": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.gotap": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.kmr": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.ttc": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.flexsuite.wem": {
+ "source": "iana"
+ },
+ "application/vnd.motorola.iprm": {
+ "source": "iana"
+ },
+ "application/vnd.mozilla.xul+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xul"]
+ },
+ "application/vnd.ms-3mfdocument": {
+ "source": "iana"
+ },
+ "application/vnd.ms-artgalry": {
+ "source": "iana",
+ "extensions": ["cil"]
+ },
+ "application/vnd.ms-asf": {
+ "source": "iana"
+ },
+ "application/vnd.ms-cab-compressed": {
+ "source": "iana",
+ "extensions": ["cab"]
+ },
+ "application/vnd.ms-color.iccprofile": {
+ "source": "apache"
+ },
+ "application/vnd.ms-excel": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["xls","xlm","xla","xlc","xlt","xlw"]
+ },
+ "application/vnd.ms-excel.addin.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["xlam"]
+ },
+ "application/vnd.ms-excel.sheet.binary.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["xlsb"]
+ },
+ "application/vnd.ms-excel.sheet.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["xlsm"]
+ },
+ "application/vnd.ms-excel.template.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["xltm"]
+ },
+ "application/vnd.ms-fontobject": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["eot"]
+ },
+ "application/vnd.ms-htmlhelp": {
+ "source": "iana",
+ "extensions": ["chm"]
+ },
+ "application/vnd.ms-ims": {
+ "source": "iana",
+ "extensions": ["ims"]
+ },
+ "application/vnd.ms-lrm": {
+ "source": "iana",
+ "extensions": ["lrm"]
+ },
+ "application/vnd.ms-office.activex+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ms-officetheme": {
+ "source": "iana",
+ "extensions": ["thmx"]
+ },
+ "application/vnd.ms-opentype": {
+ "source": "apache",
+ "compressible": true
+ },
+ "application/vnd.ms-outlook": {
+ "compressible": false,
+ "extensions": ["msg"]
+ },
+ "application/vnd.ms-package.obfuscated-opentype": {
+ "source": "apache"
+ },
+ "application/vnd.ms-pki.seccat": {
+ "source": "apache",
+ "extensions": ["cat"]
+ },
+ "application/vnd.ms-pki.stl": {
+ "source": "apache",
+ "extensions": ["stl"]
+ },
+ "application/vnd.ms-playready.initiator+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ms-powerpoint": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["ppt","pps","pot"]
+ },
+ "application/vnd.ms-powerpoint.addin.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["ppam"]
+ },
+ "application/vnd.ms-powerpoint.presentation.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["pptm"]
+ },
+ "application/vnd.ms-powerpoint.slide.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["sldm"]
+ },
+ "application/vnd.ms-powerpoint.slideshow.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["ppsm"]
+ },
+ "application/vnd.ms-powerpoint.template.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["potm"]
+ },
+ "application/vnd.ms-printdevicecapabilities+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ms-printing.printticket+xml": {
+ "source": "apache",
+ "compressible": true
+ },
+ "application/vnd.ms-printschematicket+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.ms-project": {
+ "source": "iana",
+ "extensions": ["mpp","mpt"]
+ },
+ "application/vnd.ms-tnef": {
+ "source": "iana"
+ },
+ "application/vnd.ms-visio.viewer": {
+ "extensions": ["vdx"]
+ },
+ "application/vnd.ms-windows.devicepairing": {
+ "source": "iana"
+ },
+ "application/vnd.ms-windows.nwprinting.oob": {
+ "source": "iana"
+ },
+ "application/vnd.ms-windows.printerpairing": {
+ "source": "iana"
+ },
+ "application/vnd.ms-windows.wsd.oob": {
+ "source": "iana"
+ },
+ "application/vnd.ms-wmdrm.lic-chlg-req": {
+ "source": "iana"
+ },
+ "application/vnd.ms-wmdrm.lic-resp": {
+ "source": "iana"
+ },
+ "application/vnd.ms-wmdrm.meter-chlg-req": {
+ "source": "iana"
+ },
+ "application/vnd.ms-wmdrm.meter-resp": {
+ "source": "iana"
+ },
+ "application/vnd.ms-word.document.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["docm"]
+ },
+ "application/vnd.ms-word.template.macroenabled.12": {
+ "source": "iana",
+ "extensions": ["dotm"]
+ },
+ "application/vnd.ms-works": {
+ "source": "iana",
+ "extensions": ["wps","wks","wcm","wdb"]
+ },
+ "application/vnd.ms-wpl": {
+ "source": "iana",
+ "extensions": ["wpl"]
+ },
+ "application/vnd.ms-xpsdocument": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["xps"]
+ },
+ "application/vnd.msa-disk-image": {
+ "source": "iana"
+ },
+ "application/vnd.mseq": {
+ "source": "iana",
+ "extensions": ["mseq"]
+ },
+ "application/vnd.msgpack": {
+ "source": "iana"
+ },
+ "application/vnd.msign": {
+ "source": "iana"
+ },
+ "application/vnd.multiad.creator": {
+ "source": "iana"
+ },
+ "application/vnd.multiad.creator.cif": {
+ "source": "iana"
+ },
+ "application/vnd.music-niff": {
+ "source": "iana"
+ },
+ "application/vnd.musician": {
+ "source": "iana",
+ "extensions": ["mus"]
+ },
+ "application/vnd.muvee.style": {
+ "source": "iana",
+ "extensions": ["msty"]
+ },
+ "application/vnd.mynfc": {
+ "source": "iana",
+ "extensions": ["taglet"]
+ },
+ "application/vnd.nacamar.ybrid+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.nato.bindingdataobject+cbor": {
+ "source": "iana"
+ },
+ "application/vnd.nato.bindingdataobject+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.nato.bindingdataobject+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["bdo"]
+ },
+ "application/vnd.nato.openxmlformats-package.iepd+zip": {
+ "source": "iana",
+ "compressible": false
+ },
+ "application/vnd.ncd.control": {
+ "source": "iana"
+ },
+ "application/vnd.ncd.reference": {
+ "source": "iana"
+ },
+ "application/vnd.nearst.inv+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.nebumind.line": {
+ "source": "iana"
+ },
+ "application/vnd.nervana": {
+ "source": "iana"
+ },
+ "application/vnd.netfpx": {
+ "source": "iana"
+ },
+ "application/vnd.neurolanguage.nlu": {
+ "source": "iana",
+ "extensions": ["nlu"]
+ },
+ "application/vnd.nimn": {
+ "source": "iana"
+ },
+ "application/vnd.nintendo.nitro.rom": {
+ "source": "iana"
+ },
+ "application/vnd.nintendo.snes.rom": {
+ "source": "iana"
+ },
+ "application/vnd.nitf": {
+ "source": "iana",
+ "extensions": ["ntf","nitf"]
+ },
+ "application/vnd.noblenet-directory": {
+ "source": "iana",
+ "extensions": ["nnd"]
+ },
+ "application/vnd.noblenet-sealer": {
+ "source": "iana",
+ "extensions": ["nns"]
+ },
+ "application/vnd.noblenet-web": {
+ "source": "iana",
+ "extensions": ["nnw"]
+ },
+ "application/vnd.nokia.catalogs": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.conml+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.conml+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.nokia.iptv.config+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.nokia.isds-radio-presets": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.landmark+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.landmark+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.nokia.landmarkcollection+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.nokia.n-gage.ac+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["ac"]
+ },
+ "application/vnd.nokia.n-gage.data": {
+ "source": "iana",
+ "extensions": ["ngdat"]
+ },
+ "application/vnd.nokia.n-gage.symbian.install": {
+ "source": "apache",
+ "extensions": ["n-gage"]
+ },
+ "application/vnd.nokia.ncd": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.pcd+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.nokia.pcd+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.nokia.radio-preset": {
+ "source": "iana",
+ "extensions": ["rpst"]
+ },
+ "application/vnd.nokia.radio-presets": {
+ "source": "iana",
+ "extensions": ["rpss"]
+ },
+ "application/vnd.novadigm.edm": {
+ "source": "iana",
+ "extensions": ["edm"]
+ },
+ "application/vnd.novadigm.edx": {
+ "source": "iana",
+ "extensions": ["edx"]
+ },
+ "application/vnd.novadigm.ext": {
+ "source": "iana",
+ "extensions": ["ext"]
+ },
+ "application/vnd.ntt-local.content-share": {
+ "source": "iana"
+ },
+ "application/vnd.ntt-local.file-transfer": {
+ "source": "iana"
+ },
+ "application/vnd.ntt-local.ogw_remote-access": {
+ "source": "iana"
+ },
+ "application/vnd.ntt-local.sip-ta_remote": {
+ "source": "iana"
+ },
+ "application/vnd.ntt-local.sip-ta_tcp_stream": {
+ "source": "iana"
+ },
+ "application/vnd.oai.workflows": {
+ "source": "iana"
+ },
+ "application/vnd.oai.workflows+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oai.workflows+yaml": {
+ "source": "iana"
+ },
+ "application/vnd.oasis.opendocument.base": {
+ "source": "iana"
+ },
+ "application/vnd.oasis.opendocument.chart": {
+ "source": "iana",
+ "extensions": ["odc"]
+ },
+ "application/vnd.oasis.opendocument.chart-template": {
+ "source": "iana",
+ "extensions": ["otc"]
+ },
+ "application/vnd.oasis.opendocument.database": {
+ "source": "apache",
+ "extensions": ["odb"]
+ },
+ "application/vnd.oasis.opendocument.formula": {
+ "source": "iana",
+ "extensions": ["odf"]
+ },
+ "application/vnd.oasis.opendocument.formula-template": {
+ "source": "iana",
+ "extensions": ["odft"]
+ },
+ "application/vnd.oasis.opendocument.graphics": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["odg"]
+ },
+ "application/vnd.oasis.opendocument.graphics-template": {
+ "source": "iana",
+ "extensions": ["otg"]
+ },
+ "application/vnd.oasis.opendocument.image": {
+ "source": "iana",
+ "extensions": ["odi"]
+ },
+ "application/vnd.oasis.opendocument.image-template": {
+ "source": "iana",
+ "extensions": ["oti"]
+ },
+ "application/vnd.oasis.opendocument.presentation": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["odp"]
+ },
+ "application/vnd.oasis.opendocument.presentation-template": {
+ "source": "iana",
+ "extensions": ["otp"]
+ },
+ "application/vnd.oasis.opendocument.spreadsheet": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["ods"]
+ },
+ "application/vnd.oasis.opendocument.spreadsheet-template": {
+ "source": "iana",
+ "extensions": ["ots"]
+ },
+ "application/vnd.oasis.opendocument.text": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["odt"]
+ },
+ "application/vnd.oasis.opendocument.text-master": {
+ "source": "iana",
+ "extensions": ["odm"]
+ },
+ "application/vnd.oasis.opendocument.text-master-template": {
+ "source": "iana"
+ },
+ "application/vnd.oasis.opendocument.text-template": {
+ "source": "iana",
+ "extensions": ["ott"]
+ },
+ "application/vnd.oasis.opendocument.text-web": {
+ "source": "iana",
+ "extensions": ["oth"]
+ },
+ "application/vnd.obn": {
+ "source": "iana"
+ },
+ "application/vnd.ocf+cbor": {
+ "source": "iana"
+ },
+ "application/vnd.oci.image.manifest.v1+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oftn.l10n+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oipf.contentaccessdownload+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oipf.contentaccessstreaming+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oipf.cspg-hexbinary": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.dae.svg+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oipf.dae.xhtml+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oipf.mippvcontrolmessage+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oipf.pae.gem": {
+ "source": "iana"
+ },
+ "application/vnd.oipf.spdiscovery+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oipf.spdlist+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oipf.ueprofile+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oipf.userprofile+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.olpc-sugar": {
+ "source": "iana",
+ "extensions": ["xo"]
+ },
+ "application/vnd.oma-scws-config": {
+ "source": "iana"
+ },
+ "application/vnd.oma-scws-http-request": {
+ "source": "iana"
+ },
+ "application/vnd.oma-scws-http-response": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.associated-procedure-parameter+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.bcast.drm-trigger+xml": {
+ "source": "apache",
+ "compressible": true
+ },
+ "application/vnd.oma.bcast.imd+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.bcast.ltkm": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.notification+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.bcast.provisioningtrigger": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.sgboot": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.sgdd+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.bcast.sgdu": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.simple-symbol-container": {
+ "source": "iana"
+ },
+ "application/vnd.oma.bcast.smartcard-trigger+xml": {
+ "source": "apache",
+ "compressible": true
+ },
+ "application/vnd.oma.bcast.sprov+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.bcast.stkm": {
+ "source": "iana"
+ },
+ "application/vnd.oma.cab-address-book+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.cab-feature-handler+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.cab-pcc+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.cab-subs-invite+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.cab-user-prefs+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.dcd": {
+ "source": "iana"
+ },
+ "application/vnd.oma.dcdc": {
+ "source": "iana"
+ },
+ "application/vnd.oma.dd2+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["dd2"]
+ },
+ "application/vnd.oma.drm.risd+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.group-usage-list+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.lwm2m+cbor": {
+ "source": "iana"
+ },
+ "application/vnd.oma.lwm2m+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.lwm2m+tlv": {
+ "source": "iana"
+ },
+ "application/vnd.oma.pal+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.poc.detailed-progress-report+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.poc.final-report+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.poc.groups+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.poc.invocation-descriptor+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.poc.optimized-progress-report+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.push": {
+ "source": "iana"
+ },
+ "application/vnd.oma.scidm.messages+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oma.xcap-directory+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.omads-email+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/vnd.omads-file+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/vnd.omads-folder+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/vnd.omaloc-supl-init": {
+ "source": "iana"
+ },
+ "application/vnd.onepager": {
+ "source": "iana"
+ },
+ "application/vnd.onepagertamp": {
+ "source": "iana"
+ },
+ "application/vnd.onepagertamx": {
+ "source": "iana"
+ },
+ "application/vnd.onepagertat": {
+ "source": "iana"
+ },
+ "application/vnd.onepagertatp": {
+ "source": "iana"
+ },
+ "application/vnd.onepagertatx": {
+ "source": "iana"
+ },
+ "application/vnd.onvif.metadata": {
+ "source": "iana"
+ },
+ "application/vnd.openblox.game+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["obgx"]
+ },
+ "application/vnd.openblox.game-binary": {
+ "source": "iana"
+ },
+ "application/vnd.openeye.oeb": {
+ "source": "iana"
+ },
+ "application/vnd.openofficeorg.extension": {
+ "source": "apache",
+ "extensions": ["oxt"]
+ },
+ "application/vnd.openstreetmap.data+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["osm"]
+ },
+ "application/vnd.opentimestamps.ots": {
+ "source": "iana"
+ },
+ "application/vnd.openvpi.dspx+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.custom-properties+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.customxmlproperties+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.drawing+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.extended-properties+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.comments+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["pptx"]
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.presprops+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slide": {
+ "source": "iana",
+ "extensions": ["sldx"]
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slide+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow": {
+ "source": "iana",
+ "extensions": ["ppsx"]
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.tags+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.template": {
+ "source": "iana",
+ "extensions": ["potx"]
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["xlsx"]
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.template": {
+ "source": "iana",
+ "extensions": ["xltx"]
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.theme+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.themeoverride+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.vmldrawing": {
+ "source": "iana"
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["docx"]
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.template": {
+ "source": "iana",
+ "extensions": ["dotx"]
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-package.core-properties+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.openxmlformats-package.relationships+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oracle.resource+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.orange.indata": {
+ "source": "iana"
+ },
+ "application/vnd.osa.netdeploy": {
+ "source": "iana"
+ },
+ "application/vnd.osgeo.mapguide.package": {
+ "source": "iana",
+ "extensions": ["mgp"]
+ },
+ "application/vnd.osgi.bundle": {
+ "source": "iana"
+ },
+ "application/vnd.osgi.dp": {
+ "source": "iana",
+ "extensions": ["dp"]
+ },
+ "application/vnd.osgi.subsystem": {
+ "source": "iana",
+ "extensions": ["esa"]
+ },
+ "application/vnd.otps.ct-kip+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.oxli.countgraph": {
+ "source": "iana"
+ },
+ "application/vnd.pagerduty+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.palm": {
+ "source": "iana",
+ "extensions": ["pdb","pqa","oprc"]
+ },
+ "application/vnd.panoply": {
+ "source": "iana"
+ },
+ "application/vnd.paos.xml": {
+ "source": "iana"
+ },
+ "application/vnd.patentdive": {
+ "source": "iana"
+ },
+ "application/vnd.patientecommsdoc": {
+ "source": "iana"
+ },
+ "application/vnd.pawaafile": {
+ "source": "iana",
+ "extensions": ["paw"]
+ },
+ "application/vnd.pcos": {
+ "source": "iana"
+ },
+ "application/vnd.pg.format": {
+ "source": "iana",
+ "extensions": ["str"]
+ },
+ "application/vnd.pg.osasli": {
+ "source": "iana",
+ "extensions": ["ei6"]
+ },
+ "application/vnd.piaccess.application-licence": {
+ "source": "iana"
+ },
+ "application/vnd.picsel": {
+ "source": "iana",
+ "extensions": ["efif"]
+ },
+ "application/vnd.pmi.widget": {
+ "source": "iana",
+ "extensions": ["wg"]
+ },
+ "application/vnd.poc.group-advertisement+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.pocketlearn": {
+ "source": "iana",
+ "extensions": ["plf"]
+ },
+ "application/vnd.powerbuilder6": {
+ "source": "iana",
+ "extensions": ["pbd"]
+ },
+ "application/vnd.powerbuilder6-s": {
+ "source": "iana"
+ },
+ "application/vnd.powerbuilder7": {
+ "source": "iana"
+ },
+ "application/vnd.powerbuilder7-s": {
+ "source": "iana"
+ },
+ "application/vnd.powerbuilder75": {
+ "source": "iana"
+ },
+ "application/vnd.powerbuilder75-s": {
+ "source": "iana"
+ },
+ "application/vnd.preminet": {
+ "source": "iana"
+ },
+ "application/vnd.previewsystems.box": {
+ "source": "iana",
+ "extensions": ["box"]
+ },
+ "application/vnd.procrate.brushset": {
+ "extensions": ["brushset"]
+ },
+ "application/vnd.procreate.brush": {
+ "extensions": ["brush"]
+ },
+ "application/vnd.procreate.dream": {
+ "extensions": ["drm"]
+ },
+ "application/vnd.proteus.magazine": {
+ "source": "iana",
+ "extensions": ["mgz"]
+ },
+ "application/vnd.psfs": {
+ "source": "iana"
+ },
+ "application/vnd.pt.mundusmundi": {
+ "source": "iana"
+ },
+ "application/vnd.publishare-delta-tree": {
+ "source": "iana",
+ "extensions": ["qps"]
+ },
+ "application/vnd.pvi.ptid1": {
+ "source": "iana",
+ "extensions": ["ptid"]
+ },
+ "application/vnd.pwg-multiplexed": {
+ "source": "iana"
+ },
+ "application/vnd.pwg-xhtml-print+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xhtm"]
+ },
+ "application/vnd.qualcomm.brew-app-res": {
+ "source": "iana"
+ },
+ "application/vnd.quarantainenet": {
+ "source": "iana"
+ },
+ "application/vnd.quark.quarkxpress": {
+ "source": "iana",
+ "extensions": ["qxd","qxt","qwd","qwt","qxl","qxb"]
+ },
+ "application/vnd.quobject-quoxdocument": {
+ "source": "iana"
+ },
+ "application/vnd.radisys.moml+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-audit+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-audit-conf+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-audit-conn+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-audit-dialog+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-audit-stream+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-conf+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-dialog+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-dialog-base+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-dialog-fax-detect+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-dialog-fax-sendrecv+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-dialog-group+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-dialog-speech+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.radisys.msml-dialog-transform+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.rainstor.data": {
+ "source": "iana"
+ },
+ "application/vnd.rapid": {
+ "source": "iana"
+ },
+ "application/vnd.rar": {
+ "source": "iana",
+ "extensions": ["rar"]
+ },
+ "application/vnd.realvnc.bed": {
+ "source": "iana",
+ "extensions": ["bed"]
+ },
+ "application/vnd.recordare.musicxml": {
+ "source": "iana",
+ "extensions": ["mxl"]
+ },
+ "application/vnd.recordare.musicxml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["musicxml"]
+ },
+ "application/vnd.relpipe": {
+ "source": "iana"
+ },
+ "application/vnd.renlearn.rlprint": {
+ "source": "iana"
+ },
+ "application/vnd.resilient.logic": {
+ "source": "iana"
+ },
+ "application/vnd.restful+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.rig.cryptonote": {
+ "source": "iana",
+ "extensions": ["cryptonote"]
+ },
+ "application/vnd.rim.cod": {
+ "source": "apache",
+ "extensions": ["cod"]
+ },
+ "application/vnd.rn-realmedia": {
+ "source": "apache",
+ "extensions": ["rm"]
+ },
+ "application/vnd.rn-realmedia-vbr": {
+ "source": "apache",
+ "extensions": ["rmvb"]
+ },
+ "application/vnd.route66.link66+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["link66"]
+ },
+ "application/vnd.rs-274x": {
+ "source": "iana"
+ },
+ "application/vnd.ruckus.download": {
+ "source": "iana"
+ },
+ "application/vnd.s3sms": {
+ "source": "iana"
+ },
+ "application/vnd.sailingtracker.track": {
+ "source": "iana",
+ "extensions": ["st"]
+ },
+ "application/vnd.sar": {
+ "source": "iana"
+ },
+ "application/vnd.sbm.cid": {
+ "source": "iana"
+ },
+ "application/vnd.sbm.mid2": {
+ "source": "iana"
+ },
+ "application/vnd.scribus": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.3df": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.csf": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.doc": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.eml": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.mht": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.net": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.ppt": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.tiff": {
+ "source": "iana"
+ },
+ "application/vnd.sealed.xls": {
+ "source": "iana"
+ },
+ "application/vnd.sealedmedia.softseal.html": {
+ "source": "iana"
+ },
+ "application/vnd.sealedmedia.softseal.pdf": {
+ "source": "iana"
+ },
+ "application/vnd.seemail": {
+ "source": "iana",
+ "extensions": ["see"]
+ },
+ "application/vnd.seis+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.sema": {
+ "source": "iana",
+ "extensions": ["sema"]
+ },
+ "application/vnd.semd": {
+ "source": "iana",
+ "extensions": ["semd"]
+ },
+ "application/vnd.semf": {
+ "source": "iana",
+ "extensions": ["semf"]
+ },
+ "application/vnd.shade-save-file": {
+ "source": "iana"
+ },
+ "application/vnd.shana.informed.formdata": {
+ "source": "iana",
+ "extensions": ["ifm"]
+ },
+ "application/vnd.shana.informed.formtemplate": {
+ "source": "iana",
+ "extensions": ["itp"]
+ },
+ "application/vnd.shana.informed.interchange": {
+ "source": "iana",
+ "extensions": ["iif"]
+ },
+ "application/vnd.shana.informed.package": {
+ "source": "iana",
+ "extensions": ["ipk"]
+ },
+ "application/vnd.shootproof+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.shopkick+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.shp": {
+ "source": "iana"
+ },
+ "application/vnd.shx": {
+ "source": "iana"
+ },
+ "application/vnd.sigrok.session": {
+ "source": "iana"
+ },
+ "application/vnd.simtech-mindmapper": {
+ "source": "iana",
+ "extensions": ["twd","twds"]
+ },
+ "application/vnd.siren+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.sketchometry": {
+ "source": "iana"
+ },
+ "application/vnd.smaf": {
+ "source": "iana",
+ "extensions": ["mmf"]
+ },
+ "application/vnd.smart.notebook": {
+ "source": "iana"
+ },
+ "application/vnd.smart.teacher": {
+ "source": "iana",
+ "extensions": ["teacher"]
+ },
+ "application/vnd.smintio.portals.archive": {
+ "source": "iana"
+ },
+ "application/vnd.snesdev-page-table": {
+ "source": "iana"
+ },
+ "application/vnd.software602.filler.form+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["fo"]
+ },
+ "application/vnd.software602.filler.form-xml-zip": {
+ "source": "iana"
+ },
+ "application/vnd.solent.sdkm+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["sdkm","sdkd"]
+ },
+ "application/vnd.spotfire.dxp": {
+ "source": "iana",
+ "extensions": ["dxp"]
+ },
+ "application/vnd.spotfire.sfs": {
+ "source": "iana",
+ "extensions": ["sfs"]
+ },
+ "application/vnd.sqlite3": {
+ "source": "iana"
+ },
+ "application/vnd.sss-cod": {
+ "source": "iana"
+ },
+ "application/vnd.sss-dtf": {
+ "source": "iana"
+ },
+ "application/vnd.sss-ntf": {
+ "source": "iana"
+ },
+ "application/vnd.stardivision.calc": {
+ "source": "apache",
+ "extensions": ["sdc"]
+ },
+ "application/vnd.stardivision.draw": {
+ "source": "apache",
+ "extensions": ["sda"]
+ },
+ "application/vnd.stardivision.impress": {
+ "source": "apache",
+ "extensions": ["sdd"]
+ },
+ "application/vnd.stardivision.math": {
+ "source": "apache",
+ "extensions": ["smf"]
+ },
+ "application/vnd.stardivision.writer": {
+ "source": "apache",
+ "extensions": ["sdw","vor"]
+ },
+ "application/vnd.stardivision.writer-global": {
+ "source": "apache",
+ "extensions": ["sgl"]
+ },
+ "application/vnd.stepmania.package": {
+ "source": "iana",
+ "extensions": ["smzip"]
+ },
+ "application/vnd.stepmania.stepchart": {
+ "source": "iana",
+ "extensions": ["sm"]
+ },
+ "application/vnd.street-stream": {
+ "source": "iana"
+ },
+ "application/vnd.sun.wadl+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["wadl"]
+ },
+ "application/vnd.sun.xml.calc": {
+ "source": "apache",
+ "extensions": ["sxc"]
+ },
+ "application/vnd.sun.xml.calc.template": {
+ "source": "apache",
+ "extensions": ["stc"]
+ },
+ "application/vnd.sun.xml.draw": {
+ "source": "apache",
+ "extensions": ["sxd"]
+ },
+ "application/vnd.sun.xml.draw.template": {
+ "source": "apache",
+ "extensions": ["std"]
+ },
+ "application/vnd.sun.xml.impress": {
+ "source": "apache",
+ "extensions": ["sxi"]
+ },
+ "application/vnd.sun.xml.impress.template": {
+ "source": "apache",
+ "extensions": ["sti"]
+ },
+ "application/vnd.sun.xml.math": {
+ "source": "apache",
+ "extensions": ["sxm"]
+ },
+ "application/vnd.sun.xml.writer": {
+ "source": "apache",
+ "extensions": ["sxw"]
+ },
+ "application/vnd.sun.xml.writer.global": {
+ "source": "apache",
+ "extensions": ["sxg"]
+ },
+ "application/vnd.sun.xml.writer.template": {
+ "source": "apache",
+ "extensions": ["stw"]
+ },
+ "application/vnd.sus-calendar": {
+ "source": "iana",
+ "extensions": ["sus","susp"]
+ },
+ "application/vnd.svd": {
+ "source": "iana",
+ "extensions": ["svd"]
+ },
+ "application/vnd.swiftview-ics": {
+ "source": "iana"
+ },
+ "application/vnd.sybyl.mol2": {
+ "source": "iana"
+ },
+ "application/vnd.sycle+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.syft+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.symbian.install": {
+ "source": "apache",
+ "extensions": ["sis","sisx"]
+ },
+ "application/vnd.syncml+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["xsm"]
+ },
+ "application/vnd.syncml.dm+wbxml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "extensions": ["bdm"]
+ },
+ "application/vnd.syncml.dm+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["xdm"]
+ },
+ "application/vnd.syncml.dm.notification": {
+ "source": "iana"
+ },
+ "application/vnd.syncml.dmddf+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.syncml.dmddf+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["ddf"]
+ },
+ "application/vnd.syncml.dmtnds+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.syncml.dmtnds+xml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true
+ },
+ "application/vnd.syncml.ds.notification": {
+ "source": "iana"
+ },
+ "application/vnd.tableschema+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.tao.intent-module-archive": {
+ "source": "iana",
+ "extensions": ["tao"]
+ },
+ "application/vnd.tcpdump.pcap": {
+ "source": "iana",
+ "extensions": ["pcap","cap","dmp"]
+ },
+ "application/vnd.think-cell.ppttc+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.tmd.mediaflex.api+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.tml": {
+ "source": "iana"
+ },
+ "application/vnd.tmobile-livetv": {
+ "source": "iana",
+ "extensions": ["tmo"]
+ },
+ "application/vnd.tri.onesource": {
+ "source": "iana"
+ },
+ "application/vnd.trid.tpt": {
+ "source": "iana",
+ "extensions": ["tpt"]
+ },
+ "application/vnd.triscape.mxs": {
+ "source": "iana",
+ "extensions": ["mxs"]
+ },
+ "application/vnd.trueapp": {
+ "source": "iana",
+ "extensions": ["tra"]
+ },
+ "application/vnd.truedoc": {
+ "source": "iana"
+ },
+ "application/vnd.ubisoft.webplayer": {
+ "source": "iana"
+ },
+ "application/vnd.ufdl": {
+ "source": "iana",
+ "extensions": ["ufd","ufdl"]
+ },
+ "application/vnd.uic.osdm+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.uiq.theme": {
+ "source": "iana",
+ "extensions": ["utz"]
+ },
+ "application/vnd.umajin": {
+ "source": "iana",
+ "extensions": ["umj"]
+ },
+ "application/vnd.unity": {
+ "source": "iana",
+ "extensions": ["unityweb"]
+ },
+ "application/vnd.uoml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["uoml","uo"]
+ },
+ "application/vnd.uplanet.alert": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.alert-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.bearer-choice": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.bearer-choice-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.cacheop": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.cacheop-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.channel": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.channel-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.list": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.list-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.listcmd": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.listcmd-wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.uplanet.signal": {
+ "source": "iana"
+ },
+ "application/vnd.uri-map": {
+ "source": "iana"
+ },
+ "application/vnd.valve.source.material": {
+ "source": "iana"
+ },
+ "application/vnd.vcx": {
+ "source": "iana",
+ "extensions": ["vcx"]
+ },
+ "application/vnd.vd-study": {
+ "source": "iana"
+ },
+ "application/vnd.vectorworks": {
+ "source": "iana"
+ },
+ "application/vnd.vel+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.veraison.tsm-report+cbor": {
+ "source": "iana"
+ },
+ "application/vnd.veraison.tsm-report+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.verimatrix.vcas": {
+ "source": "iana"
+ },
+ "application/vnd.veritone.aion+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.veryant.thin": {
+ "source": "iana"
+ },
+ "application/vnd.ves.encrypted": {
+ "source": "iana"
+ },
+ "application/vnd.vidsoft.vidconference": {
+ "source": "iana"
+ },
+ "application/vnd.visio": {
+ "source": "iana",
+ "extensions": ["vsd","vst","vss","vsw","vsdx","vtx"]
+ },
+ "application/vnd.visionary": {
+ "source": "iana",
+ "extensions": ["vis"]
+ },
+ "application/vnd.vividence.scriptfile": {
+ "source": "iana"
+ },
+ "application/vnd.vocalshaper.vsp4": {
+ "source": "iana"
+ },
+ "application/vnd.vsf": {
+ "source": "iana",
+ "extensions": ["vsf"]
+ },
+ "application/vnd.wap.sic": {
+ "source": "iana"
+ },
+ "application/vnd.wap.slc": {
+ "source": "iana"
+ },
+ "application/vnd.wap.wbxml": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "extensions": ["wbxml"]
+ },
+ "application/vnd.wap.wmlc": {
+ "source": "iana",
+ "extensions": ["wmlc"]
+ },
+ "application/vnd.wap.wmlscriptc": {
+ "source": "iana",
+ "extensions": ["wmlsc"]
+ },
+ "application/vnd.wasmflow.wafl": {
+ "source": "iana"
+ },
+ "application/vnd.webturbo": {
+ "source": "iana",
+ "extensions": ["wtb"]
+ },
+ "application/vnd.wfa.dpp": {
+ "source": "iana"
+ },
+ "application/vnd.wfa.p2p": {
+ "source": "iana"
+ },
+ "application/vnd.wfa.wsc": {
+ "source": "iana"
+ },
+ "application/vnd.windows.devicepairing": {
+ "source": "iana"
+ },
+ "application/vnd.wmc": {
+ "source": "iana"
+ },
+ "application/vnd.wmf.bootstrap": {
+ "source": "iana"
+ },
+ "application/vnd.wolfram.mathematica": {
+ "source": "iana"
+ },
+ "application/vnd.wolfram.mathematica.package": {
+ "source": "iana"
+ },
+ "application/vnd.wolfram.player": {
+ "source": "iana",
+ "extensions": ["nbp"]
+ },
+ "application/vnd.wordlift": {
+ "source": "iana"
+ },
+ "application/vnd.wordperfect": {
+ "source": "iana",
+ "extensions": ["wpd"]
+ },
+ "application/vnd.wqd": {
+ "source": "iana",
+ "extensions": ["wqd"]
+ },
+ "application/vnd.wrq-hp3000-labelled": {
+ "source": "iana"
+ },
+ "application/vnd.wt.stf": {
+ "source": "iana",
+ "extensions": ["stf"]
+ },
+ "application/vnd.wv.csp+wbxml": {
+ "source": "iana"
+ },
+ "application/vnd.wv.csp+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.wv.ssp+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.xacml+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.xara": {
+ "source": "iana",
+ "extensions": ["xar"]
+ },
+ "application/vnd.xarin.cpj": {
+ "source": "iana"
+ },
+ "application/vnd.xecrets-encrypted": {
+ "source": "iana"
+ },
+ "application/vnd.xfdl": {
+ "source": "iana",
+ "extensions": ["xfdl"]
+ },
+ "application/vnd.xfdl.webform": {
+ "source": "iana"
+ },
+ "application/vnd.xmi+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vnd.xmpie.cpkg": {
+ "source": "iana"
+ },
+ "application/vnd.xmpie.dpkg": {
+ "source": "iana"
+ },
+ "application/vnd.xmpie.plan": {
+ "source": "iana"
+ },
+ "application/vnd.xmpie.ppkg": {
+ "source": "iana"
+ },
+ "application/vnd.xmpie.xlim": {
+ "source": "iana"
+ },
+ "application/vnd.yamaha.hv-dic": {
+ "source": "iana",
+ "extensions": ["hvd"]
+ },
+ "application/vnd.yamaha.hv-script": {
+ "source": "iana",
+ "extensions": ["hvs"]
+ },
+ "application/vnd.yamaha.hv-voice": {
+ "source": "iana",
+ "extensions": ["hvp"]
+ },
+ "application/vnd.yamaha.openscoreformat": {
+ "source": "iana",
+ "extensions": ["osf"]
+ },
+ "application/vnd.yamaha.openscoreformat.osfpvg+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["osfpvg"]
+ },
+ "application/vnd.yamaha.remote-setup": {
+ "source": "iana"
+ },
+ "application/vnd.yamaha.smaf-audio": {
+ "source": "iana",
+ "extensions": ["saf"]
+ },
+ "application/vnd.yamaha.smaf-phrase": {
+ "source": "iana",
+ "extensions": ["spf"]
+ },
+ "application/vnd.yamaha.through-ngn": {
+ "source": "iana"
+ },
+ "application/vnd.yamaha.tunnel-udpencap": {
+ "source": "iana"
+ },
+ "application/vnd.yaoweme": {
+ "source": "iana"
+ },
+ "application/vnd.yellowriver-custom-menu": {
+ "source": "iana",
+ "extensions": ["cmp"]
+ },
+ "application/vnd.zul": {
+ "source": "iana",
+ "extensions": ["zir","zirz"]
+ },
+ "application/vnd.zzazz.deck+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["zaz"]
+ },
+ "application/voicexml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["vxml"]
+ },
+ "application/voucher-cms+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/voucher-jws+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/vp": {
+ "source": "iana"
+ },
+ "application/vp+cose": {
+ "source": "iana"
+ },
+ "application/vp+jwt": {
+ "source": "iana"
+ },
+ "application/vq-rtcpxr": {
+ "source": "iana"
+ },
+ "application/wasm": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["wasm"]
+ },
+ "application/watcherinfo+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["wif"]
+ },
+ "application/webpush-options+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/whoispp-query": {
+ "source": "iana"
+ },
+ "application/whoispp-response": {
+ "source": "iana"
+ },
+ "application/widget": {
+ "source": "iana",
+ "extensions": ["wgt"]
+ },
+ "application/winhlp": {
+ "source": "apache",
+ "extensions": ["hlp"]
+ },
+ "application/wita": {
+ "source": "iana"
+ },
+ "application/wordperfect5.1": {
+ "source": "iana"
+ },
+ "application/wsdl+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["wsdl"]
+ },
+ "application/wspolicy+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["wspolicy"]
+ },
+ "application/x-7z-compressed": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["7z"]
+ },
+ "application/x-abiword": {
+ "source": "apache",
+ "extensions": ["abw"]
+ },
+ "application/x-ace-compressed": {
+ "source": "apache",
+ "extensions": ["ace"]
+ },
+ "application/x-amf": {
+ "source": "apache"
+ },
+ "application/x-apple-diskimage": {
+ "source": "apache",
+ "extensions": ["dmg"]
+ },
+ "application/x-arj": {
+ "compressible": false,
+ "extensions": ["arj"]
+ },
+ "application/x-authorware-bin": {
+ "source": "apache",
+ "extensions": ["aab","x32","u32","vox"]
+ },
+ "application/x-authorware-map": {
+ "source": "apache",
+ "extensions": ["aam"]
+ },
+ "application/x-authorware-seg": {
+ "source": "apache",
+ "extensions": ["aas"]
+ },
+ "application/x-bcpio": {
+ "source": "apache",
+ "extensions": ["bcpio"]
+ },
+ "application/x-bdoc": {
+ "compressible": false,
+ "extensions": ["bdoc"]
+ },
+ "application/x-bittorrent": {
+ "source": "apache",
+ "extensions": ["torrent"]
+ },
+ "application/x-blender": {
+ "extensions": ["blend"]
+ },
+ "application/x-blorb": {
+ "source": "apache",
+ "extensions": ["blb","blorb"]
+ },
+ "application/x-bzip": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["bz"]
+ },
+ "application/x-bzip2": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["bz2","boz"]
+ },
+ "application/x-cbr": {
+ "source": "apache",
+ "extensions": ["cbr","cba","cbt","cbz","cb7"]
+ },
+ "application/x-cdlink": {
+ "source": "apache",
+ "extensions": ["vcd"]
+ },
+ "application/x-cfs-compressed": {
+ "source": "apache",
+ "extensions": ["cfs"]
+ },
+ "application/x-chat": {
+ "source": "apache",
+ "extensions": ["chat"]
+ },
+ "application/x-chess-pgn": {
+ "source": "apache",
+ "extensions": ["pgn"]
+ },
+ "application/x-chrome-extension": {
+ "extensions": ["crx"]
+ },
+ "application/x-cocoa": {
+ "source": "nginx",
+ "extensions": ["cco"]
+ },
+ "application/x-compress": {
+ "source": "apache"
+ },
+ "application/x-compressed": {
+ "extensions": ["rar"]
+ },
+ "application/x-conference": {
+ "source": "apache",
+ "extensions": ["nsc"]
+ },
+ "application/x-cpio": {
+ "source": "apache",
+ "extensions": ["cpio"]
+ },
+ "application/x-csh": {
+ "source": "apache",
+ "extensions": ["csh"]
+ },
+ "application/x-deb": {
+ "compressible": false
+ },
+ "application/x-debian-package": {
+ "source": "apache",
+ "extensions": ["deb","udeb"]
+ },
+ "application/x-dgc-compressed": {
+ "source": "apache",
+ "extensions": ["dgc"]
+ },
+ "application/x-director": {
+ "source": "apache",
+ "extensions": ["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"]
+ },
+ "application/x-doom": {
+ "source": "apache",
+ "extensions": ["wad"]
+ },
+ "application/x-dtbncx+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["ncx"]
+ },
+ "application/x-dtbook+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["dtb"]
+ },
+ "application/x-dtbresource+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["res"]
+ },
+ "application/x-dvi": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["dvi"]
+ },
+ "application/x-envoy": {
+ "source": "apache",
+ "extensions": ["evy"]
+ },
+ "application/x-eva": {
+ "source": "apache",
+ "extensions": ["eva"]
+ },
+ "application/x-font-bdf": {
+ "source": "apache",
+ "extensions": ["bdf"]
+ },
+ "application/x-font-dos": {
+ "source": "apache"
+ },
+ "application/x-font-framemaker": {
+ "source": "apache"
+ },
+ "application/x-font-ghostscript": {
+ "source": "apache",
+ "extensions": ["gsf"]
+ },
+ "application/x-font-libgrx": {
+ "source": "apache"
+ },
+ "application/x-font-linux-psf": {
+ "source": "apache",
+ "extensions": ["psf"]
+ },
+ "application/x-font-pcf": {
+ "source": "apache",
+ "extensions": ["pcf"]
+ },
+ "application/x-font-snf": {
+ "source": "apache",
+ "extensions": ["snf"]
+ },
+ "application/x-font-speedo": {
+ "source": "apache"
+ },
+ "application/x-font-sunos-news": {
+ "source": "apache"
+ },
+ "application/x-font-type1": {
+ "source": "apache",
+ "extensions": ["pfa","pfb","pfm","afm"]
+ },
+ "application/x-font-vfont": {
+ "source": "apache"
+ },
+ "application/x-freearc": {
+ "source": "apache",
+ "extensions": ["arc"]
+ },
+ "application/x-futuresplash": {
+ "source": "apache",
+ "extensions": ["spl"]
+ },
+ "application/x-gca-compressed": {
+ "source": "apache",
+ "extensions": ["gca"]
+ },
+ "application/x-glulx": {
+ "source": "apache",
+ "extensions": ["ulx"]
+ },
+ "application/x-gnumeric": {
+ "source": "apache",
+ "extensions": ["gnumeric"]
+ },
+ "application/x-gramps-xml": {
+ "source": "apache",
+ "extensions": ["gramps"]
+ },
+ "application/x-gtar": {
+ "source": "apache",
+ "extensions": ["gtar"]
+ },
+ "application/x-gzip": {
+ "source": "apache"
+ },
+ "application/x-hdf": {
+ "source": "apache",
+ "extensions": ["hdf"]
+ },
+ "application/x-httpd-php": {
+ "compressible": true,
+ "extensions": ["php"]
+ },
+ "application/x-install-instructions": {
+ "source": "apache",
+ "extensions": ["install"]
+ },
+ "application/x-ipynb+json": {
+ "compressible": true,
+ "extensions": ["ipynb"]
+ },
+ "application/x-iso9660-image": {
+ "source": "apache",
+ "extensions": ["iso"]
+ },
+ "application/x-iwork-keynote-sffkey": {
+ "extensions": ["key"]
+ },
+ "application/x-iwork-numbers-sffnumbers": {
+ "extensions": ["numbers"]
+ },
+ "application/x-iwork-pages-sffpages": {
+ "extensions": ["pages"]
+ },
+ "application/x-java-archive-diff": {
+ "source": "nginx",
+ "extensions": ["jardiff"]
+ },
+ "application/x-java-jnlp-file": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["jnlp"]
+ },
+ "application/x-javascript": {
+ "compressible": true
+ },
+ "application/x-keepass2": {
+ "extensions": ["kdbx"]
+ },
+ "application/x-latex": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["latex"]
+ },
+ "application/x-lua-bytecode": {
+ "extensions": ["luac"]
+ },
+ "application/x-lzh-compressed": {
+ "source": "apache",
+ "extensions": ["lzh","lha"]
+ },
+ "application/x-makeself": {
+ "source": "nginx",
+ "extensions": ["run"]
+ },
+ "application/x-mie": {
+ "source": "apache",
+ "extensions": ["mie"]
+ },
+ "application/x-mobipocket-ebook": {
+ "source": "apache",
+ "extensions": ["prc","mobi"]
+ },
+ "application/x-mpegurl": {
+ "compressible": false
+ },
+ "application/x-ms-application": {
+ "source": "apache",
+ "extensions": ["application"]
+ },
+ "application/x-ms-shortcut": {
+ "source": "apache",
+ "extensions": ["lnk"]
+ },
+ "application/x-ms-wmd": {
+ "source": "apache",
+ "extensions": ["wmd"]
+ },
+ "application/x-ms-wmz": {
+ "source": "apache",
+ "extensions": ["wmz"]
+ },
+ "application/x-ms-xbap": {
+ "source": "apache",
+ "extensions": ["xbap"]
+ },
+ "application/x-msaccess": {
+ "source": "apache",
+ "extensions": ["mdb"]
+ },
+ "application/x-msbinder": {
+ "source": "apache",
+ "extensions": ["obd"]
+ },
+ "application/x-mscardfile": {
+ "source": "apache",
+ "extensions": ["crd"]
+ },
+ "application/x-msclip": {
+ "source": "apache",
+ "extensions": ["clp"]
+ },
+ "application/x-msdos-program": {
+ "extensions": ["exe"]
+ },
+ "application/x-msdownload": {
+ "source": "apache",
+ "extensions": ["exe","dll","com","bat","msi"]
+ },
+ "application/x-msmediaview": {
+ "source": "apache",
+ "extensions": ["mvb","m13","m14"]
+ },
+ "application/x-msmetafile": {
+ "source": "apache",
+ "extensions": ["wmf","wmz","emf","emz"]
+ },
+ "application/x-msmoney": {
+ "source": "apache",
+ "extensions": ["mny"]
+ },
+ "application/x-mspublisher": {
+ "source": "apache",
+ "extensions": ["pub"]
+ },
+ "application/x-msschedule": {
+ "source": "apache",
+ "extensions": ["scd"]
+ },
+ "application/x-msterminal": {
+ "source": "apache",
+ "extensions": ["trm"]
+ },
+ "application/x-mswrite": {
+ "source": "apache",
+ "extensions": ["wri"]
+ },
+ "application/x-netcdf": {
+ "source": "apache",
+ "extensions": ["nc","cdf"]
+ },
+ "application/x-ns-proxy-autoconfig": {
+ "compressible": true,
+ "extensions": ["pac"]
+ },
+ "application/x-nzb": {
+ "source": "apache",
+ "extensions": ["nzb"]
+ },
+ "application/x-perl": {
+ "source": "nginx",
+ "extensions": ["pl","pm"]
+ },
+ "application/x-pilot": {
+ "source": "nginx",
+ "extensions": ["prc","pdb"]
+ },
+ "application/x-pkcs12": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["p12","pfx"]
+ },
+ "application/x-pkcs7-certificates": {
+ "source": "apache",
+ "extensions": ["p7b","spc"]
+ },
+ "application/x-pkcs7-certreqresp": {
+ "source": "apache",
+ "extensions": ["p7r"]
+ },
+ "application/x-pki-message": {
+ "source": "iana"
+ },
+ "application/x-rar-compressed": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["rar"]
+ },
+ "application/x-redhat-package-manager": {
+ "source": "nginx",
+ "extensions": ["rpm"]
+ },
+ "application/x-research-info-systems": {
+ "source": "apache",
+ "extensions": ["ris"]
+ },
+ "application/x-sea": {
+ "source": "nginx",
+ "extensions": ["sea"]
+ },
+ "application/x-sh": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["sh"]
+ },
+ "application/x-shar": {
+ "source": "apache",
+ "extensions": ["shar"]
+ },
+ "application/x-shockwave-flash": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["swf"]
+ },
+ "application/x-silverlight-app": {
+ "source": "apache",
+ "extensions": ["xap"]
+ },
+ "application/x-sql": {
+ "source": "apache",
+ "extensions": ["sql"]
+ },
+ "application/x-stuffit": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["sit"]
+ },
+ "application/x-stuffitx": {
+ "source": "apache",
+ "extensions": ["sitx"]
+ },
+ "application/x-subrip": {
+ "source": "apache",
+ "extensions": ["srt"]
+ },
+ "application/x-sv4cpio": {
+ "source": "apache",
+ "extensions": ["sv4cpio"]
+ },
+ "application/x-sv4crc": {
+ "source": "apache",
+ "extensions": ["sv4crc"]
+ },
+ "application/x-t3vm-image": {
+ "source": "apache",
+ "extensions": ["t3"]
+ },
+ "application/x-tads": {
+ "source": "apache",
+ "extensions": ["gam"]
+ },
+ "application/x-tar": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["tar"]
+ },
+ "application/x-tcl": {
+ "source": "apache",
+ "extensions": ["tcl","tk"]
+ },
+ "application/x-tex": {
+ "source": "apache",
+ "extensions": ["tex"]
+ },
+ "application/x-tex-tfm": {
+ "source": "apache",
+ "extensions": ["tfm"]
+ },
+ "application/x-texinfo": {
+ "source": "apache",
+ "extensions": ["texinfo","texi"]
+ },
+ "application/x-tgif": {
+ "source": "apache",
+ "extensions": ["obj"]
+ },
+ "application/x-ustar": {
+ "source": "apache",
+ "extensions": ["ustar"]
+ },
+ "application/x-virtualbox-hdd": {
+ "compressible": true,
+ "extensions": ["hdd"]
+ },
+ "application/x-virtualbox-ova": {
+ "compressible": true,
+ "extensions": ["ova"]
+ },
+ "application/x-virtualbox-ovf": {
+ "compressible": true,
+ "extensions": ["ovf"]
+ },
+ "application/x-virtualbox-vbox": {
+ "compressible": true,
+ "extensions": ["vbox"]
+ },
+ "application/x-virtualbox-vbox-extpack": {
+ "compressible": false,
+ "extensions": ["vbox-extpack"]
+ },
+ "application/x-virtualbox-vdi": {
+ "compressible": true,
+ "extensions": ["vdi"]
+ },
+ "application/x-virtualbox-vhd": {
+ "compressible": true,
+ "extensions": ["vhd"]
+ },
+ "application/x-virtualbox-vmdk": {
+ "compressible": true,
+ "extensions": ["vmdk"]
+ },
+ "application/x-wais-source": {
+ "source": "apache",
+ "extensions": ["src"]
+ },
+ "application/x-web-app-manifest+json": {
+ "compressible": true,
+ "extensions": ["webapp"]
+ },
+ "application/x-www-form-urlencoded": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/x-x509-ca-cert": {
+ "source": "iana",
+ "extensions": ["der","crt","pem"]
+ },
+ "application/x-x509-ca-ra-cert": {
+ "source": "iana"
+ },
+ "application/x-x509-next-ca-cert": {
+ "source": "iana"
+ },
+ "application/x-xfig": {
+ "source": "apache",
+ "extensions": ["fig"]
+ },
+ "application/x-xliff+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["xlf"]
+ },
+ "application/x-xpinstall": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["xpi"]
+ },
+ "application/x-xz": {
+ "source": "apache",
+ "extensions": ["xz"]
+ },
+ "application/x-zip-compressed": {
+ "extensions": ["zip"]
+ },
+ "application/x-zmachine": {
+ "source": "apache",
+ "extensions": ["z1","z2","z3","z4","z5","z6","z7","z8"]
+ },
+ "application/x400-bp": {
+ "source": "iana"
+ },
+ "application/xacml+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/xaml+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["xaml"]
+ },
+ "application/xcap-att+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xav"]
+ },
+ "application/xcap-caps+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xca"]
+ },
+ "application/xcap-diff+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xdf"]
+ },
+ "application/xcap-el+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xel"]
+ },
+ "application/xcap-error+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/xcap-ns+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xns"]
+ },
+ "application/xcon-conference-info+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/xcon-conference-info-diff+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/xenc+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xenc"]
+ },
+ "application/xfdf": {
+ "source": "iana",
+ "extensions": ["xfdf"]
+ },
+ "application/xhtml+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xhtml","xht"]
+ },
+ "application/xhtml-voice+xml": {
+ "source": "apache",
+ "compressible": true
+ },
+ "application/xliff+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xlf"]
+ },
+ "application/xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xml","xsl","xsd","rng"]
+ },
+ "application/xml-dtd": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["dtd"]
+ },
+ "application/xml-external-parsed-entity": {
+ "source": "iana"
+ },
+ "application/xml-patch+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/xmpp+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/xop+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xop"]
+ },
+ "application/xproc+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["xpl"]
+ },
+ "application/xslt+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xsl","xslt"]
+ },
+ "application/xspf+xml": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["xspf"]
+ },
+ "application/xv+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["mxml","xhvml","xvml","xvm"]
+ },
+ "application/yaml": {
+ "source": "iana"
+ },
+ "application/yang": {
+ "source": "iana",
+ "extensions": ["yang"]
+ },
+ "application/yang-data+cbor": {
+ "source": "iana"
+ },
+ "application/yang-data+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/yang-data+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/yang-patch+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/yang-patch+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/yang-sid+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "application/yin+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["yin"]
+ },
+ "application/zip": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["zip"]
+ },
+ "application/zip+dotlottie": {
+ "extensions": ["lottie"]
+ },
+ "application/zlib": {
+ "source": "iana"
+ },
+ "application/zstd": {
+ "source": "iana"
+ },
+ "audio/1d-interleaved-parityfec": {
+ "source": "iana"
+ },
+ "audio/32kadpcm": {
+ "source": "iana"
+ },
+ "audio/3gpp": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["3gpp"]
+ },
+ "audio/3gpp2": {
+ "source": "iana"
+ },
+ "audio/aac": {
+ "source": "iana",
+ "extensions": ["adts","aac"]
+ },
+ "audio/ac3": {
+ "source": "iana"
+ },
+ "audio/adpcm": {
+ "source": "apache",
+ "extensions": ["adp"]
+ },
+ "audio/amr": {
+ "source": "iana",
+ "extensions": ["amr"]
+ },
+ "audio/amr-wb": {
+ "source": "iana"
+ },
+ "audio/amr-wb+": {
+ "source": "iana"
+ },
+ "audio/aptx": {
+ "source": "iana"
+ },
+ "audio/asc": {
+ "source": "iana"
+ },
+ "audio/atrac-advanced-lossless": {
+ "source": "iana"
+ },
+ "audio/atrac-x": {
+ "source": "iana"
+ },
+ "audio/atrac3": {
+ "source": "iana"
+ },
+ "audio/basic": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["au","snd"]
+ },
+ "audio/bv16": {
+ "source": "iana"
+ },
+ "audio/bv32": {
+ "source": "iana"
+ },
+ "audio/clearmode": {
+ "source": "iana"
+ },
+ "audio/cn": {
+ "source": "iana"
+ },
+ "audio/dat12": {
+ "source": "iana"
+ },
+ "audio/dls": {
+ "source": "iana"
+ },
+ "audio/dsr-es201108": {
+ "source": "iana"
+ },
+ "audio/dsr-es202050": {
+ "source": "iana"
+ },
+ "audio/dsr-es202211": {
+ "source": "iana"
+ },
+ "audio/dsr-es202212": {
+ "source": "iana"
+ },
+ "audio/dv": {
+ "source": "iana"
+ },
+ "audio/dvi4": {
+ "source": "iana"
+ },
+ "audio/eac3": {
+ "source": "iana"
+ },
+ "audio/encaprtp": {
+ "source": "iana"
+ },
+ "audio/evrc": {
+ "source": "iana"
+ },
+ "audio/evrc-qcp": {
+ "source": "iana"
+ },
+ "audio/evrc0": {
+ "source": "iana"
+ },
+ "audio/evrc1": {
+ "source": "iana"
+ },
+ "audio/evrcb": {
+ "source": "iana"
+ },
+ "audio/evrcb0": {
+ "source": "iana"
+ },
+ "audio/evrcb1": {
+ "source": "iana"
+ },
+ "audio/evrcnw": {
+ "source": "iana"
+ },
+ "audio/evrcnw0": {
+ "source": "iana"
+ },
+ "audio/evrcnw1": {
+ "source": "iana"
+ },
+ "audio/evrcwb": {
+ "source": "iana"
+ },
+ "audio/evrcwb0": {
+ "source": "iana"
+ },
+ "audio/evrcwb1": {
+ "source": "iana"
+ },
+ "audio/evs": {
+ "source": "iana"
+ },
+ "audio/flac": {
+ "source": "iana"
+ },
+ "audio/flexfec": {
+ "source": "iana"
+ },
+ "audio/fwdred": {
+ "source": "iana"
+ },
+ "audio/g711-0": {
+ "source": "iana"
+ },
+ "audio/g719": {
+ "source": "iana"
+ },
+ "audio/g722": {
+ "source": "iana"
+ },
+ "audio/g7221": {
+ "source": "iana"
+ },
+ "audio/g723": {
+ "source": "iana"
+ },
+ "audio/g726-16": {
+ "source": "iana"
+ },
+ "audio/g726-24": {
+ "source": "iana"
+ },
+ "audio/g726-32": {
+ "source": "iana"
+ },
+ "audio/g726-40": {
+ "source": "iana"
+ },
+ "audio/g728": {
+ "source": "iana"
+ },
+ "audio/g729": {
+ "source": "iana"
+ },
+ "audio/g7291": {
+ "source": "iana"
+ },
+ "audio/g729d": {
+ "source": "iana"
+ },
+ "audio/g729e": {
+ "source": "iana"
+ },
+ "audio/gsm": {
+ "source": "iana"
+ },
+ "audio/gsm-efr": {
+ "source": "iana"
+ },
+ "audio/gsm-hr-08": {
+ "source": "iana"
+ },
+ "audio/ilbc": {
+ "source": "iana"
+ },
+ "audio/ip-mr_v2.5": {
+ "source": "iana"
+ },
+ "audio/isac": {
+ "source": "apache"
+ },
+ "audio/l16": {
+ "source": "iana"
+ },
+ "audio/l20": {
+ "source": "iana"
+ },
+ "audio/l24": {
+ "source": "iana",
+ "compressible": false
+ },
+ "audio/l8": {
+ "source": "iana"
+ },
+ "audio/lpc": {
+ "source": "iana"
+ },
+ "audio/matroska": {
+ "source": "iana"
+ },
+ "audio/melp": {
+ "source": "iana"
+ },
+ "audio/melp1200": {
+ "source": "iana"
+ },
+ "audio/melp2400": {
+ "source": "iana"
+ },
+ "audio/melp600": {
+ "source": "iana"
+ },
+ "audio/mhas": {
+ "source": "iana"
+ },
+ "audio/midi": {
+ "source": "apache",
+ "extensions": ["mid","midi","kar","rmi"]
+ },
+ "audio/midi-clip": {
+ "source": "iana"
+ },
+ "audio/mobile-xmf": {
+ "source": "iana",
+ "extensions": ["mxmf"]
+ },
+ "audio/mp3": {
+ "compressible": false,
+ "extensions": ["mp3"]
+ },
+ "audio/mp4": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["m4a","mp4a","m4b"]
+ },
+ "audio/mp4a-latm": {
+ "source": "iana"
+ },
+ "audio/mpa": {
+ "source": "iana"
+ },
+ "audio/mpa-robust": {
+ "source": "iana"
+ },
+ "audio/mpeg": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["mpga","mp2","mp2a","mp3","m2a","m3a"]
+ },
+ "audio/mpeg4-generic": {
+ "source": "iana"
+ },
+ "audio/musepack": {
+ "source": "apache"
+ },
+ "audio/ogg": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["oga","ogg","spx","opus"]
+ },
+ "audio/opus": {
+ "source": "iana"
+ },
+ "audio/parityfec": {
+ "source": "iana"
+ },
+ "audio/pcma": {
+ "source": "iana"
+ },
+ "audio/pcma-wb": {
+ "source": "iana"
+ },
+ "audio/pcmu": {
+ "source": "iana"
+ },
+ "audio/pcmu-wb": {
+ "source": "iana"
+ },
+ "audio/prs.sid": {
+ "source": "iana"
+ },
+ "audio/qcelp": {
+ "source": "iana"
+ },
+ "audio/raptorfec": {
+ "source": "iana"
+ },
+ "audio/red": {
+ "source": "iana"
+ },
+ "audio/rtp-enc-aescm128": {
+ "source": "iana"
+ },
+ "audio/rtp-midi": {
+ "source": "iana"
+ },
+ "audio/rtploopback": {
+ "source": "iana"
+ },
+ "audio/rtx": {
+ "source": "iana"
+ },
+ "audio/s3m": {
+ "source": "apache",
+ "extensions": ["s3m"]
+ },
+ "audio/scip": {
+ "source": "iana"
+ },
+ "audio/silk": {
+ "source": "apache",
+ "extensions": ["sil"]
+ },
+ "audio/smv": {
+ "source": "iana"
+ },
+ "audio/smv-qcp": {
+ "source": "iana"
+ },
+ "audio/smv0": {
+ "source": "iana"
+ },
+ "audio/sofa": {
+ "source": "iana"
+ },
+ "audio/sp-midi": {
+ "source": "iana"
+ },
+ "audio/speex": {
+ "source": "iana"
+ },
+ "audio/t140c": {
+ "source": "iana"
+ },
+ "audio/t38": {
+ "source": "iana"
+ },
+ "audio/telephone-event": {
+ "source": "iana"
+ },
+ "audio/tetra_acelp": {
+ "source": "iana"
+ },
+ "audio/tetra_acelp_bb": {
+ "source": "iana"
+ },
+ "audio/tone": {
+ "source": "iana"
+ },
+ "audio/tsvcis": {
+ "source": "iana"
+ },
+ "audio/uemclip": {
+ "source": "iana"
+ },
+ "audio/ulpfec": {
+ "source": "iana"
+ },
+ "audio/usac": {
+ "source": "iana"
+ },
+ "audio/vdvi": {
+ "source": "iana"
+ },
+ "audio/vmr-wb": {
+ "source": "iana"
+ },
+ "audio/vnd.3gpp.iufp": {
+ "source": "iana"
+ },
+ "audio/vnd.4sb": {
+ "source": "iana"
+ },
+ "audio/vnd.audiokoz": {
+ "source": "iana"
+ },
+ "audio/vnd.celp": {
+ "source": "iana"
+ },
+ "audio/vnd.cisco.nse": {
+ "source": "iana"
+ },
+ "audio/vnd.cmles.radio-events": {
+ "source": "iana"
+ },
+ "audio/vnd.cns.anp1": {
+ "source": "iana"
+ },
+ "audio/vnd.cns.inf1": {
+ "source": "iana"
+ },
+ "audio/vnd.dece.audio": {
+ "source": "iana",
+ "extensions": ["uva","uvva"]
+ },
+ "audio/vnd.digital-winds": {
+ "source": "iana",
+ "extensions": ["eol"]
+ },
+ "audio/vnd.dlna.adts": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.heaac.1": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.heaac.2": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.mlp": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.mps": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.pl2": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.pl2x": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.pl2z": {
+ "source": "iana"
+ },
+ "audio/vnd.dolby.pulse.1": {
+ "source": "iana"
+ },
+ "audio/vnd.dra": {
+ "source": "iana",
+ "extensions": ["dra"]
+ },
+ "audio/vnd.dts": {
+ "source": "iana",
+ "extensions": ["dts"]
+ },
+ "audio/vnd.dts.hd": {
+ "source": "iana",
+ "extensions": ["dtshd"]
+ },
+ "audio/vnd.dts.uhd": {
+ "source": "iana"
+ },
+ "audio/vnd.dvb.file": {
+ "source": "iana"
+ },
+ "audio/vnd.everad.plj": {
+ "source": "iana"
+ },
+ "audio/vnd.hns.audio": {
+ "source": "iana"
+ },
+ "audio/vnd.lucent.voice": {
+ "source": "iana",
+ "extensions": ["lvp"]
+ },
+ "audio/vnd.ms-playready.media.pya": {
+ "source": "iana",
+ "extensions": ["pya"]
+ },
+ "audio/vnd.nokia.mobile-xmf": {
+ "source": "iana"
+ },
+ "audio/vnd.nortel.vbk": {
+ "source": "iana"
+ },
+ "audio/vnd.nuera.ecelp4800": {
+ "source": "iana",
+ "extensions": ["ecelp4800"]
+ },
+ "audio/vnd.nuera.ecelp7470": {
+ "source": "iana",
+ "extensions": ["ecelp7470"]
+ },
+ "audio/vnd.nuera.ecelp9600": {
+ "source": "iana",
+ "extensions": ["ecelp9600"]
+ },
+ "audio/vnd.octel.sbc": {
+ "source": "iana"
+ },
+ "audio/vnd.presonus.multitrack": {
+ "source": "iana"
+ },
+ "audio/vnd.qcelp": {
+ "source": "apache"
+ },
+ "audio/vnd.rhetorex.32kadpcm": {
+ "source": "iana"
+ },
+ "audio/vnd.rip": {
+ "source": "iana",
+ "extensions": ["rip"]
+ },
+ "audio/vnd.rn-realaudio": {
+ "compressible": false
+ },
+ "audio/vnd.sealedmedia.softseal.mpeg": {
+ "source": "iana"
+ },
+ "audio/vnd.vmx.cvsd": {
+ "source": "iana"
+ },
+ "audio/vnd.wave": {
+ "compressible": false
+ },
+ "audio/vorbis": {
+ "source": "iana",
+ "compressible": false
+ },
+ "audio/vorbis-config": {
+ "source": "iana"
+ },
+ "audio/wav": {
+ "compressible": false,
+ "extensions": ["wav"]
+ },
+ "audio/wave": {
+ "compressible": false,
+ "extensions": ["wav"]
+ },
+ "audio/webm": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["weba"]
+ },
+ "audio/x-aac": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["aac"]
+ },
+ "audio/x-aiff": {
+ "source": "apache",
+ "extensions": ["aif","aiff","aifc"]
+ },
+ "audio/x-caf": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["caf"]
+ },
+ "audio/x-flac": {
+ "source": "apache",
+ "extensions": ["flac"]
+ },
+ "audio/x-m4a": {
+ "source": "nginx",
+ "extensions": ["m4a"]
+ },
+ "audio/x-matroska": {
+ "source": "apache",
+ "extensions": ["mka"]
+ },
+ "audio/x-mpegurl": {
+ "source": "apache",
+ "extensions": ["m3u"]
+ },
+ "audio/x-ms-wax": {
+ "source": "apache",
+ "extensions": ["wax"]
+ },
+ "audio/x-ms-wma": {
+ "source": "apache",
+ "extensions": ["wma"]
+ },
+ "audio/x-pn-realaudio": {
+ "source": "apache",
+ "extensions": ["ram","ra"]
+ },
+ "audio/x-pn-realaudio-plugin": {
+ "source": "apache",
+ "extensions": ["rmp"]
+ },
+ "audio/x-realaudio": {
+ "source": "nginx",
+ "extensions": ["ra"]
+ },
+ "audio/x-tta": {
+ "source": "apache"
+ },
+ "audio/x-wav": {
+ "source": "apache",
+ "extensions": ["wav"]
+ },
+ "audio/xm": {
+ "source": "apache",
+ "extensions": ["xm"]
+ },
+ "chemical/x-cdx": {
+ "source": "apache",
+ "extensions": ["cdx"]
+ },
+ "chemical/x-cif": {
+ "source": "apache",
+ "extensions": ["cif"]
+ },
+ "chemical/x-cmdf": {
+ "source": "apache",
+ "extensions": ["cmdf"]
+ },
+ "chemical/x-cml": {
+ "source": "apache",
+ "extensions": ["cml"]
+ },
+ "chemical/x-csml": {
+ "source": "apache",
+ "extensions": ["csml"]
+ },
+ "chemical/x-pdb": {
+ "source": "apache"
+ },
+ "chemical/x-xyz": {
+ "source": "apache",
+ "extensions": ["xyz"]
+ },
+ "font/collection": {
+ "source": "iana",
+ "extensions": ["ttc"]
+ },
+ "font/otf": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["otf"]
+ },
+ "font/sfnt": {
+ "source": "iana"
+ },
+ "font/ttf": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["ttf"]
+ },
+ "font/woff": {
+ "source": "iana",
+ "extensions": ["woff"]
+ },
+ "font/woff2": {
+ "source": "iana",
+ "extensions": ["woff2"]
+ },
+ "image/aces": {
+ "source": "iana",
+ "extensions": ["exr"]
+ },
+ "image/apng": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["apng"]
+ },
+ "image/avci": {
+ "source": "iana",
+ "extensions": ["avci"]
+ },
+ "image/avcs": {
+ "source": "iana",
+ "extensions": ["avcs"]
+ },
+ "image/avif": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["avif"]
+ },
+ "image/bmp": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["bmp","dib"]
+ },
+ "image/cgm": {
+ "source": "iana",
+ "extensions": ["cgm"]
+ },
+ "image/dicom-rle": {
+ "source": "iana",
+ "extensions": ["drle"]
+ },
+ "image/dpx": {
+ "source": "iana",
+ "extensions": ["dpx"]
+ },
+ "image/emf": {
+ "source": "iana",
+ "extensions": ["emf"]
+ },
+ "image/fits": {
+ "source": "iana",
+ "extensions": ["fits"]
+ },
+ "image/g3fax": {
+ "source": "iana",
+ "extensions": ["g3"]
+ },
+ "image/gif": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["gif"]
+ },
+ "image/heic": {
+ "source": "iana",
+ "extensions": ["heic"]
+ },
+ "image/heic-sequence": {
+ "source": "iana",
+ "extensions": ["heics"]
+ },
+ "image/heif": {
+ "source": "iana",
+ "extensions": ["heif"]
+ },
+ "image/heif-sequence": {
+ "source": "iana",
+ "extensions": ["heifs"]
+ },
+ "image/hej2k": {
+ "source": "iana",
+ "extensions": ["hej2"]
+ },
+ "image/ief": {
+ "source": "iana",
+ "extensions": ["ief"]
+ },
+ "image/j2c": {
+ "source": "iana"
+ },
+ "image/jaii": {
+ "source": "iana",
+ "extensions": ["jaii"]
+ },
+ "image/jais": {
+ "source": "iana",
+ "extensions": ["jais"]
+ },
+ "image/jls": {
+ "source": "iana",
+ "extensions": ["jls"]
+ },
+ "image/jp2": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["jp2","jpg2"]
+ },
+ "image/jpeg": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["jpg","jpeg","jpe"]
+ },
+ "image/jph": {
+ "source": "iana",
+ "extensions": ["jph"]
+ },
+ "image/jphc": {
+ "source": "iana",
+ "extensions": ["jhc"]
+ },
+ "image/jpm": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["jpm","jpgm"]
+ },
+ "image/jpx": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["jpx","jpf"]
+ },
+ "image/jxl": {
+ "source": "iana",
+ "extensions": ["jxl"]
+ },
+ "image/jxr": {
+ "source": "iana",
+ "extensions": ["jxr"]
+ },
+ "image/jxra": {
+ "source": "iana",
+ "extensions": ["jxra"]
+ },
+ "image/jxrs": {
+ "source": "iana",
+ "extensions": ["jxrs"]
+ },
+ "image/jxs": {
+ "source": "iana",
+ "extensions": ["jxs"]
+ },
+ "image/jxsc": {
+ "source": "iana",
+ "extensions": ["jxsc"]
+ },
+ "image/jxsi": {
+ "source": "iana",
+ "extensions": ["jxsi"]
+ },
+ "image/jxss": {
+ "source": "iana",
+ "extensions": ["jxss"]
+ },
+ "image/ktx": {
+ "source": "iana",
+ "extensions": ["ktx"]
+ },
+ "image/ktx2": {
+ "source": "iana",
+ "extensions": ["ktx2"]
+ },
+ "image/naplps": {
+ "source": "iana"
+ },
+ "image/pjpeg": {
+ "compressible": false,
+ "extensions": ["jfif"]
+ },
+ "image/png": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["png"]
+ },
+ "image/prs.btif": {
+ "source": "iana",
+ "extensions": ["btif","btf"]
+ },
+ "image/prs.pti": {
+ "source": "iana",
+ "extensions": ["pti"]
+ },
+ "image/pwg-raster": {
+ "source": "iana"
+ },
+ "image/sgi": {
+ "source": "apache",
+ "extensions": ["sgi"]
+ },
+ "image/svg+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["svg","svgz"]
+ },
+ "image/t38": {
+ "source": "iana",
+ "extensions": ["t38"]
+ },
+ "image/tiff": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["tif","tiff"]
+ },
+ "image/tiff-fx": {
+ "source": "iana",
+ "extensions": ["tfx"]
+ },
+ "image/vnd.adobe.photoshop": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["psd"]
+ },
+ "image/vnd.airzip.accelerator.azv": {
+ "source": "iana",
+ "extensions": ["azv"]
+ },
+ "image/vnd.clip": {
+ "source": "iana"
+ },
+ "image/vnd.cns.inf2": {
+ "source": "iana"
+ },
+ "image/vnd.dece.graphic": {
+ "source": "iana",
+ "extensions": ["uvi","uvvi","uvg","uvvg"]
+ },
+ "image/vnd.djvu": {
+ "source": "iana",
+ "extensions": ["djvu","djv"]
+ },
+ "image/vnd.dvb.subtitle": {
+ "source": "iana",
+ "extensions": ["sub"]
+ },
+ "image/vnd.dwg": {
+ "source": "iana",
+ "extensions": ["dwg"]
+ },
+ "image/vnd.dxf": {
+ "source": "iana",
+ "extensions": ["dxf"]
+ },
+ "image/vnd.fastbidsheet": {
+ "source": "iana",
+ "extensions": ["fbs"]
+ },
+ "image/vnd.fpx": {
+ "source": "iana",
+ "extensions": ["fpx"]
+ },
+ "image/vnd.fst": {
+ "source": "iana",
+ "extensions": ["fst"]
+ },
+ "image/vnd.fujixerox.edmics-mmr": {
+ "source": "iana",
+ "extensions": ["mmr"]
+ },
+ "image/vnd.fujixerox.edmics-rlc": {
+ "source": "iana",
+ "extensions": ["rlc"]
+ },
+ "image/vnd.globalgraphics.pgb": {
+ "source": "iana"
+ },
+ "image/vnd.microsoft.icon": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["ico"]
+ },
+ "image/vnd.mix": {
+ "source": "iana"
+ },
+ "image/vnd.mozilla.apng": {
+ "source": "iana"
+ },
+ "image/vnd.ms-dds": {
+ "compressible": true,
+ "extensions": ["dds"]
+ },
+ "image/vnd.ms-modi": {
+ "source": "iana",
+ "extensions": ["mdi"]
+ },
+ "image/vnd.ms-photo": {
+ "source": "apache",
+ "extensions": ["wdp"]
+ },
+ "image/vnd.net-fpx": {
+ "source": "iana",
+ "extensions": ["npx"]
+ },
+ "image/vnd.pco.b16": {
+ "source": "iana",
+ "extensions": ["b16"]
+ },
+ "image/vnd.radiance": {
+ "source": "iana"
+ },
+ "image/vnd.sealed.png": {
+ "source": "iana"
+ },
+ "image/vnd.sealedmedia.softseal.gif": {
+ "source": "iana"
+ },
+ "image/vnd.sealedmedia.softseal.jpg": {
+ "source": "iana"
+ },
+ "image/vnd.svf": {
+ "source": "iana"
+ },
+ "image/vnd.tencent.tap": {
+ "source": "iana",
+ "extensions": ["tap"]
+ },
+ "image/vnd.valve.source.texture": {
+ "source": "iana",
+ "extensions": ["vtf"]
+ },
+ "image/vnd.wap.wbmp": {
+ "source": "iana",
+ "extensions": ["wbmp"]
+ },
+ "image/vnd.xiff": {
+ "source": "iana",
+ "extensions": ["xif"]
+ },
+ "image/vnd.zbrush.pcx": {
+ "source": "iana",
+ "extensions": ["pcx"]
+ },
+ "image/webp": {
+ "source": "iana",
+ "extensions": ["webp"]
+ },
+ "image/wmf": {
+ "source": "iana",
+ "extensions": ["wmf"]
+ },
+ "image/x-3ds": {
+ "source": "apache",
+ "extensions": ["3ds"]
+ },
+ "image/x-adobe-dng": {
+ "extensions": ["dng"]
+ },
+ "image/x-cmu-raster": {
+ "source": "apache",
+ "extensions": ["ras"]
+ },
+ "image/x-cmx": {
+ "source": "apache",
+ "extensions": ["cmx"]
+ },
+ "image/x-emf": {
+ "source": "iana"
+ },
+ "image/x-freehand": {
+ "source": "apache",
+ "extensions": ["fh","fhc","fh4","fh5","fh7"]
+ },
+ "image/x-icon": {
+ "source": "apache",
+ "compressible": true,
+ "extensions": ["ico"]
+ },
+ "image/x-jng": {
+ "source": "nginx",
+ "extensions": ["jng"]
+ },
+ "image/x-mrsid-image": {
+ "source": "apache",
+ "extensions": ["sid"]
+ },
+ "image/x-ms-bmp": {
+ "source": "nginx",
+ "compressible": true,
+ "extensions": ["bmp"]
+ },
+ "image/x-pcx": {
+ "source": "apache",
+ "extensions": ["pcx"]
+ },
+ "image/x-pict": {
+ "source": "apache",
+ "extensions": ["pic","pct"]
+ },
+ "image/x-portable-anymap": {
+ "source": "apache",
+ "extensions": ["pnm"]
+ },
+ "image/x-portable-bitmap": {
+ "source": "apache",
+ "extensions": ["pbm"]
+ },
+ "image/x-portable-graymap": {
+ "source": "apache",
+ "extensions": ["pgm"]
+ },
+ "image/x-portable-pixmap": {
+ "source": "apache",
+ "extensions": ["ppm"]
+ },
+ "image/x-rgb": {
+ "source": "apache",
+ "extensions": ["rgb"]
+ },
+ "image/x-tga": {
+ "source": "apache",
+ "extensions": ["tga"]
+ },
+ "image/x-wmf": {
+ "source": "iana"
+ },
+ "image/x-xbitmap": {
+ "source": "apache",
+ "extensions": ["xbm"]
+ },
+ "image/x-xcf": {
+ "compressible": false
+ },
+ "image/x-xpixmap": {
+ "source": "apache",
+ "extensions": ["xpm"]
+ },
+ "image/x-xwindowdump": {
+ "source": "apache",
+ "extensions": ["xwd"]
+ },
+ "message/bhttp": {
+ "source": "iana"
+ },
+ "message/cpim": {
+ "source": "iana"
+ },
+ "message/delivery-status": {
+ "source": "iana"
+ },
+ "message/disposition-notification": {
+ "source": "iana",
+ "extensions": [
+ "disposition-notification"
+ ]
+ },
+ "message/external-body": {
+ "source": "iana"
+ },
+ "message/feedback-report": {
+ "source": "iana"
+ },
+ "message/global": {
+ "source": "iana",
+ "extensions": ["u8msg"]
+ },
+ "message/global-delivery-status": {
+ "source": "iana",
+ "extensions": ["u8dsn"]
+ },
+ "message/global-disposition-notification": {
+ "source": "iana",
+ "extensions": ["u8mdn"]
+ },
+ "message/global-headers": {
+ "source": "iana",
+ "extensions": ["u8hdr"]
+ },
+ "message/http": {
+ "source": "iana",
+ "compressible": false
+ },
+ "message/imdn+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "message/mls": {
+ "source": "iana"
+ },
+ "message/news": {
+ "source": "apache"
+ },
+ "message/ohttp-req": {
+ "source": "iana"
+ },
+ "message/ohttp-res": {
+ "source": "iana"
+ },
+ "message/partial": {
+ "source": "iana",
+ "compressible": false
+ },
+ "message/rfc822": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["eml","mime","mht","mhtml"]
+ },
+ "message/s-http": {
+ "source": "apache"
+ },
+ "message/sip": {
+ "source": "iana"
+ },
+ "message/sipfrag": {
+ "source": "iana"
+ },
+ "message/tracking-status": {
+ "source": "iana"
+ },
+ "message/vnd.si.simp": {
+ "source": "apache"
+ },
+ "message/vnd.wfa.wsc": {
+ "source": "iana",
+ "extensions": ["wsc"]
+ },
+ "model/3mf": {
+ "source": "iana",
+ "extensions": ["3mf"]
+ },
+ "model/e57": {
+ "source": "iana"
+ },
+ "model/gltf+json": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["gltf"]
+ },
+ "model/gltf-binary": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["glb"]
+ },
+ "model/iges": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["igs","iges"]
+ },
+ "model/jt": {
+ "source": "iana",
+ "extensions": ["jt"]
+ },
+ "model/mesh": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["msh","mesh","silo"]
+ },
+ "model/mtl": {
+ "source": "iana",
+ "extensions": ["mtl"]
+ },
+ "model/obj": {
+ "source": "iana",
+ "extensions": ["obj"]
+ },
+ "model/prc": {
+ "source": "iana",
+ "extensions": ["prc"]
+ },
+ "model/step": {
+ "source": "iana",
+ "extensions": ["step","stp","stpnc","p21","210"]
+ },
+ "model/step+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["stpx"]
+ },
+ "model/step+zip": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["stpz"]
+ },
+ "model/step-xml+zip": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["stpxz"]
+ },
+ "model/stl": {
+ "source": "iana",
+ "extensions": ["stl"]
+ },
+ "model/u3d": {
+ "source": "iana",
+ "extensions": ["u3d"]
+ },
+ "model/vnd.bary": {
+ "source": "iana",
+ "extensions": ["bary"]
+ },
+ "model/vnd.cld": {
+ "source": "iana",
+ "extensions": ["cld"]
+ },
+ "model/vnd.collada+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["dae"]
+ },
+ "model/vnd.dwf": {
+ "source": "iana",
+ "extensions": ["dwf"]
+ },
+ "model/vnd.flatland.3dml": {
+ "source": "iana"
+ },
+ "model/vnd.gdl": {
+ "source": "iana",
+ "extensions": ["gdl"]
+ },
+ "model/vnd.gs-gdl": {
+ "source": "apache"
+ },
+ "model/vnd.gs.gdl": {
+ "source": "iana"
+ },
+ "model/vnd.gtw": {
+ "source": "iana",
+ "extensions": ["gtw"]
+ },
+ "model/vnd.moml+xml": {
+ "source": "iana",
+ "compressible": true
+ },
+ "model/vnd.mts": {
+ "source": "iana",
+ "extensions": ["mts"]
+ },
+ "model/vnd.opengex": {
+ "source": "iana",
+ "extensions": ["ogex"]
+ },
+ "model/vnd.parasolid.transmit.binary": {
+ "source": "iana",
+ "extensions": ["x_b"]
+ },
+ "model/vnd.parasolid.transmit.text": {
+ "source": "iana",
+ "extensions": ["x_t"]
+ },
+ "model/vnd.pytha.pyox": {
+ "source": "iana",
+ "extensions": ["pyo","pyox"]
+ },
+ "model/vnd.rosette.annotated-data-model": {
+ "source": "iana"
+ },
+ "model/vnd.sap.vds": {
+ "source": "iana",
+ "extensions": ["vds"]
+ },
+ "model/vnd.usda": {
+ "source": "iana",
+ "extensions": ["usda"]
+ },
+ "model/vnd.usdz+zip": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["usdz"]
+ },
+ "model/vnd.valve.source.compiled-map": {
+ "source": "iana",
+ "extensions": ["bsp"]
+ },
+ "model/vnd.vtu": {
+ "source": "iana",
+ "extensions": ["vtu"]
+ },
+ "model/vrml": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["wrl","vrml"]
+ },
+ "model/x3d+binary": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["x3db","x3dbz"]
+ },
+ "model/x3d+fastinfoset": {
+ "source": "iana",
+ "extensions": ["x3db"]
+ },
+ "model/x3d+vrml": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["x3dv","x3dvz"]
+ },
+ "model/x3d+xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["x3d","x3dz"]
+ },
+ "model/x3d-vrml": {
+ "source": "iana",
+ "extensions": ["x3dv"]
+ },
+ "multipart/alternative": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/appledouble": {
+ "source": "iana"
+ },
+ "multipart/byteranges": {
+ "source": "iana"
+ },
+ "multipart/digest": {
+ "source": "iana"
+ },
+ "multipart/encrypted": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/form-data": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/header-set": {
+ "source": "iana"
+ },
+ "multipart/mixed": {
+ "source": "iana"
+ },
+ "multipart/multilingual": {
+ "source": "iana"
+ },
+ "multipart/parallel": {
+ "source": "iana"
+ },
+ "multipart/related": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/report": {
+ "source": "iana"
+ },
+ "multipart/signed": {
+ "source": "iana",
+ "compressible": false
+ },
+ "multipart/vnd.bint.med-plus": {
+ "source": "iana"
+ },
+ "multipart/voice-message": {
+ "source": "iana"
+ },
+ "multipart/x-mixed-replace": {
+ "source": "iana"
+ },
+ "text/1d-interleaved-parityfec": {
+ "source": "iana"
+ },
+ "text/cache-manifest": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["appcache","manifest"]
+ },
+ "text/calendar": {
+ "source": "iana",
+ "extensions": ["ics","ifb"]
+ },
+ "text/calender": {
+ "compressible": true
+ },
+ "text/cmd": {
+ "compressible": true
+ },
+ "text/coffeescript": {
+ "extensions": ["coffee","litcoffee"]
+ },
+ "text/cql": {
+ "source": "iana"
+ },
+ "text/cql-expression": {
+ "source": "iana"
+ },
+ "text/cql-identifier": {
+ "source": "iana"
+ },
+ "text/css": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["css"]
+ },
+ "text/csv": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["csv"]
+ },
+ "text/csv-schema": {
+ "source": "iana"
+ },
+ "text/directory": {
+ "source": "iana"
+ },
+ "text/dns": {
+ "source": "iana"
+ },
+ "text/ecmascript": {
+ "source": "apache"
+ },
+ "text/encaprtp": {
+ "source": "iana"
+ },
+ "text/enriched": {
+ "source": "iana"
+ },
+ "text/fhirpath": {
+ "source": "iana"
+ },
+ "text/flexfec": {
+ "source": "iana"
+ },
+ "text/fwdred": {
+ "source": "iana"
+ },
+ "text/gff3": {
+ "source": "iana"
+ },
+ "text/grammar-ref-list": {
+ "source": "iana"
+ },
+ "text/hl7v2": {
+ "source": "iana"
+ },
+ "text/html": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["html","htm","shtml"]
+ },
+ "text/jade": {
+ "extensions": ["jade"]
+ },
+ "text/javascript": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["js","mjs"]
+ },
+ "text/jcr-cnd": {
+ "source": "iana"
+ },
+ "text/jsx": {
+ "compressible": true,
+ "extensions": ["jsx"]
+ },
+ "text/less": {
+ "compressible": true,
+ "extensions": ["less"]
+ },
+ "text/markdown": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["md","markdown"]
+ },
+ "text/mathml": {
+ "source": "nginx",
+ "extensions": ["mml"]
+ },
+ "text/mdx": {
+ "compressible": true,
+ "extensions": ["mdx"]
+ },
+ "text/mizar": {
+ "source": "iana"
+ },
+ "text/n3": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["n3"]
+ },
+ "text/parameters": {
+ "source": "iana",
+ "charset": "UTF-8"
+ },
+ "text/parityfec": {
+ "source": "iana"
+ },
+ "text/plain": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["txt","text","conf","def","list","log","in","ini"]
+ },
+ "text/provenance-notation": {
+ "source": "iana",
+ "charset": "UTF-8"
+ },
+ "text/prs.fallenstein.rst": {
+ "source": "iana"
+ },
+ "text/prs.lines.tag": {
+ "source": "iana",
+ "extensions": ["dsc"]
+ },
+ "text/prs.prop.logic": {
+ "source": "iana"
+ },
+ "text/prs.texi": {
+ "source": "iana"
+ },
+ "text/raptorfec": {
+ "source": "iana"
+ },
+ "text/red": {
+ "source": "iana"
+ },
+ "text/rfc822-headers": {
+ "source": "iana"
+ },
+ "text/richtext": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rtx"]
+ },
+ "text/rtf": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["rtf"]
+ },
+ "text/rtp-enc-aescm128": {
+ "source": "iana"
+ },
+ "text/rtploopback": {
+ "source": "iana"
+ },
+ "text/rtx": {
+ "source": "iana"
+ },
+ "text/sgml": {
+ "source": "iana",
+ "extensions": ["sgml","sgm"]
+ },
+ "text/shaclc": {
+ "source": "iana"
+ },
+ "text/shex": {
+ "source": "iana",
+ "extensions": ["shex"]
+ },
+ "text/slim": {
+ "extensions": ["slim","slm"]
+ },
+ "text/spdx": {
+ "source": "iana",
+ "extensions": ["spdx"]
+ },
+ "text/strings": {
+ "source": "iana"
+ },
+ "text/stylus": {
+ "extensions": ["stylus","styl"]
+ },
+ "text/t140": {
+ "source": "iana"
+ },
+ "text/tab-separated-values": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["tsv"]
+ },
+ "text/troff": {
+ "source": "iana",
+ "extensions": ["t","tr","roff","man","me","ms"]
+ },
+ "text/turtle": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "extensions": ["ttl"]
+ },
+ "text/ulpfec": {
+ "source": "iana"
+ },
+ "text/uri-list": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["uri","uris","urls"]
+ },
+ "text/vcard": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["vcard"]
+ },
+ "text/vnd.a": {
+ "source": "iana"
+ },
+ "text/vnd.abc": {
+ "source": "iana"
+ },
+ "text/vnd.ascii-art": {
+ "source": "iana"
+ },
+ "text/vnd.curl": {
+ "source": "iana",
+ "extensions": ["curl"]
+ },
+ "text/vnd.curl.dcurl": {
+ "source": "apache",
+ "extensions": ["dcurl"]
+ },
+ "text/vnd.curl.mcurl": {
+ "source": "apache",
+ "extensions": ["mcurl"]
+ },
+ "text/vnd.curl.scurl": {
+ "source": "apache",
+ "extensions": ["scurl"]
+ },
+ "text/vnd.debian.copyright": {
+ "source": "iana",
+ "charset": "UTF-8"
+ },
+ "text/vnd.dmclientscript": {
+ "source": "iana"
+ },
+ "text/vnd.dvb.subtitle": {
+ "source": "iana",
+ "extensions": ["sub"]
+ },
+ "text/vnd.esmertec.theme-descriptor": {
+ "source": "iana",
+ "charset": "UTF-8"
+ },
+ "text/vnd.exchangeable": {
+ "source": "iana"
+ },
+ "text/vnd.familysearch.gedcom": {
+ "source": "iana",
+ "extensions": ["ged"]
+ },
+ "text/vnd.ficlab.flt": {
+ "source": "iana"
+ },
+ "text/vnd.fly": {
+ "source": "iana",
+ "extensions": ["fly"]
+ },
+ "text/vnd.fmi.flexstor": {
+ "source": "iana",
+ "extensions": ["flx"]
+ },
+ "text/vnd.gml": {
+ "source": "iana"
+ },
+ "text/vnd.graphviz": {
+ "source": "iana",
+ "extensions": ["gv"]
+ },
+ "text/vnd.hans": {
+ "source": "iana"
+ },
+ "text/vnd.hgl": {
+ "source": "iana"
+ },
+ "text/vnd.in3d.3dml": {
+ "source": "iana",
+ "extensions": ["3dml"]
+ },
+ "text/vnd.in3d.spot": {
+ "source": "iana",
+ "extensions": ["spot"]
+ },
+ "text/vnd.iptc.newsml": {
+ "source": "iana"
+ },
+ "text/vnd.iptc.nitf": {
+ "source": "iana"
+ },
+ "text/vnd.latex-z": {
+ "source": "iana"
+ },
+ "text/vnd.motorola.reflex": {
+ "source": "iana"
+ },
+ "text/vnd.ms-mediapackage": {
+ "source": "iana"
+ },
+ "text/vnd.net2phone.commcenter.command": {
+ "source": "iana"
+ },
+ "text/vnd.radisys.msml-basic-layout": {
+ "source": "iana"
+ },
+ "text/vnd.senx.warpscript": {
+ "source": "iana"
+ },
+ "text/vnd.si.uricatalogue": {
+ "source": "apache"
+ },
+ "text/vnd.sosi": {
+ "source": "iana"
+ },
+ "text/vnd.sun.j2me.app-descriptor": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "extensions": ["jad"]
+ },
+ "text/vnd.trolltech.linguist": {
+ "source": "iana",
+ "charset": "UTF-8"
+ },
+ "text/vnd.vcf": {
+ "source": "iana"
+ },
+ "text/vnd.wap.si": {
+ "source": "iana"
+ },
+ "text/vnd.wap.sl": {
+ "source": "iana"
+ },
+ "text/vnd.wap.wml": {
+ "source": "iana",
+ "extensions": ["wml"]
+ },
+ "text/vnd.wap.wmlscript": {
+ "source": "iana",
+ "extensions": ["wmls"]
+ },
+ "text/vnd.zoo.kcl": {
+ "source": "iana"
+ },
+ "text/vtt": {
+ "source": "iana",
+ "charset": "UTF-8",
+ "compressible": true,
+ "extensions": ["vtt"]
+ },
+ "text/wgsl": {
+ "source": "iana",
+ "extensions": ["wgsl"]
+ },
+ "text/x-asm": {
+ "source": "apache",
+ "extensions": ["s","asm"]
+ },
+ "text/x-c": {
+ "source": "apache",
+ "extensions": ["c","cc","cxx","cpp","h","hh","dic"]
+ },
+ "text/x-component": {
+ "source": "nginx",
+ "extensions": ["htc"]
+ },
+ "text/x-fortran": {
+ "source": "apache",
+ "extensions": ["f","for","f77","f90"]
+ },
+ "text/x-gwt-rpc": {
+ "compressible": true
+ },
+ "text/x-handlebars-template": {
+ "extensions": ["hbs"]
+ },
+ "text/x-java-source": {
+ "source": "apache",
+ "extensions": ["java"]
+ },
+ "text/x-jquery-tmpl": {
+ "compressible": true
+ },
+ "text/x-lua": {
+ "extensions": ["lua"]
+ },
+ "text/x-markdown": {
+ "compressible": true,
+ "extensions": ["mkd"]
+ },
+ "text/x-nfo": {
+ "source": "apache",
+ "extensions": ["nfo"]
+ },
+ "text/x-opml": {
+ "source": "apache",
+ "extensions": ["opml"]
+ },
+ "text/x-org": {
+ "compressible": true,
+ "extensions": ["org"]
+ },
+ "text/x-pascal": {
+ "source": "apache",
+ "extensions": ["p","pas"]
+ },
+ "text/x-processing": {
+ "compressible": true,
+ "extensions": ["pde"]
+ },
+ "text/x-sass": {
+ "extensions": ["sass"]
+ },
+ "text/x-scss": {
+ "extensions": ["scss"]
+ },
+ "text/x-setext": {
+ "source": "apache",
+ "extensions": ["etx"]
+ },
+ "text/x-sfv": {
+ "source": "apache",
+ "extensions": ["sfv"]
+ },
+ "text/x-suse-ymp": {
+ "compressible": true,
+ "extensions": ["ymp"]
+ },
+ "text/x-uuencode": {
+ "source": "apache",
+ "extensions": ["uu"]
+ },
+ "text/x-vcalendar": {
+ "source": "apache",
+ "extensions": ["vcs"]
+ },
+ "text/x-vcard": {
+ "source": "apache",
+ "extensions": ["vcf"]
+ },
+ "text/xml": {
+ "source": "iana",
+ "compressible": true,
+ "extensions": ["xml"]
+ },
+ "text/xml-external-parsed-entity": {
+ "source": "iana"
+ },
+ "text/yaml": {
+ "compressible": true,
+ "extensions": ["yaml","yml"]
+ },
+ "video/1d-interleaved-parityfec": {
+ "source": "iana"
+ },
+ "video/3gpp": {
+ "source": "iana",
+ "extensions": ["3gp","3gpp"]
+ },
+ "video/3gpp-tt": {
+ "source": "iana"
+ },
+ "video/3gpp2": {
+ "source": "iana",
+ "extensions": ["3g2"]
+ },
+ "video/av1": {
+ "source": "iana"
+ },
+ "video/bmpeg": {
+ "source": "iana"
+ },
+ "video/bt656": {
+ "source": "iana"
+ },
+ "video/celb": {
+ "source": "iana"
+ },
+ "video/dv": {
+ "source": "iana"
+ },
+ "video/encaprtp": {
+ "source": "iana"
+ },
+ "video/evc": {
+ "source": "iana"
+ },
+ "video/ffv1": {
+ "source": "iana"
+ },
+ "video/flexfec": {
+ "source": "iana"
+ },
+ "video/h261": {
+ "source": "iana",
+ "extensions": ["h261"]
+ },
+ "video/h263": {
+ "source": "iana",
+ "extensions": ["h263"]
+ },
+ "video/h263-1998": {
+ "source": "iana"
+ },
+ "video/h263-2000": {
+ "source": "iana"
+ },
+ "video/h264": {
+ "source": "iana",
+ "extensions": ["h264"]
+ },
+ "video/h264-rcdo": {
+ "source": "iana"
+ },
+ "video/h264-svc": {
+ "source": "iana"
+ },
+ "video/h265": {
+ "source": "iana"
+ },
+ "video/h266": {
+ "source": "iana"
+ },
+ "video/iso.segment": {
+ "source": "iana",
+ "extensions": ["m4s"]
+ },
+ "video/jpeg": {
+ "source": "iana",
+ "extensions": ["jpgv"]
+ },
+ "video/jpeg2000": {
+ "source": "iana"
+ },
+ "video/jpm": {
+ "source": "apache",
+ "extensions": ["jpm","jpgm"]
+ },
+ "video/jxsv": {
+ "source": "iana"
+ },
+ "video/lottie+json": {
+ "source": "iana",
+ "compressible": true
+ },
+ "video/matroska": {
+ "source": "iana"
+ },
+ "video/matroska-3d": {
+ "source": "iana"
+ },
+ "video/mj2": {
+ "source": "iana",
+ "extensions": ["mj2","mjp2"]
+ },
+ "video/mp1s": {
+ "source": "iana"
+ },
+ "video/mp2p": {
+ "source": "iana"
+ },
+ "video/mp2t": {
+ "source": "iana",
+ "extensions": ["ts","m2t","m2ts","mts"]
+ },
+ "video/mp4": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["mp4","mp4v","mpg4"]
+ },
+ "video/mp4v-es": {
+ "source": "iana"
+ },
+ "video/mpeg": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["mpeg","mpg","mpe","m1v","m2v"]
+ },
+ "video/mpeg4-generic": {
+ "source": "iana"
+ },
+ "video/mpv": {
+ "source": "iana"
+ },
+ "video/nv": {
+ "source": "iana"
+ },
+ "video/ogg": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["ogv"]
+ },
+ "video/parityfec": {
+ "source": "iana"
+ },
+ "video/pointer": {
+ "source": "iana"
+ },
+ "video/quicktime": {
+ "source": "iana",
+ "compressible": false,
+ "extensions": ["qt","mov"]
+ },
+ "video/raptorfec": {
+ "source": "iana"
+ },
+ "video/raw": {
+ "source": "iana"
+ },
+ "video/rtp-enc-aescm128": {
+ "source": "iana"
+ },
+ "video/rtploopback": {
+ "source": "iana"
+ },
+ "video/rtx": {
+ "source": "iana"
+ },
+ "video/scip": {
+ "source": "iana"
+ },
+ "video/smpte291": {
+ "source": "iana"
+ },
+ "video/smpte292m": {
+ "source": "iana"
+ },
+ "video/ulpfec": {
+ "source": "iana"
+ },
+ "video/vc1": {
+ "source": "iana"
+ },
+ "video/vc2": {
+ "source": "iana"
+ },
+ "video/vnd.cctv": {
+ "source": "iana"
+ },
+ "video/vnd.dece.hd": {
+ "source": "iana",
+ "extensions": ["uvh","uvvh"]
+ },
+ "video/vnd.dece.mobile": {
+ "source": "iana",
+ "extensions": ["uvm","uvvm"]
+ },
+ "video/vnd.dece.mp4": {
+ "source": "iana"
+ },
+ "video/vnd.dece.pd": {
+ "source": "iana",
+ "extensions": ["uvp","uvvp"]
+ },
+ "video/vnd.dece.sd": {
+ "source": "iana",
+ "extensions": ["uvs","uvvs"]
+ },
+ "video/vnd.dece.video": {
+ "source": "iana",
+ "extensions": ["uvv","uvvv"]
+ },
+ "video/vnd.directv.mpeg": {
+ "source": "iana"
+ },
+ "video/vnd.directv.mpeg-tts": {
+ "source": "iana"
+ },
+ "video/vnd.dlna.mpeg-tts": {
+ "source": "iana"
+ },
+ "video/vnd.dvb.file": {
+ "source": "iana",
+ "extensions": ["dvb"]
+ },
+ "video/vnd.fvt": {
+ "source": "iana",
+ "extensions": ["fvt"]
+ },
+ "video/vnd.hns.video": {
+ "source": "iana"
+ },
+ "video/vnd.iptvforum.1dparityfec-1010": {
+ "source": "iana"
+ },
+ "video/vnd.iptvforum.1dparityfec-2005": {
+ "source": "iana"
+ },
+ "video/vnd.iptvforum.2dparityfec-1010": {
+ "source": "iana"
+ },
+ "video/vnd.iptvforum.2dparityfec-2005": {
+ "source": "iana"
+ },
+ "video/vnd.iptvforum.ttsavc": {
+ "source": "iana"
+ },
+ "video/vnd.iptvforum.ttsmpeg2": {
+ "source": "iana"
+ },
+ "video/vnd.motorola.video": {
+ "source": "iana"
+ },
+ "video/vnd.motorola.videop": {
+ "source": "iana"
+ },
+ "video/vnd.mpegurl": {
+ "source": "iana",
+ "extensions": ["mxu","m4u"]
+ },
+ "video/vnd.ms-playready.media.pyv": {
+ "source": "iana",
+ "extensions": ["pyv"]
+ },
+ "video/vnd.nokia.interleaved-multimedia": {
+ "source": "iana"
+ },
+ "video/vnd.nokia.mp4vr": {
+ "source": "iana"
+ },
+ "video/vnd.nokia.videovoip": {
+ "source": "iana"
+ },
+ "video/vnd.objectvideo": {
+ "source": "iana"
+ },
+ "video/vnd.planar": {
+ "source": "iana"
+ },
+ "video/vnd.radgamettools.bink": {
+ "source": "iana"
+ },
+ "video/vnd.radgamettools.smacker": {
+ "source": "apache"
+ },
+ "video/vnd.sealed.mpeg1": {
+ "source": "iana"
+ },
+ "video/vnd.sealed.mpeg4": {
+ "source": "iana"
+ },
+ "video/vnd.sealed.swf": {
+ "source": "iana"
+ },
+ "video/vnd.sealedmedia.softseal.mov": {
+ "source": "iana"
+ },
+ "video/vnd.uvvu.mp4": {
+ "source": "iana",
+ "extensions": ["uvu","uvvu"]
+ },
+ "video/vnd.vivo": {
+ "source": "iana",
+ "extensions": ["viv"]
+ },
+ "video/vnd.youtube.yt": {
+ "source": "iana"
+ },
+ "video/vp8": {
+ "source": "iana"
+ },
+ "video/vp9": {
+ "source": "iana"
+ },
+ "video/webm": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["webm"]
+ },
+ "video/x-f4v": {
+ "source": "apache",
+ "extensions": ["f4v"]
+ },
+ "video/x-fli": {
+ "source": "apache",
+ "extensions": ["fli"]
+ },
+ "video/x-flv": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["flv"]
+ },
+ "video/x-m4v": {
+ "source": "apache",
+ "extensions": ["m4v"]
+ },
+ "video/x-matroska": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["mkv","mk3d","mks"]
+ },
+ "video/x-mng": {
+ "source": "apache",
+ "extensions": ["mng"]
+ },
+ "video/x-ms-asf": {
+ "source": "apache",
+ "extensions": ["asf","asx"]
+ },
+ "video/x-ms-vob": {
+ "source": "apache",
+ "extensions": ["vob"]
+ },
+ "video/x-ms-wm": {
+ "source": "apache",
+ "extensions": ["wm"]
+ },
+ "video/x-ms-wmv": {
+ "source": "apache",
+ "compressible": false,
+ "extensions": ["wmv"]
+ },
+ "video/x-ms-wmx": {
+ "source": "apache",
+ "extensions": ["wmx"]
+ },
+ "video/x-ms-wvx": {
+ "source": "apache",
+ "extensions": ["wvx"]
+ },
+ "video/x-msvideo": {
+ "source": "apache",
+ "extensions": ["avi"]
+ },
+ "video/x-sgi-movie": {
+ "source": "apache",
+ "extensions": ["movie"]
+ },
+ "video/x-smv": {
+ "source": "apache",
+ "extensions": ["smv"]
+ },
+ "x-conference/x-cooltalk": {
+ "source": "apache",
+ "extensions": ["ice"]
+ },
+ "x-shader/x-fragment": {
+ "compressible": true
+ },
+ "x-shader/x-vertex": {
+ "compressible": true
+ }
+}
+
+}, function(modId) { var map = {}; return __REQUIRE__(map[modId], modId); })
+return __REQUIRE__(1761637667903);
+})()
+//miniprogram-npm-outsideDeps=[]
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/miniprogram_npm/accepts/miniprogram_npm/mime-db/index.js.map b/miniprogram_npm/accepts/miniprogram_npm/mime-db/index.js.map
new file mode 100644
index 0000000..2e96048
--- /dev/null
+++ b/miniprogram_npm/accepts/miniprogram_npm/mime-db/index.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["index.js","db.json"],"names":[],"mappings":";;;;;;;AAAA;AACA;AACA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA,ADGA;ACFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"index.js","sourcesContent":["/*!\n * mime-db\n * Copyright(c) 2014 Jonathan Ong\n * Copyright(c) 2015-2022 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n/**\n * Module exports.\n */\n\nmodule.exports = require('./db.json')\n","module.exports = {\n \"application/1d-interleaved-parityfec\": {\n \"source\": \"iana\"\n },\n \"application/3gpdash-qoe-report+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/3gpp-ims+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/3gpphal+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/3gpphalforms+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/a2l\": {\n \"source\": \"iana\"\n },\n \"application/ace+cbor\": {\n \"source\": \"iana\"\n },\n \"application/ace+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/ace-groupcomm+cbor\": {\n \"source\": \"iana\"\n },\n \"application/ace-trl+cbor\": {\n \"source\": \"iana\"\n },\n \"application/activemessage\": {\n \"source\": \"iana\"\n },\n \"application/activity+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/aif+cbor\": {\n \"source\": \"iana\"\n },\n \"application/aif+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-cdni+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-cdnifilter+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-costmap+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-costmapfilter+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-directory+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-endpointcost+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-endpointcostparams+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-endpointprop+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-endpointpropparams+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-error+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-networkmap+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-networkmapfilter+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-propmap+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-propmapparams+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-tips+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-tipsparams+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-updatestreamcontrol+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/alto-updatestreamparams+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/aml\": {\n \"source\": \"iana\"\n },\n \"application/andrew-inset\": {\n \"source\": \"iana\",\n \"extensions\": [\"ez\"]\n },\n \"application/appinstaller\": {\n \"compressible\": false,\n \"extensions\": [\"appinstaller\"]\n },\n \"application/applefile\": {\n \"source\": \"iana\"\n },\n \"application/applixware\": {\n \"source\": \"apache\",\n \"extensions\": [\"aw\"]\n },\n \"application/appx\": {\n \"compressible\": false,\n \"extensions\": [\"appx\"]\n },\n \"application/appxbundle\": {\n \"compressible\": false,\n \"extensions\": [\"appxbundle\"]\n },\n \"application/at+jwt\": {\n \"source\": \"iana\"\n },\n \"application/atf\": {\n \"source\": \"iana\"\n },\n \"application/atfx\": {\n \"source\": \"iana\"\n },\n \"application/atom+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"atom\"]\n },\n \"application/atomcat+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"atomcat\"]\n },\n \"application/atomdeleted+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"atomdeleted\"]\n },\n \"application/atomicmail\": {\n \"source\": \"iana\"\n },\n \"application/atomsvc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"atomsvc\"]\n },\n \"application/atsc-dwd+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"dwd\"]\n },\n \"application/atsc-dynamic-event-message\": {\n \"source\": \"iana\"\n },\n \"application/atsc-held+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"held\"]\n },\n \"application/atsc-rdt+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/atsc-rsat+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rsat\"]\n },\n \"application/atxml\": {\n \"source\": \"iana\"\n },\n \"application/auth-policy+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/automationml-aml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"aml\"]\n },\n \"application/automationml-amlx+zip\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"amlx\"]\n },\n \"application/bacnet-xdd+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/batch-smtp\": {\n \"source\": \"iana\"\n },\n \"application/bdoc\": {\n \"compressible\": false,\n \"extensions\": [\"bdoc\"]\n },\n \"application/beep+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/bufr\": {\n \"source\": \"iana\"\n },\n \"application/c2pa\": {\n \"source\": \"iana\"\n },\n \"application/calendar+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/calendar+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xcs\"]\n },\n \"application/call-completion\": {\n \"source\": \"iana\"\n },\n \"application/cals-1840\": {\n \"source\": \"iana\"\n },\n \"application/captive+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/cbor\": {\n \"source\": \"iana\"\n },\n \"application/cbor-seq\": {\n \"source\": \"iana\"\n },\n \"application/cccex\": {\n \"source\": \"iana\"\n },\n \"application/ccmp+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/ccxml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"ccxml\"]\n },\n \"application/cda+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/cdfx+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"cdfx\"]\n },\n \"application/cdmi-capability\": {\n \"source\": \"iana\",\n \"extensions\": [\"cdmia\"]\n },\n \"application/cdmi-container\": {\n \"source\": \"iana\",\n \"extensions\": [\"cdmic\"]\n },\n \"application/cdmi-domain\": {\n \"source\": \"iana\",\n \"extensions\": [\"cdmid\"]\n },\n \"application/cdmi-object\": {\n \"source\": \"iana\",\n \"extensions\": [\"cdmio\"]\n },\n \"application/cdmi-queue\": {\n \"source\": \"iana\",\n \"extensions\": [\"cdmiq\"]\n },\n \"application/cdni\": {\n \"source\": \"iana\"\n },\n \"application/ce+cbor\": {\n \"source\": \"iana\"\n },\n \"application/cea\": {\n \"source\": \"iana\"\n },\n \"application/cea-2018+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/cellml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/cfw\": {\n \"source\": \"iana\"\n },\n \"application/cid-edhoc+cbor-seq\": {\n \"source\": \"iana\"\n },\n \"application/city+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/city+json-seq\": {\n \"source\": \"iana\"\n },\n \"application/clr\": {\n \"source\": \"iana\"\n },\n \"application/clue+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/clue_info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/cms\": {\n \"source\": \"iana\"\n },\n \"application/cnrp+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/coap-eap\": {\n \"source\": \"iana\"\n },\n \"application/coap-group+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/coap-payload\": {\n \"source\": \"iana\"\n },\n \"application/commonground\": {\n \"source\": \"iana\"\n },\n \"application/concise-problem-details+cbor\": {\n \"source\": \"iana\"\n },\n \"application/conference-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/cose\": {\n \"source\": \"iana\"\n },\n \"application/cose-key\": {\n \"source\": \"iana\"\n },\n \"application/cose-key-set\": {\n \"source\": \"iana\"\n },\n \"application/cose-x509\": {\n \"source\": \"iana\"\n },\n \"application/cpl+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"cpl\"]\n },\n \"application/csrattrs\": {\n \"source\": \"iana\"\n },\n \"application/csta+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/cstadata+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/csvm+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/cu-seeme\": {\n \"source\": \"apache\",\n \"extensions\": [\"cu\"]\n },\n \"application/cwl\": {\n \"source\": \"iana\",\n \"extensions\": [\"cwl\"]\n },\n \"application/cwl+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/cwl+yaml\": {\n \"source\": \"iana\"\n },\n \"application/cwt\": {\n \"source\": \"iana\"\n },\n \"application/cybercash\": {\n \"source\": \"iana\"\n },\n \"application/dart\": {\n \"compressible\": true\n },\n \"application/dash+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mpd\"]\n },\n \"application/dash-patch+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mpp\"]\n },\n \"application/dashdelta\": {\n \"source\": \"iana\"\n },\n \"application/davmount+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"davmount\"]\n },\n \"application/dca-rft\": {\n \"source\": \"iana\"\n },\n \"application/dcd\": {\n \"source\": \"iana\"\n },\n \"application/dec-dx\": {\n \"source\": \"iana\"\n },\n \"application/dialog-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/dicom\": {\n \"source\": \"iana\",\n \"extensions\": [\"dcm\"]\n },\n \"application/dicom+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/dicom+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/dii\": {\n \"source\": \"iana\"\n },\n \"application/dit\": {\n \"source\": \"iana\"\n },\n \"application/dns\": {\n \"source\": \"iana\"\n },\n \"application/dns+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/dns-message\": {\n \"source\": \"iana\"\n },\n \"application/docbook+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"dbk\"]\n },\n \"application/dots+cbor\": {\n \"source\": \"iana\"\n },\n \"application/dpop+jwt\": {\n \"source\": \"iana\"\n },\n \"application/dskpp+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/dssc+der\": {\n \"source\": \"iana\",\n \"extensions\": [\"dssc\"]\n },\n \"application/dssc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xdssc\"]\n },\n \"application/dvcs\": {\n \"source\": \"iana\"\n },\n \"application/eat+cwt\": {\n \"source\": \"iana\"\n },\n \"application/eat+jwt\": {\n \"source\": \"iana\"\n },\n \"application/eat-bun+cbor\": {\n \"source\": \"iana\"\n },\n \"application/eat-bun+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/eat-ucs+cbor\": {\n \"source\": \"iana\"\n },\n \"application/eat-ucs+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/ecmascript\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"ecma\"]\n },\n \"application/edhoc+cbor-seq\": {\n \"source\": \"iana\"\n },\n \"application/edi-consent\": {\n \"source\": \"iana\"\n },\n \"application/edi-x12\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/edifact\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/efi\": {\n \"source\": \"iana\"\n },\n \"application/elm+json\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/elm+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/emergencycalldata.cap+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/emergencycalldata.comment+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/emergencycalldata.control+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/emergencycalldata.deviceinfo+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/emergencycalldata.ecall.msd\": {\n \"source\": \"iana\"\n },\n \"application/emergencycalldata.legacyesn+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/emergencycalldata.providerinfo+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/emergencycalldata.serviceinfo+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/emergencycalldata.subscriberinfo+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/emergencycalldata.veds+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/emma+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"emma\"]\n },\n \"application/emotionml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"emotionml\"]\n },\n \"application/encaprtp\": {\n \"source\": \"iana\"\n },\n \"application/entity-statement+jwt\": {\n \"source\": \"iana\"\n },\n \"application/epp+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/epub+zip\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"epub\"]\n },\n \"application/eshop\": {\n \"source\": \"iana\"\n },\n \"application/exi\": {\n \"source\": \"iana\",\n \"extensions\": [\"exi\"]\n },\n \"application/expect-ct-report+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/express\": {\n \"source\": \"iana\",\n \"extensions\": [\"exp\"]\n },\n \"application/fastinfoset\": {\n \"source\": \"iana\"\n },\n \"application/fastsoap\": {\n \"source\": \"iana\"\n },\n \"application/fdf\": {\n \"source\": \"iana\",\n \"extensions\": [\"fdf\"]\n },\n \"application/fdt+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"fdt\"]\n },\n \"application/fhir+json\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/fhir+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/fido.trusted-apps+json\": {\n \"compressible\": true\n },\n \"application/fits\": {\n \"source\": \"iana\"\n },\n \"application/flexfec\": {\n \"source\": \"iana\"\n },\n \"application/font-sfnt\": {\n \"source\": \"iana\"\n },\n \"application/font-tdpfr\": {\n \"source\": \"iana\",\n \"extensions\": [\"pfr\"]\n },\n \"application/font-woff\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/framework-attributes+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/geo+json\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"geojson\"]\n },\n \"application/geo+json-seq\": {\n \"source\": \"iana\"\n },\n \"application/geopackage+sqlite3\": {\n \"source\": \"iana\"\n },\n \"application/geopose+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/geoxacml+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/geoxacml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/gltf-buffer\": {\n \"source\": \"iana\"\n },\n \"application/gml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"gml\"]\n },\n \"application/gnap-binding-jws\": {\n \"source\": \"iana\"\n },\n \"application/gnap-binding-jwsd\": {\n \"source\": \"iana\"\n },\n \"application/gnap-binding-rotation-jws\": {\n \"source\": \"iana\"\n },\n \"application/gnap-binding-rotation-jwsd\": {\n \"source\": \"iana\"\n },\n \"application/gpx+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"gpx\"]\n },\n \"application/grib\": {\n \"source\": \"iana\"\n },\n \"application/gxf\": {\n \"source\": \"apache\",\n \"extensions\": [\"gxf\"]\n },\n \"application/gzip\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"gz\"]\n },\n \"application/h224\": {\n \"source\": \"iana\"\n },\n \"application/held+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/hjson\": {\n \"extensions\": [\"hjson\"]\n },\n \"application/hl7v2+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/http\": {\n \"source\": \"iana\"\n },\n \"application/hyperstudio\": {\n \"source\": \"iana\",\n \"extensions\": [\"stk\"]\n },\n \"application/ibe-key-request+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/ibe-pkg-reply+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/ibe-pp-data\": {\n \"source\": \"iana\"\n },\n \"application/iges\": {\n \"source\": \"iana\"\n },\n \"application/im-iscomposing+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/index\": {\n \"source\": \"iana\"\n },\n \"application/index.cmd\": {\n \"source\": \"iana\"\n },\n \"application/index.obj\": {\n \"source\": \"iana\"\n },\n \"application/index.response\": {\n \"source\": \"iana\"\n },\n \"application/index.vnd\": {\n \"source\": \"iana\"\n },\n \"application/inkml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"ink\",\"inkml\"]\n },\n \"application/iotp\": {\n \"source\": \"iana\"\n },\n \"application/ipfix\": {\n \"source\": \"iana\",\n \"extensions\": [\"ipfix\"]\n },\n \"application/ipp\": {\n \"source\": \"iana\"\n },\n \"application/isup\": {\n \"source\": \"iana\"\n },\n \"application/its+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"its\"]\n },\n \"application/java-archive\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"jar\",\"war\",\"ear\"]\n },\n \"application/java-serialized-object\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"ser\"]\n },\n \"application/java-vm\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"class\"]\n },\n \"application/javascript\": {\n \"source\": \"apache\",\n \"charset\": \"UTF-8\",\n \"compressible\": true,\n \"extensions\": [\"js\"]\n },\n \"application/jf2feed+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/jose\": {\n \"source\": \"iana\"\n },\n \"application/jose+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/jrd+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/jscalendar+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/jscontact+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/json\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true,\n \"extensions\": [\"json\",\"map\"]\n },\n \"application/json-patch+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/json-seq\": {\n \"source\": \"iana\"\n },\n \"application/json5\": {\n \"extensions\": [\"json5\"]\n },\n \"application/jsonml+json\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"jsonml\"]\n },\n \"application/jsonpath\": {\n \"source\": \"iana\"\n },\n \"application/jwk+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/jwk-set+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/jwk-set+jwt\": {\n \"source\": \"iana\"\n },\n \"application/jwt\": {\n \"source\": \"iana\"\n },\n \"application/kpml-request+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/kpml-response+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/ld+json\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"jsonld\"]\n },\n \"application/lgr+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"lgr\"]\n },\n \"application/link-format\": {\n \"source\": \"iana\"\n },\n \"application/linkset\": {\n \"source\": \"iana\"\n },\n \"application/linkset+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/load-control+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/logout+jwt\": {\n \"source\": \"iana\"\n },\n \"application/lost+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"lostxml\"]\n },\n \"application/lostsync+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/lpf+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/lxf\": {\n \"source\": \"iana\"\n },\n \"application/mac-binhex40\": {\n \"source\": \"iana\",\n \"extensions\": [\"hqx\"]\n },\n \"application/mac-compactpro\": {\n \"source\": \"apache\",\n \"extensions\": [\"cpt\"]\n },\n \"application/macwriteii\": {\n \"source\": \"iana\"\n },\n \"application/mads+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mads\"]\n },\n \"application/manifest+json\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true,\n \"extensions\": [\"webmanifest\"]\n },\n \"application/marc\": {\n \"source\": \"iana\",\n \"extensions\": [\"mrc\"]\n },\n \"application/marcxml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mrcx\"]\n },\n \"application/mathematica\": {\n \"source\": \"iana\",\n \"extensions\": [\"ma\",\"nb\",\"mb\"]\n },\n \"application/mathml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mathml\"]\n },\n \"application/mathml-content+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mathml-presentation+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-associated-procedure-description+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-deregister+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-envelope+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-msk+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-msk-response+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-protection-description+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-reception-report+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-register+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-register-response+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-schedule+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbms-user-service-description+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mbox\": {\n \"source\": \"iana\",\n \"extensions\": [\"mbox\"]\n },\n \"application/media-policy-dataset+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mpf\"]\n },\n \"application/media_control+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mediaservercontrol+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mscml\"]\n },\n \"application/merge-patch+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/metalink+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"metalink\"]\n },\n \"application/metalink4+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"meta4\"]\n },\n \"application/mets+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mets\"]\n },\n \"application/mf4\": {\n \"source\": \"iana\"\n },\n \"application/mikey\": {\n \"source\": \"iana\"\n },\n \"application/mipc\": {\n \"source\": \"iana\"\n },\n \"application/missing-blocks+cbor-seq\": {\n \"source\": \"iana\"\n },\n \"application/mmt-aei+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"maei\"]\n },\n \"application/mmt-usd+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"musd\"]\n },\n \"application/mods+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mods\"]\n },\n \"application/moss-keys\": {\n \"source\": \"iana\"\n },\n \"application/moss-signature\": {\n \"source\": \"iana\"\n },\n \"application/mosskey-data\": {\n \"source\": \"iana\"\n },\n \"application/mosskey-request\": {\n \"source\": \"iana\"\n },\n \"application/mp21\": {\n \"source\": \"iana\",\n \"extensions\": [\"m21\",\"mp21\"]\n },\n \"application/mp4\": {\n \"source\": \"iana\",\n \"extensions\": [\"mp4\",\"mpg4\",\"mp4s\",\"m4p\"]\n },\n \"application/mpeg4-generic\": {\n \"source\": \"iana\"\n },\n \"application/mpeg4-iod\": {\n \"source\": \"iana\"\n },\n \"application/mpeg4-iod-xmt\": {\n \"source\": \"iana\"\n },\n \"application/mrb-consumer+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/mrb-publish+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/msc-ivr+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/msc-mixer+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/msix\": {\n \"compressible\": false,\n \"extensions\": [\"msix\"]\n },\n \"application/msixbundle\": {\n \"compressible\": false,\n \"extensions\": [\"msixbundle\"]\n },\n \"application/msword\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"doc\",\"dot\"]\n },\n \"application/mud+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/multipart-core\": {\n \"source\": \"iana\"\n },\n \"application/mxf\": {\n \"source\": \"iana\",\n \"extensions\": [\"mxf\"]\n },\n \"application/n-quads\": {\n \"source\": \"iana\",\n \"extensions\": [\"nq\"]\n },\n \"application/n-triples\": {\n \"source\": \"iana\",\n \"extensions\": [\"nt\"]\n },\n \"application/nasdata\": {\n \"source\": \"iana\"\n },\n \"application/news-checkgroups\": {\n \"source\": \"iana\",\n \"charset\": \"US-ASCII\"\n },\n \"application/news-groupinfo\": {\n \"source\": \"iana\",\n \"charset\": \"US-ASCII\"\n },\n \"application/news-transmission\": {\n \"source\": \"iana\"\n },\n \"application/nlsml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/node\": {\n \"source\": \"iana\",\n \"extensions\": [\"cjs\"]\n },\n \"application/nss\": {\n \"source\": \"iana\"\n },\n \"application/oauth-authz-req+jwt\": {\n \"source\": \"iana\"\n },\n \"application/oblivious-dns-message\": {\n \"source\": \"iana\"\n },\n \"application/ocsp-request\": {\n \"source\": \"iana\"\n },\n \"application/ocsp-response\": {\n \"source\": \"iana\"\n },\n \"application/octet-stream\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"bin\",\"dms\",\"lrf\",\"mar\",\"so\",\"dist\",\"distz\",\"pkg\",\"bpk\",\"dump\",\"elc\",\"deploy\",\"exe\",\"dll\",\"deb\",\"dmg\",\"iso\",\"img\",\"msi\",\"msp\",\"msm\",\"buffer\"]\n },\n \"application/oda\": {\n \"source\": \"iana\",\n \"extensions\": [\"oda\"]\n },\n \"application/odm+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/odx\": {\n \"source\": \"iana\"\n },\n \"application/oebps-package+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"opf\"]\n },\n \"application/ogg\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"ogx\"]\n },\n \"application/ohttp-keys\": {\n \"source\": \"iana\"\n },\n \"application/omdoc+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"omdoc\"]\n },\n \"application/onenote\": {\n \"source\": \"apache\",\n \"extensions\": [\"onetoc\",\"onetoc2\",\"onetmp\",\"onepkg\",\"one\",\"onea\"]\n },\n \"application/opc-nodeset+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/oscore\": {\n \"source\": \"iana\"\n },\n \"application/oxps\": {\n \"source\": \"iana\",\n \"extensions\": [\"oxps\"]\n },\n \"application/p21\": {\n \"source\": \"iana\"\n },\n \"application/p21+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/p2p-overlay+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"relo\"]\n },\n \"application/parityfec\": {\n \"source\": \"iana\"\n },\n \"application/passport\": {\n \"source\": \"iana\"\n },\n \"application/patch-ops-error+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xer\"]\n },\n \"application/pdf\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"pdf\"]\n },\n \"application/pdx\": {\n \"source\": \"iana\"\n },\n \"application/pem-certificate-chain\": {\n \"source\": \"iana\"\n },\n \"application/pgp-encrypted\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"pgp\"]\n },\n \"application/pgp-keys\": {\n \"source\": \"iana\",\n \"extensions\": [\"asc\"]\n },\n \"application/pgp-signature\": {\n \"source\": \"iana\",\n \"extensions\": [\"sig\",\"asc\"]\n },\n \"application/pics-rules\": {\n \"source\": \"apache\",\n \"extensions\": [\"prf\"]\n },\n \"application/pidf+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/pidf-diff+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/pkcs10\": {\n \"source\": \"iana\",\n \"extensions\": [\"p10\"]\n },\n \"application/pkcs12\": {\n \"source\": \"iana\"\n },\n \"application/pkcs7-mime\": {\n \"source\": \"iana\",\n \"extensions\": [\"p7m\",\"p7c\"]\n },\n \"application/pkcs7-signature\": {\n \"source\": \"iana\",\n \"extensions\": [\"p7s\"]\n },\n \"application/pkcs8\": {\n \"source\": \"iana\",\n \"extensions\": [\"p8\"]\n },\n \"application/pkcs8-encrypted\": {\n \"source\": \"iana\"\n },\n \"application/pkix-attr-cert\": {\n \"source\": \"iana\",\n \"extensions\": [\"ac\"]\n },\n \"application/pkix-cert\": {\n \"source\": \"iana\",\n \"extensions\": [\"cer\"]\n },\n \"application/pkix-crl\": {\n \"source\": \"iana\",\n \"extensions\": [\"crl\"]\n },\n \"application/pkix-pkipath\": {\n \"source\": \"iana\",\n \"extensions\": [\"pkipath\"]\n },\n \"application/pkixcmp\": {\n \"source\": \"iana\",\n \"extensions\": [\"pki\"]\n },\n \"application/pls+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"pls\"]\n },\n \"application/poc-settings+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/postscript\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"ai\",\"eps\",\"ps\"]\n },\n \"application/ppsp-tracker+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/private-token-issuer-directory\": {\n \"source\": \"iana\"\n },\n \"application/private-token-request\": {\n \"source\": \"iana\"\n },\n \"application/private-token-response\": {\n \"source\": \"iana\"\n },\n \"application/problem+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/problem+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/provenance+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"provx\"]\n },\n \"application/provided-claims+jwt\": {\n \"source\": \"iana\"\n },\n \"application/prs.alvestrand.titrax-sheet\": {\n \"source\": \"iana\"\n },\n \"application/prs.cww\": {\n \"source\": \"iana\",\n \"extensions\": [\"cww\"]\n },\n \"application/prs.cyn\": {\n \"source\": \"iana\",\n \"charset\": \"7-BIT\"\n },\n \"application/prs.hpub+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/prs.implied-document+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/prs.implied-executable\": {\n \"source\": \"iana\"\n },\n \"application/prs.implied-object+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/prs.implied-object+json-seq\": {\n \"source\": \"iana\"\n },\n \"application/prs.implied-object+yaml\": {\n \"source\": \"iana\"\n },\n \"application/prs.implied-structure\": {\n \"source\": \"iana\"\n },\n \"application/prs.mayfile\": {\n \"source\": \"iana\"\n },\n \"application/prs.nprend\": {\n \"source\": \"iana\"\n },\n \"application/prs.plucker\": {\n \"source\": \"iana\"\n },\n \"application/prs.rdf-xml-crypt\": {\n \"source\": \"iana\"\n },\n \"application/prs.vcfbzip2\": {\n \"source\": \"iana\"\n },\n \"application/prs.xsf+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xsf\"]\n },\n \"application/pskc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"pskcxml\"]\n },\n \"application/pvd+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/qsig\": {\n \"source\": \"iana\"\n },\n \"application/raml+yaml\": {\n \"compressible\": true,\n \"extensions\": [\"raml\"]\n },\n \"application/raptorfec\": {\n \"source\": \"iana\"\n },\n \"application/rdap+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/rdf+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rdf\",\"owl\"]\n },\n \"application/reginfo+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rif\"]\n },\n \"application/relax-ng-compact-syntax\": {\n \"source\": \"iana\",\n \"extensions\": [\"rnc\"]\n },\n \"application/remote-printing\": {\n \"source\": \"apache\"\n },\n \"application/reputon+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/resolve-response+jwt\": {\n \"source\": \"iana\"\n },\n \"application/resource-lists+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rl\"]\n },\n \"application/resource-lists-diff+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rld\"]\n },\n \"application/rfc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/riscos\": {\n \"source\": \"iana\"\n },\n \"application/rlmi+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/rls-services+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rs\"]\n },\n \"application/route-apd+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rapd\"]\n },\n \"application/route-s-tsid+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"sls\"]\n },\n \"application/route-usd+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rusd\"]\n },\n \"application/rpki-checklist\": {\n \"source\": \"iana\"\n },\n \"application/rpki-ghostbusters\": {\n \"source\": \"iana\",\n \"extensions\": [\"gbr\"]\n },\n \"application/rpki-manifest\": {\n \"source\": \"iana\",\n \"extensions\": [\"mft\"]\n },\n \"application/rpki-publication\": {\n \"source\": \"iana\"\n },\n \"application/rpki-roa\": {\n \"source\": \"iana\",\n \"extensions\": [\"roa\"]\n },\n \"application/rpki-signed-tal\": {\n \"source\": \"iana\"\n },\n \"application/rpki-updown\": {\n \"source\": \"iana\"\n },\n \"application/rsd+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"rsd\"]\n },\n \"application/rss+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"rss\"]\n },\n \"application/rtf\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rtf\"]\n },\n \"application/rtploopback\": {\n \"source\": \"iana\"\n },\n \"application/rtx\": {\n \"source\": \"iana\"\n },\n \"application/samlassertion+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/samlmetadata+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/sarif+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/sarif-external-properties+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/sbe\": {\n \"source\": \"iana\"\n },\n \"application/sbml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"sbml\"]\n },\n \"application/scaip+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/scim+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/scvp-cv-request\": {\n \"source\": \"iana\",\n \"extensions\": [\"scq\"]\n },\n \"application/scvp-cv-response\": {\n \"source\": \"iana\",\n \"extensions\": [\"scs\"]\n },\n \"application/scvp-vp-request\": {\n \"source\": \"iana\",\n \"extensions\": [\"spq\"]\n },\n \"application/scvp-vp-response\": {\n \"source\": \"iana\",\n \"extensions\": [\"spp\"]\n },\n \"application/sdp\": {\n \"source\": \"iana\",\n \"extensions\": [\"sdp\"]\n },\n \"application/secevent+jwt\": {\n \"source\": \"iana\"\n },\n \"application/senml+cbor\": {\n \"source\": \"iana\"\n },\n \"application/senml+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/senml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"senmlx\"]\n },\n \"application/senml-etch+cbor\": {\n \"source\": \"iana\"\n },\n \"application/senml-etch+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/senml-exi\": {\n \"source\": \"iana\"\n },\n \"application/sensml+cbor\": {\n \"source\": \"iana\"\n },\n \"application/sensml+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/sensml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"sensmlx\"]\n },\n \"application/sensml-exi\": {\n \"source\": \"iana\"\n },\n \"application/sep+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/sep-exi\": {\n \"source\": \"iana\"\n },\n \"application/session-info\": {\n \"source\": \"iana\"\n },\n \"application/set-payment\": {\n \"source\": \"iana\"\n },\n \"application/set-payment-initiation\": {\n \"source\": \"iana\",\n \"extensions\": [\"setpay\"]\n },\n \"application/set-registration\": {\n \"source\": \"iana\"\n },\n \"application/set-registration-initiation\": {\n \"source\": \"iana\",\n \"extensions\": [\"setreg\"]\n },\n \"application/sgml\": {\n \"source\": \"iana\"\n },\n \"application/sgml-open-catalog\": {\n \"source\": \"iana\"\n },\n \"application/shf+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"shf\"]\n },\n \"application/sieve\": {\n \"source\": \"iana\",\n \"extensions\": [\"siv\",\"sieve\"]\n },\n \"application/simple-filter+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/simple-message-summary\": {\n \"source\": \"iana\"\n },\n \"application/simplesymbolcontainer\": {\n \"source\": \"iana\"\n },\n \"application/sipc\": {\n \"source\": \"iana\"\n },\n \"application/slate\": {\n \"source\": \"iana\"\n },\n \"application/smil\": {\n \"source\": \"apache\"\n },\n \"application/smil+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"smi\",\"smil\"]\n },\n \"application/smpte336m\": {\n \"source\": \"iana\"\n },\n \"application/soap+fastinfoset\": {\n \"source\": \"iana\"\n },\n \"application/soap+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/sparql-query\": {\n \"source\": \"iana\",\n \"extensions\": [\"rq\"]\n },\n \"application/sparql-results+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"srx\"]\n },\n \"application/spdx+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/spirits-event+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/sql\": {\n \"source\": \"iana\",\n \"extensions\": [\"sql\"]\n },\n \"application/srgs\": {\n \"source\": \"iana\",\n \"extensions\": [\"gram\"]\n },\n \"application/srgs+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"grxml\"]\n },\n \"application/sru+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"sru\"]\n },\n \"application/ssdl+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"ssdl\"]\n },\n \"application/sslkeylogfile\": {\n \"source\": \"iana\"\n },\n \"application/ssml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"ssml\"]\n },\n \"application/st2110-41\": {\n \"source\": \"iana\"\n },\n \"application/stix+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/stratum\": {\n \"source\": \"iana\"\n },\n \"application/swid+cbor\": {\n \"source\": \"iana\"\n },\n \"application/swid+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"swidtag\"]\n },\n \"application/tamp-apex-update\": {\n \"source\": \"iana\"\n },\n \"application/tamp-apex-update-confirm\": {\n \"source\": \"iana\"\n },\n \"application/tamp-community-update\": {\n \"source\": \"iana\"\n },\n \"application/tamp-community-update-confirm\": {\n \"source\": \"iana\"\n },\n \"application/tamp-error\": {\n \"source\": \"iana\"\n },\n \"application/tamp-sequence-adjust\": {\n \"source\": \"iana\"\n },\n \"application/tamp-sequence-adjust-confirm\": {\n \"source\": \"iana\"\n },\n \"application/tamp-status-query\": {\n \"source\": \"iana\"\n },\n \"application/tamp-status-response\": {\n \"source\": \"iana\"\n },\n \"application/tamp-update\": {\n \"source\": \"iana\"\n },\n \"application/tamp-update-confirm\": {\n \"source\": \"iana\"\n },\n \"application/tar\": {\n \"compressible\": true\n },\n \"application/taxii+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/td+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/tei+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"tei\",\"teicorpus\"]\n },\n \"application/tetra_isi\": {\n \"source\": \"iana\"\n },\n \"application/thraud+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"tfi\"]\n },\n \"application/timestamp-query\": {\n \"source\": \"iana\"\n },\n \"application/timestamp-reply\": {\n \"source\": \"iana\"\n },\n \"application/timestamped-data\": {\n \"source\": \"iana\",\n \"extensions\": [\"tsd\"]\n },\n \"application/tlsrpt+gzip\": {\n \"source\": \"iana\"\n },\n \"application/tlsrpt+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/tm+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/tnauthlist\": {\n \"source\": \"iana\"\n },\n \"application/toc+cbor\": {\n \"source\": \"iana\"\n },\n \"application/token-introspection+jwt\": {\n \"source\": \"iana\"\n },\n \"application/toml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"toml\"]\n },\n \"application/trickle-ice-sdpfrag\": {\n \"source\": \"iana\"\n },\n \"application/trig\": {\n \"source\": \"iana\",\n \"extensions\": [\"trig\"]\n },\n \"application/trust-chain+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/trust-mark+jwt\": {\n \"source\": \"iana\"\n },\n \"application/trust-mark-delegation+jwt\": {\n \"source\": \"iana\"\n },\n \"application/ttml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"ttml\"]\n },\n \"application/tve-trigger\": {\n \"source\": \"iana\"\n },\n \"application/tzif\": {\n \"source\": \"iana\"\n },\n \"application/tzif-leap\": {\n \"source\": \"iana\"\n },\n \"application/ubjson\": {\n \"compressible\": false,\n \"extensions\": [\"ubj\"]\n },\n \"application/uccs+cbor\": {\n \"source\": \"iana\"\n },\n \"application/ujcs+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/ulpfec\": {\n \"source\": \"iana\"\n },\n \"application/urc-grpsheet+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/urc-ressheet+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rsheet\"]\n },\n \"application/urc-targetdesc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"td\"]\n },\n \"application/urc-uisocketdesc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vc\": {\n \"source\": \"iana\"\n },\n \"application/vc+cose\": {\n \"source\": \"iana\"\n },\n \"application/vc+jwt\": {\n \"source\": \"iana\"\n },\n \"application/vcard+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vcard+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vemmi\": {\n \"source\": \"iana\"\n },\n \"application/vividence.scriptfile\": {\n \"source\": \"apache\"\n },\n \"application/vnd.1000minds.decision-model+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"1km\"]\n },\n \"application/vnd.1ob\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp-prose+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp-prose-pc3a+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp-prose-pc3ach+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp-prose-pc3ch+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp-prose-pc8+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp-v2x-local-service-information\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.5gnas\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.5gsa2x\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.5gsa2x-local-service-information\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.5gsv2x\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.5gsv2x-local-service-information\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.access-transfer-events+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.bsf+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.crs+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.current-location-discovery+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.gmop+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.gtpc\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.interworking-data\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.lpp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.mc-signalling-ear\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.mcdata-affiliation-command+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcdata-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcdata-msgstore-ctrl-request+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcdata-payload\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.mcdata-regroup+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcdata-service-config+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcdata-signalling\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.mcdata-ue-config+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcdata-user-profile+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-affiliation-command+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-floor-request+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-location-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-mbms-usage-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-regroup+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-service-config+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-signed+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-ue-config+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-ue-init-config+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcptt-user-profile+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcvideo-affiliation-command+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcvideo-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcvideo-location-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcvideo-mbms-usage-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcvideo-regroup+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcvideo-service-config+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcvideo-transmission-request+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcvideo-ue-config+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mcvideo-user-profile+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.mid-call+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.ngap\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.pfcp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.pic-bw-large\": {\n \"source\": \"iana\",\n \"extensions\": [\"plb\"]\n },\n \"application/vnd.3gpp.pic-bw-small\": {\n \"source\": \"iana\",\n \"extensions\": [\"psb\"]\n },\n \"application/vnd.3gpp.pic-bw-var\": {\n \"source\": \"iana\",\n \"extensions\": [\"pvb\"]\n },\n \"application/vnd.3gpp.pinapp-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.s1ap\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.seal-group-doc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.seal-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.seal-location-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.seal-mbms-usage-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.seal-network-qos-management-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.seal-ue-config-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.seal-unicast-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.seal-user-profile-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.sms\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.sms+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.srvcc-ext+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.srvcc-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.state-and-event-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.ussd+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp.v2x\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp.vae-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp2.bcmcsinfo+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.3gpp2.sms\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3gpp2.tcap\": {\n \"source\": \"iana\",\n \"extensions\": [\"tcap\"]\n },\n \"application/vnd.3lightssoftware.imagescal\": {\n \"source\": \"iana\"\n },\n \"application/vnd.3m.post-it-notes\": {\n \"source\": \"iana\",\n \"extensions\": [\"pwn\"]\n },\n \"application/vnd.accpac.simply.aso\": {\n \"source\": \"iana\",\n \"extensions\": [\"aso\"]\n },\n \"application/vnd.accpac.simply.imp\": {\n \"source\": \"iana\",\n \"extensions\": [\"imp\"]\n },\n \"application/vnd.acm.addressxfer+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.acm.chatbot+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.acucobol\": {\n \"source\": \"iana\",\n \"extensions\": [\"acu\"]\n },\n \"application/vnd.acucorp\": {\n \"source\": \"iana\",\n \"extensions\": [\"atc\",\"acutc\"]\n },\n \"application/vnd.adobe.air-application-installer-package+zip\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"air\"]\n },\n \"application/vnd.adobe.flash.movie\": {\n \"source\": \"iana\"\n },\n \"application/vnd.adobe.formscentral.fcdt\": {\n \"source\": \"iana\",\n \"extensions\": [\"fcdt\"]\n },\n \"application/vnd.adobe.fxp\": {\n \"source\": \"iana\",\n \"extensions\": [\"fxp\",\"fxpl\"]\n },\n \"application/vnd.adobe.partial-upload\": {\n \"source\": \"iana\"\n },\n \"application/vnd.adobe.xdp+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xdp\"]\n },\n \"application/vnd.adobe.xfdf\": {\n \"source\": \"apache\",\n \"extensions\": [\"xfdf\"]\n },\n \"application/vnd.aether.imp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.afplinedata\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.afplinedata-pagedef\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.cmoca-cmresource\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.foca-charset\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.foca-codedfont\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.foca-codepage\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.modca\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.modca-cmtable\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.modca-formdef\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.modca-mediummap\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.modca-objectcontainer\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.modca-overlay\": {\n \"source\": \"iana\"\n },\n \"application/vnd.afpc.modca-pagesegment\": {\n \"source\": \"iana\"\n },\n \"application/vnd.age\": {\n \"source\": \"iana\",\n \"extensions\": [\"age\"]\n },\n \"application/vnd.ah-barcode\": {\n \"source\": \"apache\"\n },\n \"application/vnd.ahead.space\": {\n \"source\": \"iana\",\n \"extensions\": [\"ahead\"]\n },\n \"application/vnd.airzip.filesecure.azf\": {\n \"source\": \"iana\",\n \"extensions\": [\"azf\"]\n },\n \"application/vnd.airzip.filesecure.azs\": {\n \"source\": \"iana\",\n \"extensions\": [\"azs\"]\n },\n \"application/vnd.amadeus+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.amazon.ebook\": {\n \"source\": \"apache\",\n \"extensions\": [\"azw\"]\n },\n \"application/vnd.amazon.mobi8-ebook\": {\n \"source\": \"iana\"\n },\n \"application/vnd.americandynamics.acc\": {\n \"source\": \"iana\",\n \"extensions\": [\"acc\"]\n },\n \"application/vnd.amiga.ami\": {\n \"source\": \"iana\",\n \"extensions\": [\"ami\"]\n },\n \"application/vnd.amundsen.maze+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.android.ota\": {\n \"source\": \"iana\"\n },\n \"application/vnd.android.package-archive\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"apk\"]\n },\n \"application/vnd.anki\": {\n \"source\": \"iana\"\n },\n \"application/vnd.anser-web-certificate-issue-initiation\": {\n \"source\": \"iana\",\n \"extensions\": [\"cii\"]\n },\n \"application/vnd.anser-web-funds-transfer-initiation\": {\n \"source\": \"apache\",\n \"extensions\": [\"fti\"]\n },\n \"application/vnd.antix.game-component\": {\n \"source\": \"iana\",\n \"extensions\": [\"atx\"]\n },\n \"application/vnd.apache.arrow.file\": {\n \"source\": \"iana\"\n },\n \"application/vnd.apache.arrow.stream\": {\n \"source\": \"iana\"\n },\n \"application/vnd.apache.parquet\": {\n \"source\": \"iana\"\n },\n \"application/vnd.apache.thrift.binary\": {\n \"source\": \"iana\"\n },\n \"application/vnd.apache.thrift.compact\": {\n \"source\": \"iana\"\n },\n \"application/vnd.apache.thrift.json\": {\n \"source\": \"iana\"\n },\n \"application/vnd.apexlang\": {\n \"source\": \"iana\"\n },\n \"application/vnd.api+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.aplextor.warrp+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.apothekende.reservation+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.apple.installer+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mpkg\"]\n },\n \"application/vnd.apple.keynote\": {\n \"source\": \"iana\",\n \"extensions\": [\"key\"]\n },\n \"application/vnd.apple.mpegurl\": {\n \"source\": \"iana\",\n \"extensions\": [\"m3u8\"]\n },\n \"application/vnd.apple.numbers\": {\n \"source\": \"iana\",\n \"extensions\": [\"numbers\"]\n },\n \"application/vnd.apple.pages\": {\n \"source\": \"iana\",\n \"extensions\": [\"pages\"]\n },\n \"application/vnd.apple.pkpass\": {\n \"compressible\": false,\n \"extensions\": [\"pkpass\"]\n },\n \"application/vnd.arastra.swi\": {\n \"source\": \"apache\"\n },\n \"application/vnd.aristanetworks.swi\": {\n \"source\": \"iana\",\n \"extensions\": [\"swi\"]\n },\n \"application/vnd.artisan+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.artsquare\": {\n \"source\": \"iana\"\n },\n \"application/vnd.astraea-software.iota\": {\n \"source\": \"iana\",\n \"extensions\": [\"iota\"]\n },\n \"application/vnd.audiograph\": {\n \"source\": \"iana\",\n \"extensions\": [\"aep\"]\n },\n \"application/vnd.autodesk.fbx\": {\n \"extensions\": [\"fbx\"]\n },\n \"application/vnd.autopackage\": {\n \"source\": \"iana\"\n },\n \"application/vnd.avalon+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.avistar+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.balsamiq.bmml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"bmml\"]\n },\n \"application/vnd.balsamiq.bmpr\": {\n \"source\": \"iana\"\n },\n \"application/vnd.banana-accounting\": {\n \"source\": \"iana\"\n },\n \"application/vnd.bbf.usp.error\": {\n \"source\": \"iana\"\n },\n \"application/vnd.bbf.usp.msg\": {\n \"source\": \"iana\"\n },\n \"application/vnd.bbf.usp.msg+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.bekitzur-stech+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.belightsoft.lhzd+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.belightsoft.lhzl+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.bint.med-content\": {\n \"source\": \"iana\"\n },\n \"application/vnd.biopax.rdf+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.blink-idb-value-wrapper\": {\n \"source\": \"iana\"\n },\n \"application/vnd.blueice.multipass\": {\n \"source\": \"iana\",\n \"extensions\": [\"mpm\"]\n },\n \"application/vnd.bluetooth.ep.oob\": {\n \"source\": \"iana\"\n },\n \"application/vnd.bluetooth.le.oob\": {\n \"source\": \"iana\"\n },\n \"application/vnd.bmi\": {\n \"source\": \"iana\",\n \"extensions\": [\"bmi\"]\n },\n \"application/vnd.bpf\": {\n \"source\": \"iana\"\n },\n \"application/vnd.bpf3\": {\n \"source\": \"iana\"\n },\n \"application/vnd.businessobjects\": {\n \"source\": \"iana\",\n \"extensions\": [\"rep\"]\n },\n \"application/vnd.byu.uapi+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.bzip3\": {\n \"source\": \"iana\"\n },\n \"application/vnd.c3voc.schedule+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.cab-jscript\": {\n \"source\": \"iana\"\n },\n \"application/vnd.canon-cpdl\": {\n \"source\": \"iana\"\n },\n \"application/vnd.canon-lips\": {\n \"source\": \"iana\"\n },\n \"application/vnd.capasystems-pg+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.cendio.thinlinc.clientconf\": {\n \"source\": \"iana\"\n },\n \"application/vnd.century-systems.tcp_stream\": {\n \"source\": \"iana\"\n },\n \"application/vnd.chemdraw+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"cdxml\"]\n },\n \"application/vnd.chess-pgn\": {\n \"source\": \"iana\"\n },\n \"application/vnd.chipnuts.karaoke-mmd\": {\n \"source\": \"iana\",\n \"extensions\": [\"mmd\"]\n },\n \"application/vnd.ciedi\": {\n \"source\": \"iana\"\n },\n \"application/vnd.cinderella\": {\n \"source\": \"iana\",\n \"extensions\": [\"cdy\"]\n },\n \"application/vnd.cirpack.isdn-ext\": {\n \"source\": \"iana\"\n },\n \"application/vnd.citationstyles.style+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"csl\"]\n },\n \"application/vnd.claymore\": {\n \"source\": \"iana\",\n \"extensions\": [\"cla\"]\n },\n \"application/vnd.cloanto.rp9\": {\n \"source\": \"iana\",\n \"extensions\": [\"rp9\"]\n },\n \"application/vnd.clonk.c4group\": {\n \"source\": \"iana\",\n \"extensions\": [\"c4g\",\"c4d\",\"c4f\",\"c4p\",\"c4u\"]\n },\n \"application/vnd.cluetrust.cartomobile-config\": {\n \"source\": \"iana\",\n \"extensions\": [\"c11amc\"]\n },\n \"application/vnd.cluetrust.cartomobile-config-pkg\": {\n \"source\": \"iana\",\n \"extensions\": [\"c11amz\"]\n },\n \"application/vnd.cncf.helm.chart.content.v1.tar+gzip\": {\n \"source\": \"iana\"\n },\n \"application/vnd.cncf.helm.chart.provenance.v1.prov\": {\n \"source\": \"iana\"\n },\n \"application/vnd.cncf.helm.config.v1+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.coffeescript\": {\n \"source\": \"iana\"\n },\n \"application/vnd.collabio.xodocuments.document\": {\n \"source\": \"iana\"\n },\n \"application/vnd.collabio.xodocuments.document-template\": {\n \"source\": \"iana\"\n },\n \"application/vnd.collabio.xodocuments.presentation\": {\n \"source\": \"iana\"\n },\n \"application/vnd.collabio.xodocuments.presentation-template\": {\n \"source\": \"iana\"\n },\n \"application/vnd.collabio.xodocuments.spreadsheet\": {\n \"source\": \"iana\"\n },\n \"application/vnd.collabio.xodocuments.spreadsheet-template\": {\n \"source\": \"iana\"\n },\n \"application/vnd.collection+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.collection.doc+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.collection.next+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.comicbook+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.comicbook-rar\": {\n \"source\": \"iana\"\n },\n \"application/vnd.commerce-battelle\": {\n \"source\": \"iana\"\n },\n \"application/vnd.commonspace\": {\n \"source\": \"iana\",\n \"extensions\": [\"csp\"]\n },\n \"application/vnd.contact.cmsg\": {\n \"source\": \"iana\",\n \"extensions\": [\"cdbcmsg\"]\n },\n \"application/vnd.coreos.ignition+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.cosmocaller\": {\n \"source\": \"iana\",\n \"extensions\": [\"cmc\"]\n },\n \"application/vnd.crick.clicker\": {\n \"source\": \"iana\",\n \"extensions\": [\"clkx\"]\n },\n \"application/vnd.crick.clicker.keyboard\": {\n \"source\": \"iana\",\n \"extensions\": [\"clkk\"]\n },\n \"application/vnd.crick.clicker.palette\": {\n \"source\": \"iana\",\n \"extensions\": [\"clkp\"]\n },\n \"application/vnd.crick.clicker.template\": {\n \"source\": \"iana\",\n \"extensions\": [\"clkt\"]\n },\n \"application/vnd.crick.clicker.wordbank\": {\n \"source\": \"iana\",\n \"extensions\": [\"clkw\"]\n },\n \"application/vnd.criticaltools.wbs+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"wbs\"]\n },\n \"application/vnd.cryptii.pipe+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.crypto-shade-file\": {\n \"source\": \"iana\"\n },\n \"application/vnd.cryptomator.encrypted\": {\n \"source\": \"iana\"\n },\n \"application/vnd.cryptomator.vault\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ctc-posml\": {\n \"source\": \"iana\",\n \"extensions\": [\"pml\"]\n },\n \"application/vnd.ctct.ws+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.cups-pdf\": {\n \"source\": \"iana\"\n },\n \"application/vnd.cups-postscript\": {\n \"source\": \"iana\"\n },\n \"application/vnd.cups-ppd\": {\n \"source\": \"iana\",\n \"extensions\": [\"ppd\"]\n },\n \"application/vnd.cups-raster\": {\n \"source\": \"iana\"\n },\n \"application/vnd.cups-raw\": {\n \"source\": \"iana\"\n },\n \"application/vnd.curl\": {\n \"source\": \"iana\"\n },\n \"application/vnd.curl.car\": {\n \"source\": \"apache\",\n \"extensions\": [\"car\"]\n },\n \"application/vnd.curl.pcurl\": {\n \"source\": \"apache\",\n \"extensions\": [\"pcurl\"]\n },\n \"application/vnd.cyan.dean.root+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.cybank\": {\n \"source\": \"iana\"\n },\n \"application/vnd.cyclonedx+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.cyclonedx+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.d2l.coursepackage1p0+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.d3m-dataset\": {\n \"source\": \"iana\"\n },\n \"application/vnd.d3m-problem\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dart\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"dart\"]\n },\n \"application/vnd.data-vision.rdz\": {\n \"source\": \"iana\",\n \"extensions\": [\"rdz\"]\n },\n \"application/vnd.datalog\": {\n \"source\": \"iana\"\n },\n \"application/vnd.datapackage+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dataresource+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dbf\": {\n \"source\": \"iana\",\n \"extensions\": [\"dbf\"]\n },\n \"application/vnd.dcmp+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"dcmp\"]\n },\n \"application/vnd.debian.binary-package\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dece.data\": {\n \"source\": \"iana\",\n \"extensions\": [\"uvf\",\"uvvf\",\"uvd\",\"uvvd\"]\n },\n \"application/vnd.dece.ttml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"uvt\",\"uvvt\"]\n },\n \"application/vnd.dece.unspecified\": {\n \"source\": \"iana\",\n \"extensions\": [\"uvx\",\"uvvx\"]\n },\n \"application/vnd.dece.zip\": {\n \"source\": \"iana\",\n \"extensions\": [\"uvz\",\"uvvz\"]\n },\n \"application/vnd.denovo.fcselayout-link\": {\n \"source\": \"iana\",\n \"extensions\": [\"fe_launch\"]\n },\n \"application/vnd.desmume.movie\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dir-bi.plate-dl-nosuffix\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dm.delegation+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dna\": {\n \"source\": \"iana\",\n \"extensions\": [\"dna\"]\n },\n \"application/vnd.document+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dolby.mlp\": {\n \"source\": \"apache\",\n \"extensions\": [\"mlp\"]\n },\n \"application/vnd.dolby.mobile.1\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dolby.mobile.2\": {\n \"source\": \"iana\"\n },\n \"application/vnd.doremir.scorecloud-binary-document\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dpgraph\": {\n \"source\": \"iana\",\n \"extensions\": [\"dpg\"]\n },\n \"application/vnd.dreamfactory\": {\n \"source\": \"iana\",\n \"extensions\": [\"dfac\"]\n },\n \"application/vnd.drive+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ds-keypoint\": {\n \"source\": \"apache\",\n \"extensions\": [\"kpxx\"]\n },\n \"application/vnd.dtg.local\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dtg.local.flash\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dtg.local.html\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.ait\": {\n \"source\": \"iana\",\n \"extensions\": [\"ait\"]\n },\n \"application/vnd.dvb.dvbisl+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dvb.dvbj\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.esgcontainer\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.ipdcdftnotifaccess\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.ipdcesgaccess\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.ipdcesgaccess2\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.ipdcesgpdd\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.ipdcroaming\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.iptv.alfec-base\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.iptv.alfec-enhancement\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.notif-aggregate-root+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dvb.notif-container+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dvb.notif-generic+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dvb.notif-ia-msglist+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dvb.notif-ia-registration-request+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dvb.notif-ia-registration-response+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dvb.notif-init+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.dvb.pfr\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dvb.service\": {\n \"source\": \"iana\",\n \"extensions\": [\"svc\"]\n },\n \"application/vnd.dxr\": {\n \"source\": \"iana\"\n },\n \"application/vnd.dynageo\": {\n \"source\": \"iana\",\n \"extensions\": [\"geo\"]\n },\n \"application/vnd.dzr\": {\n \"source\": \"iana\"\n },\n \"application/vnd.easykaraoke.cdgdownload\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ecdis-update\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ecip.rlp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.eclipse.ditto+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ecowin.chart\": {\n \"source\": \"iana\",\n \"extensions\": [\"mag\"]\n },\n \"application/vnd.ecowin.filerequest\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ecowin.fileupdate\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ecowin.series\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ecowin.seriesrequest\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ecowin.seriesupdate\": {\n \"source\": \"iana\"\n },\n \"application/vnd.efi.img\": {\n \"source\": \"iana\"\n },\n \"application/vnd.efi.iso\": {\n \"source\": \"iana\"\n },\n \"application/vnd.eln+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.emclient.accessrequest+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.enliven\": {\n \"source\": \"iana\",\n \"extensions\": [\"nml\"]\n },\n \"application/vnd.enphase.envoy\": {\n \"source\": \"iana\"\n },\n \"application/vnd.eprints.data+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.epson.esf\": {\n \"source\": \"iana\",\n \"extensions\": [\"esf\"]\n },\n \"application/vnd.epson.msf\": {\n \"source\": \"iana\",\n \"extensions\": [\"msf\"]\n },\n \"application/vnd.epson.quickanime\": {\n \"source\": \"iana\",\n \"extensions\": [\"qam\"]\n },\n \"application/vnd.epson.salt\": {\n \"source\": \"iana\",\n \"extensions\": [\"slt\"]\n },\n \"application/vnd.epson.ssf\": {\n \"source\": \"iana\",\n \"extensions\": [\"ssf\"]\n },\n \"application/vnd.ericsson.quickcall\": {\n \"source\": \"iana\"\n },\n \"application/vnd.erofs\": {\n \"source\": \"iana\"\n },\n \"application/vnd.espass-espass+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.eszigno3+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"es3\",\"et3\"]\n },\n \"application/vnd.etsi.aoc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.asic-e+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.etsi.asic-s+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.etsi.cug+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.iptvcommand+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.iptvdiscovery+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.iptvprofile+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.iptvsad-bc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.iptvsad-cod+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.iptvsad-npvr+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.iptvservice+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.iptvsync+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.iptvueprofile+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.mcid+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.mheg5\": {\n \"source\": \"iana\"\n },\n \"application/vnd.etsi.overload-control-policy-dataset+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.pstn+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.sci+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.simservs+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.timestamp-token\": {\n \"source\": \"iana\"\n },\n \"application/vnd.etsi.tsl+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.etsi.tsl.der\": {\n \"source\": \"iana\"\n },\n \"application/vnd.eu.kasparian.car+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.eudora.data\": {\n \"source\": \"iana\"\n },\n \"application/vnd.evolv.ecig.profile\": {\n \"source\": \"iana\"\n },\n \"application/vnd.evolv.ecig.settings\": {\n \"source\": \"iana\"\n },\n \"application/vnd.evolv.ecig.theme\": {\n \"source\": \"iana\"\n },\n \"application/vnd.exstream-empower+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.exstream-package\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ezpix-album\": {\n \"source\": \"iana\",\n \"extensions\": [\"ez2\"]\n },\n \"application/vnd.ezpix-package\": {\n \"source\": \"iana\",\n \"extensions\": [\"ez3\"]\n },\n \"application/vnd.f-secure.mobile\": {\n \"source\": \"iana\"\n },\n \"application/vnd.familysearch.gedcom+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.fastcopy-disk-image\": {\n \"source\": \"iana\"\n },\n \"application/vnd.fdf\": {\n \"source\": \"apache\",\n \"extensions\": [\"fdf\"]\n },\n \"application/vnd.fdsn.mseed\": {\n \"source\": \"iana\",\n \"extensions\": [\"mseed\"]\n },\n \"application/vnd.fdsn.seed\": {\n \"source\": \"iana\",\n \"extensions\": [\"seed\",\"dataless\"]\n },\n \"application/vnd.fdsn.stationxml+xml\": {\n \"source\": \"iana\",\n \"charset\": \"XML-BASED\",\n \"compressible\": true\n },\n \"application/vnd.ffsns\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ficlab.flb+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.filmit.zfc\": {\n \"source\": \"iana\"\n },\n \"application/vnd.fints\": {\n \"source\": \"iana\"\n },\n \"application/vnd.firemonkeys.cloudcell\": {\n \"source\": \"iana\"\n },\n \"application/vnd.flographit\": {\n \"source\": \"iana\",\n \"extensions\": [\"gph\"]\n },\n \"application/vnd.fluxtime.clip\": {\n \"source\": \"iana\",\n \"extensions\": [\"ftc\"]\n },\n \"application/vnd.font-fontforge-sfd\": {\n \"source\": \"iana\"\n },\n \"application/vnd.framemaker\": {\n \"source\": \"iana\",\n \"extensions\": [\"fm\",\"frame\",\"maker\",\"book\"]\n },\n \"application/vnd.freelog.comic\": {\n \"source\": \"iana\"\n },\n \"application/vnd.frogans.fnc\": {\n \"source\": \"apache\",\n \"extensions\": [\"fnc\"]\n },\n \"application/vnd.frogans.ltf\": {\n \"source\": \"apache\",\n \"extensions\": [\"ltf\"]\n },\n \"application/vnd.fsc.weblaunch\": {\n \"source\": \"iana\",\n \"extensions\": [\"fsc\"]\n },\n \"application/vnd.fujifilm.fb.docuworks\": {\n \"source\": \"iana\"\n },\n \"application/vnd.fujifilm.fb.docuworks.binder\": {\n \"source\": \"iana\"\n },\n \"application/vnd.fujifilm.fb.docuworks.container\": {\n \"source\": \"iana\"\n },\n \"application/vnd.fujifilm.fb.jfi+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.fujitsu.oasys\": {\n \"source\": \"iana\",\n \"extensions\": [\"oas\"]\n },\n \"application/vnd.fujitsu.oasys2\": {\n \"source\": \"iana\",\n \"extensions\": [\"oa2\"]\n },\n \"application/vnd.fujitsu.oasys3\": {\n \"source\": \"iana\",\n \"extensions\": [\"oa3\"]\n },\n \"application/vnd.fujitsu.oasysgp\": {\n \"source\": \"iana\",\n \"extensions\": [\"fg5\"]\n },\n \"application/vnd.fujitsu.oasysprs\": {\n \"source\": \"iana\",\n \"extensions\": [\"bh2\"]\n },\n \"application/vnd.fujixerox.art-ex\": {\n \"source\": \"iana\"\n },\n \"application/vnd.fujixerox.art4\": {\n \"source\": \"iana\"\n },\n \"application/vnd.fujixerox.ddd\": {\n \"source\": \"iana\",\n \"extensions\": [\"ddd\"]\n },\n \"application/vnd.fujixerox.docuworks\": {\n \"source\": \"iana\",\n \"extensions\": [\"xdw\"]\n },\n \"application/vnd.fujixerox.docuworks.binder\": {\n \"source\": \"iana\",\n \"extensions\": [\"xbd\"]\n },\n \"application/vnd.fujixerox.docuworks.container\": {\n \"source\": \"iana\"\n },\n \"application/vnd.fujixerox.hbpl\": {\n \"source\": \"iana\"\n },\n \"application/vnd.fut-misnet\": {\n \"source\": \"iana\"\n },\n \"application/vnd.futoin+cbor\": {\n \"source\": \"iana\"\n },\n \"application/vnd.futoin+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.fuzzysheet\": {\n \"source\": \"iana\",\n \"extensions\": [\"fzs\"]\n },\n \"application/vnd.ga4gh.passport+jwt\": {\n \"source\": \"iana\"\n },\n \"application/vnd.genomatix.tuxedo\": {\n \"source\": \"iana\",\n \"extensions\": [\"txd\"]\n },\n \"application/vnd.genozip\": {\n \"source\": \"iana\"\n },\n \"application/vnd.gentics.grd+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.gentoo.catmetadata+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.gentoo.ebuild\": {\n \"source\": \"iana\"\n },\n \"application/vnd.gentoo.eclass\": {\n \"source\": \"iana\"\n },\n \"application/vnd.gentoo.gpkg\": {\n \"source\": \"iana\"\n },\n \"application/vnd.gentoo.manifest\": {\n \"source\": \"iana\"\n },\n \"application/vnd.gentoo.pkgmetadata+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.gentoo.xpak\": {\n \"source\": \"iana\"\n },\n \"application/vnd.geo+json\": {\n \"source\": \"apache\",\n \"compressible\": true\n },\n \"application/vnd.geocube+xml\": {\n \"source\": \"apache\",\n \"compressible\": true\n },\n \"application/vnd.geogebra.file\": {\n \"source\": \"iana\",\n \"extensions\": [\"ggb\"]\n },\n \"application/vnd.geogebra.pinboard\": {\n \"source\": \"iana\"\n },\n \"application/vnd.geogebra.slides\": {\n \"source\": \"iana\",\n \"extensions\": [\"ggs\"]\n },\n \"application/vnd.geogebra.tool\": {\n \"source\": \"iana\",\n \"extensions\": [\"ggt\"]\n },\n \"application/vnd.geometry-explorer\": {\n \"source\": \"iana\",\n \"extensions\": [\"gex\",\"gre\"]\n },\n \"application/vnd.geonext\": {\n \"source\": \"iana\",\n \"extensions\": [\"gxt\"]\n },\n \"application/vnd.geoplan\": {\n \"source\": \"iana\",\n \"extensions\": [\"g2w\"]\n },\n \"application/vnd.geospace\": {\n \"source\": \"iana\",\n \"extensions\": [\"g3w\"]\n },\n \"application/vnd.gerber\": {\n \"source\": \"iana\"\n },\n \"application/vnd.globalplatform.card-content-mgt\": {\n \"source\": \"iana\"\n },\n \"application/vnd.globalplatform.card-content-mgt-response\": {\n \"source\": \"iana\"\n },\n \"application/vnd.gmx\": {\n \"source\": \"iana\",\n \"extensions\": [\"gmx\"]\n },\n \"application/vnd.gnu.taler.exchange+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.gnu.taler.merchant+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.google-apps.audio\": {},\n \"application/vnd.google-apps.document\": {\n \"compressible\": false,\n \"extensions\": [\"gdoc\"]\n },\n \"application/vnd.google-apps.drawing\": {\n \"compressible\": false,\n \"extensions\": [\"gdraw\"]\n },\n \"application/vnd.google-apps.drive-sdk\": {\n \"compressible\": false\n },\n \"application/vnd.google-apps.file\": {},\n \"application/vnd.google-apps.folder\": {\n \"compressible\": false\n },\n \"application/vnd.google-apps.form\": {\n \"compressible\": false,\n \"extensions\": [\"gform\"]\n },\n \"application/vnd.google-apps.fusiontable\": {},\n \"application/vnd.google-apps.jam\": {\n \"compressible\": false,\n \"extensions\": [\"gjam\"]\n },\n \"application/vnd.google-apps.mail-layout\": {},\n \"application/vnd.google-apps.map\": {\n \"compressible\": false,\n \"extensions\": [\"gmap\"]\n },\n \"application/vnd.google-apps.photo\": {},\n \"application/vnd.google-apps.presentation\": {\n \"compressible\": false,\n \"extensions\": [\"gslides\"]\n },\n \"application/vnd.google-apps.script\": {\n \"compressible\": false,\n \"extensions\": [\"gscript\"]\n },\n \"application/vnd.google-apps.shortcut\": {},\n \"application/vnd.google-apps.site\": {\n \"compressible\": false,\n \"extensions\": [\"gsite\"]\n },\n \"application/vnd.google-apps.spreadsheet\": {\n \"compressible\": false,\n \"extensions\": [\"gsheet\"]\n },\n \"application/vnd.google-apps.unknown\": {},\n \"application/vnd.google-apps.video\": {},\n \"application/vnd.google-earth.kml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"kml\"]\n },\n \"application/vnd.google-earth.kmz\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"kmz\"]\n },\n \"application/vnd.gov.sk.e-form+xml\": {\n \"source\": \"apache\",\n \"compressible\": true\n },\n \"application/vnd.gov.sk.e-form+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.gov.sk.xmldatacontainer+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xdcf\"]\n },\n \"application/vnd.gpxsee.map+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.grafeq\": {\n \"source\": \"iana\",\n \"extensions\": [\"gqf\",\"gqs\"]\n },\n \"application/vnd.gridmp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.groove-account\": {\n \"source\": \"iana\",\n \"extensions\": [\"gac\"]\n },\n \"application/vnd.groove-help\": {\n \"source\": \"iana\",\n \"extensions\": [\"ghf\"]\n },\n \"application/vnd.groove-identity-message\": {\n \"source\": \"iana\",\n \"extensions\": [\"gim\"]\n },\n \"application/vnd.groove-injector\": {\n \"source\": \"iana\",\n \"extensions\": [\"grv\"]\n },\n \"application/vnd.groove-tool-message\": {\n \"source\": \"iana\",\n \"extensions\": [\"gtm\"]\n },\n \"application/vnd.groove-tool-template\": {\n \"source\": \"iana\",\n \"extensions\": [\"tpl\"]\n },\n \"application/vnd.groove-vcard\": {\n \"source\": \"iana\",\n \"extensions\": [\"vcg\"]\n },\n \"application/vnd.hal+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.hal+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"hal\"]\n },\n \"application/vnd.handheld-entertainment+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"zmm\"]\n },\n \"application/vnd.hbci\": {\n \"source\": \"iana\",\n \"extensions\": [\"hbci\"]\n },\n \"application/vnd.hc+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.hcl-bireports\": {\n \"source\": \"iana\"\n },\n \"application/vnd.hdt\": {\n \"source\": \"iana\"\n },\n \"application/vnd.heroku+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.hhe.lesson-player\": {\n \"source\": \"iana\",\n \"extensions\": [\"les\"]\n },\n \"application/vnd.hp-hpgl\": {\n \"source\": \"iana\",\n \"extensions\": [\"hpgl\"]\n },\n \"application/vnd.hp-hpid\": {\n \"source\": \"iana\",\n \"extensions\": [\"hpid\"]\n },\n \"application/vnd.hp-hps\": {\n \"source\": \"iana\",\n \"extensions\": [\"hps\"]\n },\n \"application/vnd.hp-jlyt\": {\n \"source\": \"iana\",\n \"extensions\": [\"jlt\"]\n },\n \"application/vnd.hp-pcl\": {\n \"source\": \"iana\",\n \"extensions\": [\"pcl\"]\n },\n \"application/vnd.hp-pclxl\": {\n \"source\": \"iana\",\n \"extensions\": [\"pclxl\"]\n },\n \"application/vnd.hsl\": {\n \"source\": \"iana\"\n },\n \"application/vnd.httphone\": {\n \"source\": \"iana\"\n },\n \"application/vnd.hydrostatix.sof-data\": {\n \"source\": \"iana\",\n \"extensions\": [\"sfd-hdstx\"]\n },\n \"application/vnd.hyper+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.hyper-item+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.hyperdrive+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.hzn-3d-crossword\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ibm.afplinedata\": {\n \"source\": \"apache\"\n },\n \"application/vnd.ibm.electronic-media\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ibm.minipay\": {\n \"source\": \"iana\",\n \"extensions\": [\"mpy\"]\n },\n \"application/vnd.ibm.modcap\": {\n \"source\": \"apache\",\n \"extensions\": [\"afp\",\"listafp\",\"list3820\"]\n },\n \"application/vnd.ibm.rights-management\": {\n \"source\": \"iana\",\n \"extensions\": [\"irm\"]\n },\n \"application/vnd.ibm.secure-container\": {\n \"source\": \"iana\",\n \"extensions\": [\"sc\"]\n },\n \"application/vnd.iccprofile\": {\n \"source\": \"iana\",\n \"extensions\": [\"icc\",\"icm\"]\n },\n \"application/vnd.ieee.1905\": {\n \"source\": \"iana\"\n },\n \"application/vnd.igloader\": {\n \"source\": \"iana\",\n \"extensions\": [\"igl\"]\n },\n \"application/vnd.imagemeter.folder+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.imagemeter.image+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.immervision-ivp\": {\n \"source\": \"iana\",\n \"extensions\": [\"ivp\"]\n },\n \"application/vnd.immervision-ivu\": {\n \"source\": \"iana\",\n \"extensions\": [\"ivu\"]\n },\n \"application/vnd.ims.imsccv1p1\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ims.imsccv1p2\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ims.imsccv1p3\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ims.lis.v2.result+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ims.lti.v2.toolconsumerprofile+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ims.lti.v2.toolproxy+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ims.lti.v2.toolproxy.id+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ims.lti.v2.toolsettings+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ims.lti.v2.toolsettings.simple+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.informedcontrol.rms+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.informix-visionary\": {\n \"source\": \"apache\"\n },\n \"application/vnd.infotech.project\": {\n \"source\": \"iana\"\n },\n \"application/vnd.infotech.project+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.innopath.wamp.notification\": {\n \"source\": \"iana\"\n },\n \"application/vnd.insors.igm\": {\n \"source\": \"iana\",\n \"extensions\": [\"igm\"]\n },\n \"application/vnd.intercon.formnet\": {\n \"source\": \"iana\",\n \"extensions\": [\"xpw\",\"xpx\"]\n },\n \"application/vnd.intergeo\": {\n \"source\": \"iana\",\n \"extensions\": [\"i2g\"]\n },\n \"application/vnd.intertrust.digibox\": {\n \"source\": \"iana\"\n },\n \"application/vnd.intertrust.nncp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.intu.qbo\": {\n \"source\": \"iana\",\n \"extensions\": [\"qbo\"]\n },\n \"application/vnd.intu.qfx\": {\n \"source\": \"iana\",\n \"extensions\": [\"qfx\"]\n },\n \"application/vnd.ipfs.ipns-record\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ipld.car\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ipld.dag-cbor\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ipld.dag-json\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ipld.raw\": {\n \"source\": \"iana\"\n },\n \"application/vnd.iptc.g2.catalogitem+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.iptc.g2.conceptitem+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.iptc.g2.knowledgeitem+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.iptc.g2.newsitem+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.iptc.g2.newsmessage+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.iptc.g2.packageitem+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.iptc.g2.planningitem+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ipunplugged.rcprofile\": {\n \"source\": \"iana\",\n \"extensions\": [\"rcprofile\"]\n },\n \"application/vnd.irepository.package+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"irp\"]\n },\n \"application/vnd.is-xpr\": {\n \"source\": \"iana\",\n \"extensions\": [\"xpr\"]\n },\n \"application/vnd.isac.fcs\": {\n \"source\": \"iana\",\n \"extensions\": [\"fcs\"]\n },\n \"application/vnd.iso11783-10+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.jam\": {\n \"source\": \"iana\",\n \"extensions\": [\"jam\"]\n },\n \"application/vnd.japannet-directory-service\": {\n \"source\": \"iana\"\n },\n \"application/vnd.japannet-jpnstore-wakeup\": {\n \"source\": \"iana\"\n },\n \"application/vnd.japannet-payment-wakeup\": {\n \"source\": \"iana\"\n },\n \"application/vnd.japannet-registration\": {\n \"source\": \"iana\"\n },\n \"application/vnd.japannet-registration-wakeup\": {\n \"source\": \"iana\"\n },\n \"application/vnd.japannet-setstore-wakeup\": {\n \"source\": \"iana\"\n },\n \"application/vnd.japannet-verification\": {\n \"source\": \"iana\"\n },\n \"application/vnd.japannet-verification-wakeup\": {\n \"source\": \"iana\"\n },\n \"application/vnd.jcp.javame.midlet-rms\": {\n \"source\": \"iana\",\n \"extensions\": [\"rms\"]\n },\n \"application/vnd.jisp\": {\n \"source\": \"iana\",\n \"extensions\": [\"jisp\"]\n },\n \"application/vnd.joost.joda-archive\": {\n \"source\": \"iana\",\n \"extensions\": [\"joda\"]\n },\n \"application/vnd.jsk.isdn-ngn\": {\n \"source\": \"iana\"\n },\n \"application/vnd.kahootz\": {\n \"source\": \"iana\",\n \"extensions\": [\"ktz\",\"ktr\"]\n },\n \"application/vnd.kde.karbon\": {\n \"source\": \"iana\",\n \"extensions\": [\"karbon\"]\n },\n \"application/vnd.kde.kchart\": {\n \"source\": \"iana\",\n \"extensions\": [\"chrt\"]\n },\n \"application/vnd.kde.kformula\": {\n \"source\": \"iana\",\n \"extensions\": [\"kfo\"]\n },\n \"application/vnd.kde.kivio\": {\n \"source\": \"iana\",\n \"extensions\": [\"flw\"]\n },\n \"application/vnd.kde.kontour\": {\n \"source\": \"iana\",\n \"extensions\": [\"kon\"]\n },\n \"application/vnd.kde.kpresenter\": {\n \"source\": \"iana\",\n \"extensions\": [\"kpr\",\"kpt\"]\n },\n \"application/vnd.kde.kspread\": {\n \"source\": \"iana\",\n \"extensions\": [\"ksp\"]\n },\n \"application/vnd.kde.kword\": {\n \"source\": \"iana\",\n \"extensions\": [\"kwd\",\"kwt\"]\n },\n \"application/vnd.kdl\": {\n \"source\": \"iana\"\n },\n \"application/vnd.kenameaapp\": {\n \"source\": \"iana\",\n \"extensions\": [\"htke\"]\n },\n \"application/vnd.keyman.kmp+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.keyman.kmx\": {\n \"source\": \"iana\"\n },\n \"application/vnd.kidspiration\": {\n \"source\": \"iana\",\n \"extensions\": [\"kia\"]\n },\n \"application/vnd.kinar\": {\n \"source\": \"iana\",\n \"extensions\": [\"kne\",\"knp\"]\n },\n \"application/vnd.koan\": {\n \"source\": \"iana\",\n \"extensions\": [\"skp\",\"skd\",\"skt\",\"skm\"]\n },\n \"application/vnd.kodak-descriptor\": {\n \"source\": \"iana\",\n \"extensions\": [\"sse\"]\n },\n \"application/vnd.las\": {\n \"source\": \"iana\"\n },\n \"application/vnd.las.las+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.las.las+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"lasxml\"]\n },\n \"application/vnd.laszip\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ldev.productlicensing\": {\n \"source\": \"iana\"\n },\n \"application/vnd.leap+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.liberty-request+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.llamagraphics.life-balance.desktop\": {\n \"source\": \"iana\",\n \"extensions\": [\"lbd\"]\n },\n \"application/vnd.llamagraphics.life-balance.exchange+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"lbe\"]\n },\n \"application/vnd.logipipe.circuit+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.loom\": {\n \"source\": \"iana\"\n },\n \"application/vnd.lotus-1-2-3\": {\n \"source\": \"iana\",\n \"extensions\": [\"123\"]\n },\n \"application/vnd.lotus-approach\": {\n \"source\": \"iana\",\n \"extensions\": [\"apr\"]\n },\n \"application/vnd.lotus-freelance\": {\n \"source\": \"iana\",\n \"extensions\": [\"pre\"]\n },\n \"application/vnd.lotus-notes\": {\n \"source\": \"iana\",\n \"extensions\": [\"nsf\"]\n },\n \"application/vnd.lotus-organizer\": {\n \"source\": \"iana\",\n \"extensions\": [\"org\"]\n },\n \"application/vnd.lotus-screencam\": {\n \"source\": \"iana\",\n \"extensions\": [\"scm\"]\n },\n \"application/vnd.lotus-wordpro\": {\n \"source\": \"iana\",\n \"extensions\": [\"lwp\"]\n },\n \"application/vnd.macports.portpkg\": {\n \"source\": \"iana\",\n \"extensions\": [\"portpkg\"]\n },\n \"application/vnd.mapbox-vector-tile\": {\n \"source\": \"iana\",\n \"extensions\": [\"mvt\"]\n },\n \"application/vnd.marlin.drm.actiontoken+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.marlin.drm.conftoken+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.marlin.drm.license+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.marlin.drm.mdcf\": {\n \"source\": \"iana\"\n },\n \"application/vnd.mason+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.maxar.archive.3tz+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.maxmind.maxmind-db\": {\n \"source\": \"iana\"\n },\n \"application/vnd.mcd\": {\n \"source\": \"iana\",\n \"extensions\": [\"mcd\"]\n },\n \"application/vnd.mdl\": {\n \"source\": \"iana\"\n },\n \"application/vnd.mdl-mbsdf\": {\n \"source\": \"iana\"\n },\n \"application/vnd.medcalcdata\": {\n \"source\": \"iana\",\n \"extensions\": [\"mc1\"]\n },\n \"application/vnd.mediastation.cdkey\": {\n \"source\": \"iana\",\n \"extensions\": [\"cdkey\"]\n },\n \"application/vnd.medicalholodeck.recordxr\": {\n \"source\": \"iana\"\n },\n \"application/vnd.meridian-slingshot\": {\n \"source\": \"iana\"\n },\n \"application/vnd.mermaid\": {\n \"source\": \"iana\"\n },\n \"application/vnd.mfer\": {\n \"source\": \"iana\",\n \"extensions\": [\"mwf\"]\n },\n \"application/vnd.mfmp\": {\n \"source\": \"iana\",\n \"extensions\": [\"mfm\"]\n },\n \"application/vnd.micro+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.micrografx.flo\": {\n \"source\": \"iana\",\n \"extensions\": [\"flo\"]\n },\n \"application/vnd.micrografx.igx\": {\n \"source\": \"iana\",\n \"extensions\": [\"igx\"]\n },\n \"application/vnd.microsoft.portable-executable\": {\n \"source\": \"iana\"\n },\n \"application/vnd.microsoft.windows.thumbnail-cache\": {\n \"source\": \"iana\"\n },\n \"application/vnd.miele+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.mif\": {\n \"source\": \"iana\",\n \"extensions\": [\"mif\"]\n },\n \"application/vnd.minisoft-hp3000-save\": {\n \"source\": \"iana\"\n },\n \"application/vnd.mitsubishi.misty-guard.trustweb\": {\n \"source\": \"iana\"\n },\n \"application/vnd.mobius.daf\": {\n \"source\": \"iana\",\n \"extensions\": [\"daf\"]\n },\n \"application/vnd.mobius.dis\": {\n \"source\": \"iana\",\n \"extensions\": [\"dis\"]\n },\n \"application/vnd.mobius.mbk\": {\n \"source\": \"iana\",\n \"extensions\": [\"mbk\"]\n },\n \"application/vnd.mobius.mqy\": {\n \"source\": \"iana\",\n \"extensions\": [\"mqy\"]\n },\n \"application/vnd.mobius.msl\": {\n \"source\": \"iana\",\n \"extensions\": [\"msl\"]\n },\n \"application/vnd.mobius.plc\": {\n \"source\": \"iana\",\n \"extensions\": [\"plc\"]\n },\n \"application/vnd.mobius.txf\": {\n \"source\": \"iana\",\n \"extensions\": [\"txf\"]\n },\n \"application/vnd.modl\": {\n \"source\": \"iana\"\n },\n \"application/vnd.mophun.application\": {\n \"source\": \"iana\",\n \"extensions\": [\"mpn\"]\n },\n \"application/vnd.mophun.certificate\": {\n \"source\": \"iana\",\n \"extensions\": [\"mpc\"]\n },\n \"application/vnd.motorola.flexsuite\": {\n \"source\": \"iana\"\n },\n \"application/vnd.motorola.flexsuite.adsi\": {\n \"source\": \"iana\"\n },\n \"application/vnd.motorola.flexsuite.fis\": {\n \"source\": \"iana\"\n },\n \"application/vnd.motorola.flexsuite.gotap\": {\n \"source\": \"iana\"\n },\n \"application/vnd.motorola.flexsuite.kmr\": {\n \"source\": \"iana\"\n },\n \"application/vnd.motorola.flexsuite.ttc\": {\n \"source\": \"iana\"\n },\n \"application/vnd.motorola.flexsuite.wem\": {\n \"source\": \"iana\"\n },\n \"application/vnd.motorola.iprm\": {\n \"source\": \"iana\"\n },\n \"application/vnd.mozilla.xul+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xul\"]\n },\n \"application/vnd.ms-3mfdocument\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-artgalry\": {\n \"source\": \"iana\",\n \"extensions\": [\"cil\"]\n },\n \"application/vnd.ms-asf\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-cab-compressed\": {\n \"source\": \"iana\",\n \"extensions\": [\"cab\"]\n },\n \"application/vnd.ms-color.iccprofile\": {\n \"source\": \"apache\"\n },\n \"application/vnd.ms-excel\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"xls\",\"xlm\",\"xla\",\"xlc\",\"xlt\",\"xlw\"]\n },\n \"application/vnd.ms-excel.addin.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"xlam\"]\n },\n \"application/vnd.ms-excel.sheet.binary.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"xlsb\"]\n },\n \"application/vnd.ms-excel.sheet.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"xlsm\"]\n },\n \"application/vnd.ms-excel.template.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"xltm\"]\n },\n \"application/vnd.ms-fontobject\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"eot\"]\n },\n \"application/vnd.ms-htmlhelp\": {\n \"source\": \"iana\",\n \"extensions\": [\"chm\"]\n },\n \"application/vnd.ms-ims\": {\n \"source\": \"iana\",\n \"extensions\": [\"ims\"]\n },\n \"application/vnd.ms-lrm\": {\n \"source\": \"iana\",\n \"extensions\": [\"lrm\"]\n },\n \"application/vnd.ms-office.activex+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ms-officetheme\": {\n \"source\": \"iana\",\n \"extensions\": [\"thmx\"]\n },\n \"application/vnd.ms-opentype\": {\n \"source\": \"apache\",\n \"compressible\": true\n },\n \"application/vnd.ms-outlook\": {\n \"compressible\": false,\n \"extensions\": [\"msg\"]\n },\n \"application/vnd.ms-package.obfuscated-opentype\": {\n \"source\": \"apache\"\n },\n \"application/vnd.ms-pki.seccat\": {\n \"source\": \"apache\",\n \"extensions\": [\"cat\"]\n },\n \"application/vnd.ms-pki.stl\": {\n \"source\": \"apache\",\n \"extensions\": [\"stl\"]\n },\n \"application/vnd.ms-playready.initiator+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ms-powerpoint\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"ppt\",\"pps\",\"pot\"]\n },\n \"application/vnd.ms-powerpoint.addin.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"ppam\"]\n },\n \"application/vnd.ms-powerpoint.presentation.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"pptm\"]\n },\n \"application/vnd.ms-powerpoint.slide.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"sldm\"]\n },\n \"application/vnd.ms-powerpoint.slideshow.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"ppsm\"]\n },\n \"application/vnd.ms-powerpoint.template.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"potm\"]\n },\n \"application/vnd.ms-printdevicecapabilities+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ms-printing.printticket+xml\": {\n \"source\": \"apache\",\n \"compressible\": true\n },\n \"application/vnd.ms-printschematicket+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.ms-project\": {\n \"source\": \"iana\",\n \"extensions\": [\"mpp\",\"mpt\"]\n },\n \"application/vnd.ms-tnef\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-visio.viewer\": {\n \"extensions\": [\"vdx\"]\n },\n \"application/vnd.ms-windows.devicepairing\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-windows.nwprinting.oob\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-windows.printerpairing\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-windows.wsd.oob\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-wmdrm.lic-chlg-req\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-wmdrm.lic-resp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-wmdrm.meter-chlg-req\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-wmdrm.meter-resp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ms-word.document.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"docm\"]\n },\n \"application/vnd.ms-word.template.macroenabled.12\": {\n \"source\": \"iana\",\n \"extensions\": [\"dotm\"]\n },\n \"application/vnd.ms-works\": {\n \"source\": \"iana\",\n \"extensions\": [\"wps\",\"wks\",\"wcm\",\"wdb\"]\n },\n \"application/vnd.ms-wpl\": {\n \"source\": \"iana\",\n \"extensions\": [\"wpl\"]\n },\n \"application/vnd.ms-xpsdocument\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"xps\"]\n },\n \"application/vnd.msa-disk-image\": {\n \"source\": \"iana\"\n },\n \"application/vnd.mseq\": {\n \"source\": \"iana\",\n \"extensions\": [\"mseq\"]\n },\n \"application/vnd.msgpack\": {\n \"source\": \"iana\"\n },\n \"application/vnd.msign\": {\n \"source\": \"iana\"\n },\n \"application/vnd.multiad.creator\": {\n \"source\": \"iana\"\n },\n \"application/vnd.multiad.creator.cif\": {\n \"source\": \"iana\"\n },\n \"application/vnd.music-niff\": {\n \"source\": \"iana\"\n },\n \"application/vnd.musician\": {\n \"source\": \"iana\",\n \"extensions\": [\"mus\"]\n },\n \"application/vnd.muvee.style\": {\n \"source\": \"iana\",\n \"extensions\": [\"msty\"]\n },\n \"application/vnd.mynfc\": {\n \"source\": \"iana\",\n \"extensions\": [\"taglet\"]\n },\n \"application/vnd.nacamar.ybrid+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.nato.bindingdataobject+cbor\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nato.bindingdataobject+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.nato.bindingdataobject+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"bdo\"]\n },\n \"application/vnd.nato.openxmlformats-package.iepd+zip\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"application/vnd.ncd.control\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ncd.reference\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nearst.inv+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.nebumind.line\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nervana\": {\n \"source\": \"iana\"\n },\n \"application/vnd.netfpx\": {\n \"source\": \"iana\"\n },\n \"application/vnd.neurolanguage.nlu\": {\n \"source\": \"iana\",\n \"extensions\": [\"nlu\"]\n },\n \"application/vnd.nimn\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nintendo.nitro.rom\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nintendo.snes.rom\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nitf\": {\n \"source\": \"iana\",\n \"extensions\": [\"ntf\",\"nitf\"]\n },\n \"application/vnd.noblenet-directory\": {\n \"source\": \"iana\",\n \"extensions\": [\"nnd\"]\n },\n \"application/vnd.noblenet-sealer\": {\n \"source\": \"iana\",\n \"extensions\": [\"nns\"]\n },\n \"application/vnd.noblenet-web\": {\n \"source\": \"iana\",\n \"extensions\": [\"nnw\"]\n },\n \"application/vnd.nokia.catalogs\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nokia.conml+wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nokia.conml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.nokia.iptv.config+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.nokia.isds-radio-presets\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nokia.landmark+wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nokia.landmark+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.nokia.landmarkcollection+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.nokia.n-gage.ac+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"ac\"]\n },\n \"application/vnd.nokia.n-gage.data\": {\n \"source\": \"iana\",\n \"extensions\": [\"ngdat\"]\n },\n \"application/vnd.nokia.n-gage.symbian.install\": {\n \"source\": \"apache\",\n \"extensions\": [\"n-gage\"]\n },\n \"application/vnd.nokia.ncd\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nokia.pcd+wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.nokia.pcd+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.nokia.radio-preset\": {\n \"source\": \"iana\",\n \"extensions\": [\"rpst\"]\n },\n \"application/vnd.nokia.radio-presets\": {\n \"source\": \"iana\",\n \"extensions\": [\"rpss\"]\n },\n \"application/vnd.novadigm.edm\": {\n \"source\": \"iana\",\n \"extensions\": [\"edm\"]\n },\n \"application/vnd.novadigm.edx\": {\n \"source\": \"iana\",\n \"extensions\": [\"edx\"]\n },\n \"application/vnd.novadigm.ext\": {\n \"source\": \"iana\",\n \"extensions\": [\"ext\"]\n },\n \"application/vnd.ntt-local.content-share\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ntt-local.file-transfer\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ntt-local.ogw_remote-access\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ntt-local.sip-ta_remote\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ntt-local.sip-ta_tcp_stream\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oai.workflows\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oai.workflows+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oai.workflows+yaml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oasis.opendocument.base\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oasis.opendocument.chart\": {\n \"source\": \"iana\",\n \"extensions\": [\"odc\"]\n },\n \"application/vnd.oasis.opendocument.chart-template\": {\n \"source\": \"iana\",\n \"extensions\": [\"otc\"]\n },\n \"application/vnd.oasis.opendocument.database\": {\n \"source\": \"apache\",\n \"extensions\": [\"odb\"]\n },\n \"application/vnd.oasis.opendocument.formula\": {\n \"source\": \"iana\",\n \"extensions\": [\"odf\"]\n },\n \"application/vnd.oasis.opendocument.formula-template\": {\n \"source\": \"iana\",\n \"extensions\": [\"odft\"]\n },\n \"application/vnd.oasis.opendocument.graphics\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"odg\"]\n },\n \"application/vnd.oasis.opendocument.graphics-template\": {\n \"source\": \"iana\",\n \"extensions\": [\"otg\"]\n },\n \"application/vnd.oasis.opendocument.image\": {\n \"source\": \"iana\",\n \"extensions\": [\"odi\"]\n },\n \"application/vnd.oasis.opendocument.image-template\": {\n \"source\": \"iana\",\n \"extensions\": [\"oti\"]\n },\n \"application/vnd.oasis.opendocument.presentation\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"odp\"]\n },\n \"application/vnd.oasis.opendocument.presentation-template\": {\n \"source\": \"iana\",\n \"extensions\": [\"otp\"]\n },\n \"application/vnd.oasis.opendocument.spreadsheet\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"ods\"]\n },\n \"application/vnd.oasis.opendocument.spreadsheet-template\": {\n \"source\": \"iana\",\n \"extensions\": [\"ots\"]\n },\n \"application/vnd.oasis.opendocument.text\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"odt\"]\n },\n \"application/vnd.oasis.opendocument.text-master\": {\n \"source\": \"iana\",\n \"extensions\": [\"odm\"]\n },\n \"application/vnd.oasis.opendocument.text-master-template\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oasis.opendocument.text-template\": {\n \"source\": \"iana\",\n \"extensions\": [\"ott\"]\n },\n \"application/vnd.oasis.opendocument.text-web\": {\n \"source\": \"iana\",\n \"extensions\": [\"oth\"]\n },\n \"application/vnd.obn\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ocf+cbor\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oci.image.manifest.v1+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oftn.l10n+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oipf.contentaccessdownload+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oipf.contentaccessstreaming+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oipf.cspg-hexbinary\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oipf.dae.svg+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oipf.dae.xhtml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oipf.mippvcontrolmessage+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oipf.pae.gem\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oipf.spdiscovery+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oipf.spdlist+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oipf.ueprofile+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oipf.userprofile+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.olpc-sugar\": {\n \"source\": \"iana\",\n \"extensions\": [\"xo\"]\n },\n \"application/vnd.oma-scws-config\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma-scws-http-request\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma-scws-http-response\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.bcast.associated-procedure-parameter+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.bcast.drm-trigger+xml\": {\n \"source\": \"apache\",\n \"compressible\": true\n },\n \"application/vnd.oma.bcast.imd+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.bcast.ltkm\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.bcast.notification+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.bcast.provisioningtrigger\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.bcast.sgboot\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.bcast.sgdd+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.bcast.sgdu\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.bcast.simple-symbol-container\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.bcast.smartcard-trigger+xml\": {\n \"source\": \"apache\",\n \"compressible\": true\n },\n \"application/vnd.oma.bcast.sprov+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.bcast.stkm\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.cab-address-book+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.cab-feature-handler+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.cab-pcc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.cab-subs-invite+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.cab-user-prefs+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.dcd\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.dcdc\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.dd2+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"dd2\"]\n },\n \"application/vnd.oma.drm.risd+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.group-usage-list+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.lwm2m+cbor\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.lwm2m+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.lwm2m+tlv\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.pal+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.poc.detailed-progress-report+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.poc.final-report+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.poc.groups+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.poc.invocation-descriptor+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.poc.optimized-progress-report+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.push\": {\n \"source\": \"iana\"\n },\n \"application/vnd.oma.scidm.messages+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oma.xcap-directory+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.omads-email+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/vnd.omads-file+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/vnd.omads-folder+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/vnd.omaloc-supl-init\": {\n \"source\": \"iana\"\n },\n \"application/vnd.onepager\": {\n \"source\": \"iana\"\n },\n \"application/vnd.onepagertamp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.onepagertamx\": {\n \"source\": \"iana\"\n },\n \"application/vnd.onepagertat\": {\n \"source\": \"iana\"\n },\n \"application/vnd.onepagertatp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.onepagertatx\": {\n \"source\": \"iana\"\n },\n \"application/vnd.onvif.metadata\": {\n \"source\": \"iana\"\n },\n \"application/vnd.openblox.game+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"obgx\"]\n },\n \"application/vnd.openblox.game-binary\": {\n \"source\": \"iana\"\n },\n \"application/vnd.openeye.oeb\": {\n \"source\": \"iana\"\n },\n \"application/vnd.openofficeorg.extension\": {\n \"source\": \"apache\",\n \"extensions\": [\"oxt\"]\n },\n \"application/vnd.openstreetmap.data+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"osm\"]\n },\n \"application/vnd.opentimestamps.ots\": {\n \"source\": \"iana\"\n },\n \"application/vnd.openvpi.dspx+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.custom-properties+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.customxmlproperties+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.drawing+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.drawingml.chart+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.extended-properties+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.comments+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"pptx\"]\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.presprops+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.slide\": {\n \"source\": \"iana\",\n \"extensions\": [\"sldx\"]\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.slide+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.slideshow\": {\n \"source\": \"iana\",\n \"extensions\": [\"ppsx\"]\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.tags+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.template\": {\n \"source\": \"iana\",\n \"extensions\": [\"potx\"]\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.template.main+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"xlsx\"]\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.template\": {\n \"source\": \"iana\",\n \"extensions\": [\"xltx\"]\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.theme+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.themeoverride+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.vmldrawing\": {\n \"source\": \"iana\"\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"docx\"]\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.template\": {\n \"source\": \"iana\",\n \"extensions\": [\"dotx\"]\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-package.core-properties+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.openxmlformats-package.relationships+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oracle.resource+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.orange.indata\": {\n \"source\": \"iana\"\n },\n \"application/vnd.osa.netdeploy\": {\n \"source\": \"iana\"\n },\n \"application/vnd.osgeo.mapguide.package\": {\n \"source\": \"iana\",\n \"extensions\": [\"mgp\"]\n },\n \"application/vnd.osgi.bundle\": {\n \"source\": \"iana\"\n },\n \"application/vnd.osgi.dp\": {\n \"source\": \"iana\",\n \"extensions\": [\"dp\"]\n },\n \"application/vnd.osgi.subsystem\": {\n \"source\": \"iana\",\n \"extensions\": [\"esa\"]\n },\n \"application/vnd.otps.ct-kip+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.oxli.countgraph\": {\n \"source\": \"iana\"\n },\n \"application/vnd.pagerduty+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.palm\": {\n \"source\": \"iana\",\n \"extensions\": [\"pdb\",\"pqa\",\"oprc\"]\n },\n \"application/vnd.panoply\": {\n \"source\": \"iana\"\n },\n \"application/vnd.paos.xml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.patentdive\": {\n \"source\": \"iana\"\n },\n \"application/vnd.patientecommsdoc\": {\n \"source\": \"iana\"\n },\n \"application/vnd.pawaafile\": {\n \"source\": \"iana\",\n \"extensions\": [\"paw\"]\n },\n \"application/vnd.pcos\": {\n \"source\": \"iana\"\n },\n \"application/vnd.pg.format\": {\n \"source\": \"iana\",\n \"extensions\": [\"str\"]\n },\n \"application/vnd.pg.osasli\": {\n \"source\": \"iana\",\n \"extensions\": [\"ei6\"]\n },\n \"application/vnd.piaccess.application-licence\": {\n \"source\": \"iana\"\n },\n \"application/vnd.picsel\": {\n \"source\": \"iana\",\n \"extensions\": [\"efif\"]\n },\n \"application/vnd.pmi.widget\": {\n \"source\": \"iana\",\n \"extensions\": [\"wg\"]\n },\n \"application/vnd.poc.group-advertisement+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.pocketlearn\": {\n \"source\": \"iana\",\n \"extensions\": [\"plf\"]\n },\n \"application/vnd.powerbuilder6\": {\n \"source\": \"iana\",\n \"extensions\": [\"pbd\"]\n },\n \"application/vnd.powerbuilder6-s\": {\n \"source\": \"iana\"\n },\n \"application/vnd.powerbuilder7\": {\n \"source\": \"iana\"\n },\n \"application/vnd.powerbuilder7-s\": {\n \"source\": \"iana\"\n },\n \"application/vnd.powerbuilder75\": {\n \"source\": \"iana\"\n },\n \"application/vnd.powerbuilder75-s\": {\n \"source\": \"iana\"\n },\n \"application/vnd.preminet\": {\n \"source\": \"iana\"\n },\n \"application/vnd.previewsystems.box\": {\n \"source\": \"iana\",\n \"extensions\": [\"box\"]\n },\n \"application/vnd.procrate.brushset\": {\n \"extensions\": [\"brushset\"]\n },\n \"application/vnd.procreate.brush\": {\n \"extensions\": [\"brush\"]\n },\n \"application/vnd.procreate.dream\": {\n \"extensions\": [\"drm\"]\n },\n \"application/vnd.proteus.magazine\": {\n \"source\": \"iana\",\n \"extensions\": [\"mgz\"]\n },\n \"application/vnd.psfs\": {\n \"source\": \"iana\"\n },\n \"application/vnd.pt.mundusmundi\": {\n \"source\": \"iana\"\n },\n \"application/vnd.publishare-delta-tree\": {\n \"source\": \"iana\",\n \"extensions\": [\"qps\"]\n },\n \"application/vnd.pvi.ptid1\": {\n \"source\": \"iana\",\n \"extensions\": [\"ptid\"]\n },\n \"application/vnd.pwg-multiplexed\": {\n \"source\": \"iana\"\n },\n \"application/vnd.pwg-xhtml-print+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xhtm\"]\n },\n \"application/vnd.qualcomm.brew-app-res\": {\n \"source\": \"iana\"\n },\n \"application/vnd.quarantainenet\": {\n \"source\": \"iana\"\n },\n \"application/vnd.quark.quarkxpress\": {\n \"source\": \"iana\",\n \"extensions\": [\"qxd\",\"qxt\",\"qwd\",\"qwt\",\"qxl\",\"qxb\"]\n },\n \"application/vnd.quobject-quoxdocument\": {\n \"source\": \"iana\"\n },\n \"application/vnd.radisys.moml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-audit+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-audit-conf+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-audit-conn+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-audit-dialog+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-audit-stream+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-conf+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-dialog+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-dialog-base+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-dialog-fax-detect+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-dialog-fax-sendrecv+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-dialog-group+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-dialog-speech+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.radisys.msml-dialog-transform+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.rainstor.data\": {\n \"source\": \"iana\"\n },\n \"application/vnd.rapid\": {\n \"source\": \"iana\"\n },\n \"application/vnd.rar\": {\n \"source\": \"iana\",\n \"extensions\": [\"rar\"]\n },\n \"application/vnd.realvnc.bed\": {\n \"source\": \"iana\",\n \"extensions\": [\"bed\"]\n },\n \"application/vnd.recordare.musicxml\": {\n \"source\": \"iana\",\n \"extensions\": [\"mxl\"]\n },\n \"application/vnd.recordare.musicxml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"musicxml\"]\n },\n \"application/vnd.relpipe\": {\n \"source\": \"iana\"\n },\n \"application/vnd.renlearn.rlprint\": {\n \"source\": \"iana\"\n },\n \"application/vnd.resilient.logic\": {\n \"source\": \"iana\"\n },\n \"application/vnd.restful+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.rig.cryptonote\": {\n \"source\": \"iana\",\n \"extensions\": [\"cryptonote\"]\n },\n \"application/vnd.rim.cod\": {\n \"source\": \"apache\",\n \"extensions\": [\"cod\"]\n },\n \"application/vnd.rn-realmedia\": {\n \"source\": \"apache\",\n \"extensions\": [\"rm\"]\n },\n \"application/vnd.rn-realmedia-vbr\": {\n \"source\": \"apache\",\n \"extensions\": [\"rmvb\"]\n },\n \"application/vnd.route66.link66+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"link66\"]\n },\n \"application/vnd.rs-274x\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ruckus.download\": {\n \"source\": \"iana\"\n },\n \"application/vnd.s3sms\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sailingtracker.track\": {\n \"source\": \"iana\",\n \"extensions\": [\"st\"]\n },\n \"application/vnd.sar\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sbm.cid\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sbm.mid2\": {\n \"source\": \"iana\"\n },\n \"application/vnd.scribus\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealed.3df\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealed.csf\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealed.doc\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealed.eml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealed.mht\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealed.net\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealed.ppt\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealed.tiff\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealed.xls\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealedmedia.softseal.html\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sealedmedia.softseal.pdf\": {\n \"source\": \"iana\"\n },\n \"application/vnd.seemail\": {\n \"source\": \"iana\",\n \"extensions\": [\"see\"]\n },\n \"application/vnd.seis+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.sema\": {\n \"source\": \"iana\",\n \"extensions\": [\"sema\"]\n },\n \"application/vnd.semd\": {\n \"source\": \"iana\",\n \"extensions\": [\"semd\"]\n },\n \"application/vnd.semf\": {\n \"source\": \"iana\",\n \"extensions\": [\"semf\"]\n },\n \"application/vnd.shade-save-file\": {\n \"source\": \"iana\"\n },\n \"application/vnd.shana.informed.formdata\": {\n \"source\": \"iana\",\n \"extensions\": [\"ifm\"]\n },\n \"application/vnd.shana.informed.formtemplate\": {\n \"source\": \"iana\",\n \"extensions\": [\"itp\"]\n },\n \"application/vnd.shana.informed.interchange\": {\n \"source\": \"iana\",\n \"extensions\": [\"iif\"]\n },\n \"application/vnd.shana.informed.package\": {\n \"source\": \"iana\",\n \"extensions\": [\"ipk\"]\n },\n \"application/vnd.shootproof+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.shopkick+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.shp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.shx\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sigrok.session\": {\n \"source\": \"iana\"\n },\n \"application/vnd.simtech-mindmapper\": {\n \"source\": \"iana\",\n \"extensions\": [\"twd\",\"twds\"]\n },\n \"application/vnd.siren+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.sketchometry\": {\n \"source\": \"iana\"\n },\n \"application/vnd.smaf\": {\n \"source\": \"iana\",\n \"extensions\": [\"mmf\"]\n },\n \"application/vnd.smart.notebook\": {\n \"source\": \"iana\"\n },\n \"application/vnd.smart.teacher\": {\n \"source\": \"iana\",\n \"extensions\": [\"teacher\"]\n },\n \"application/vnd.smintio.portals.archive\": {\n \"source\": \"iana\"\n },\n \"application/vnd.snesdev-page-table\": {\n \"source\": \"iana\"\n },\n \"application/vnd.software602.filler.form+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"fo\"]\n },\n \"application/vnd.software602.filler.form-xml-zip\": {\n \"source\": \"iana\"\n },\n \"application/vnd.solent.sdkm+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"sdkm\",\"sdkd\"]\n },\n \"application/vnd.spotfire.dxp\": {\n \"source\": \"iana\",\n \"extensions\": [\"dxp\"]\n },\n \"application/vnd.spotfire.sfs\": {\n \"source\": \"iana\",\n \"extensions\": [\"sfs\"]\n },\n \"application/vnd.sqlite3\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sss-cod\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sss-dtf\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sss-ntf\": {\n \"source\": \"iana\"\n },\n \"application/vnd.stardivision.calc\": {\n \"source\": \"apache\",\n \"extensions\": [\"sdc\"]\n },\n \"application/vnd.stardivision.draw\": {\n \"source\": \"apache\",\n \"extensions\": [\"sda\"]\n },\n \"application/vnd.stardivision.impress\": {\n \"source\": \"apache\",\n \"extensions\": [\"sdd\"]\n },\n \"application/vnd.stardivision.math\": {\n \"source\": \"apache\",\n \"extensions\": [\"smf\"]\n },\n \"application/vnd.stardivision.writer\": {\n \"source\": \"apache\",\n \"extensions\": [\"sdw\",\"vor\"]\n },\n \"application/vnd.stardivision.writer-global\": {\n \"source\": \"apache\",\n \"extensions\": [\"sgl\"]\n },\n \"application/vnd.stepmania.package\": {\n \"source\": \"iana\",\n \"extensions\": [\"smzip\"]\n },\n \"application/vnd.stepmania.stepchart\": {\n \"source\": \"iana\",\n \"extensions\": [\"sm\"]\n },\n \"application/vnd.street-stream\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sun.wadl+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"wadl\"]\n },\n \"application/vnd.sun.xml.calc\": {\n \"source\": \"apache\",\n \"extensions\": [\"sxc\"]\n },\n \"application/vnd.sun.xml.calc.template\": {\n \"source\": \"apache\",\n \"extensions\": [\"stc\"]\n },\n \"application/vnd.sun.xml.draw\": {\n \"source\": \"apache\",\n \"extensions\": [\"sxd\"]\n },\n \"application/vnd.sun.xml.draw.template\": {\n \"source\": \"apache\",\n \"extensions\": [\"std\"]\n },\n \"application/vnd.sun.xml.impress\": {\n \"source\": \"apache\",\n \"extensions\": [\"sxi\"]\n },\n \"application/vnd.sun.xml.impress.template\": {\n \"source\": \"apache\",\n \"extensions\": [\"sti\"]\n },\n \"application/vnd.sun.xml.math\": {\n \"source\": \"apache\",\n \"extensions\": [\"sxm\"]\n },\n \"application/vnd.sun.xml.writer\": {\n \"source\": \"apache\",\n \"extensions\": [\"sxw\"]\n },\n \"application/vnd.sun.xml.writer.global\": {\n \"source\": \"apache\",\n \"extensions\": [\"sxg\"]\n },\n \"application/vnd.sun.xml.writer.template\": {\n \"source\": \"apache\",\n \"extensions\": [\"stw\"]\n },\n \"application/vnd.sus-calendar\": {\n \"source\": \"iana\",\n \"extensions\": [\"sus\",\"susp\"]\n },\n \"application/vnd.svd\": {\n \"source\": \"iana\",\n \"extensions\": [\"svd\"]\n },\n \"application/vnd.swiftview-ics\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sybyl.mol2\": {\n \"source\": \"iana\"\n },\n \"application/vnd.sycle+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.syft+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.symbian.install\": {\n \"source\": \"apache\",\n \"extensions\": [\"sis\",\"sisx\"]\n },\n \"application/vnd.syncml+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true,\n \"extensions\": [\"xsm\"]\n },\n \"application/vnd.syncml.dm+wbxml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"extensions\": [\"bdm\"]\n },\n \"application/vnd.syncml.dm+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true,\n \"extensions\": [\"xdm\"]\n },\n \"application/vnd.syncml.dm.notification\": {\n \"source\": \"iana\"\n },\n \"application/vnd.syncml.dmddf+wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.syncml.dmddf+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true,\n \"extensions\": [\"ddf\"]\n },\n \"application/vnd.syncml.dmtnds+wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.syncml.dmtnds+xml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true\n },\n \"application/vnd.syncml.ds.notification\": {\n \"source\": \"iana\"\n },\n \"application/vnd.tableschema+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.tao.intent-module-archive\": {\n \"source\": \"iana\",\n \"extensions\": [\"tao\"]\n },\n \"application/vnd.tcpdump.pcap\": {\n \"source\": \"iana\",\n \"extensions\": [\"pcap\",\"cap\",\"dmp\"]\n },\n \"application/vnd.think-cell.ppttc+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.tmd.mediaflex.api+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.tml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.tmobile-livetv\": {\n \"source\": \"iana\",\n \"extensions\": [\"tmo\"]\n },\n \"application/vnd.tri.onesource\": {\n \"source\": \"iana\"\n },\n \"application/vnd.trid.tpt\": {\n \"source\": \"iana\",\n \"extensions\": [\"tpt\"]\n },\n \"application/vnd.triscape.mxs\": {\n \"source\": \"iana\",\n \"extensions\": [\"mxs\"]\n },\n \"application/vnd.trueapp\": {\n \"source\": \"iana\",\n \"extensions\": [\"tra\"]\n },\n \"application/vnd.truedoc\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ubisoft.webplayer\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ufdl\": {\n \"source\": \"iana\",\n \"extensions\": [\"ufd\",\"ufdl\"]\n },\n \"application/vnd.uic.osdm+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.uiq.theme\": {\n \"source\": \"iana\",\n \"extensions\": [\"utz\"]\n },\n \"application/vnd.umajin\": {\n \"source\": \"iana\",\n \"extensions\": [\"umj\"]\n },\n \"application/vnd.unity\": {\n \"source\": \"iana\",\n \"extensions\": [\"unityweb\"]\n },\n \"application/vnd.uoml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"uoml\",\"uo\"]\n },\n \"application/vnd.uplanet.alert\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.alert-wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.bearer-choice\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.bearer-choice-wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.cacheop\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.cacheop-wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.channel\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.channel-wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.list\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.list-wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.listcmd\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.listcmd-wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uplanet.signal\": {\n \"source\": \"iana\"\n },\n \"application/vnd.uri-map\": {\n \"source\": \"iana\"\n },\n \"application/vnd.valve.source.material\": {\n \"source\": \"iana\"\n },\n \"application/vnd.vcx\": {\n \"source\": \"iana\",\n \"extensions\": [\"vcx\"]\n },\n \"application/vnd.vd-study\": {\n \"source\": \"iana\"\n },\n \"application/vnd.vectorworks\": {\n \"source\": \"iana\"\n },\n \"application/vnd.vel+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.veraison.tsm-report+cbor\": {\n \"source\": \"iana\"\n },\n \"application/vnd.veraison.tsm-report+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.verimatrix.vcas\": {\n \"source\": \"iana\"\n },\n \"application/vnd.veritone.aion+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.veryant.thin\": {\n \"source\": \"iana\"\n },\n \"application/vnd.ves.encrypted\": {\n \"source\": \"iana\"\n },\n \"application/vnd.vidsoft.vidconference\": {\n \"source\": \"iana\"\n },\n \"application/vnd.visio\": {\n \"source\": \"iana\",\n \"extensions\": [\"vsd\",\"vst\",\"vss\",\"vsw\",\"vsdx\",\"vtx\"]\n },\n \"application/vnd.visionary\": {\n \"source\": \"iana\",\n \"extensions\": [\"vis\"]\n },\n \"application/vnd.vividence.scriptfile\": {\n \"source\": \"iana\"\n },\n \"application/vnd.vocalshaper.vsp4\": {\n \"source\": \"iana\"\n },\n \"application/vnd.vsf\": {\n \"source\": \"iana\",\n \"extensions\": [\"vsf\"]\n },\n \"application/vnd.wap.sic\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wap.slc\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wap.wbxml\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"extensions\": [\"wbxml\"]\n },\n \"application/vnd.wap.wmlc\": {\n \"source\": \"iana\",\n \"extensions\": [\"wmlc\"]\n },\n \"application/vnd.wap.wmlscriptc\": {\n \"source\": \"iana\",\n \"extensions\": [\"wmlsc\"]\n },\n \"application/vnd.wasmflow.wafl\": {\n \"source\": \"iana\"\n },\n \"application/vnd.webturbo\": {\n \"source\": \"iana\",\n \"extensions\": [\"wtb\"]\n },\n \"application/vnd.wfa.dpp\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wfa.p2p\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wfa.wsc\": {\n \"source\": \"iana\"\n },\n \"application/vnd.windows.devicepairing\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wmc\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wmf.bootstrap\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wolfram.mathematica\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wolfram.mathematica.package\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wolfram.player\": {\n \"source\": \"iana\",\n \"extensions\": [\"nbp\"]\n },\n \"application/vnd.wordlift\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wordperfect\": {\n \"source\": \"iana\",\n \"extensions\": [\"wpd\"]\n },\n \"application/vnd.wqd\": {\n \"source\": \"iana\",\n \"extensions\": [\"wqd\"]\n },\n \"application/vnd.wrq-hp3000-labelled\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wt.stf\": {\n \"source\": \"iana\",\n \"extensions\": [\"stf\"]\n },\n \"application/vnd.wv.csp+wbxml\": {\n \"source\": \"iana\"\n },\n \"application/vnd.wv.csp+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.wv.ssp+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.xacml+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.xara\": {\n \"source\": \"iana\",\n \"extensions\": [\"xar\"]\n },\n \"application/vnd.xarin.cpj\": {\n \"source\": \"iana\"\n },\n \"application/vnd.xecrets-encrypted\": {\n \"source\": \"iana\"\n },\n \"application/vnd.xfdl\": {\n \"source\": \"iana\",\n \"extensions\": [\"xfdl\"]\n },\n \"application/vnd.xfdl.webform\": {\n \"source\": \"iana\"\n },\n \"application/vnd.xmi+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vnd.xmpie.cpkg\": {\n \"source\": \"iana\"\n },\n \"application/vnd.xmpie.dpkg\": {\n \"source\": \"iana\"\n },\n \"application/vnd.xmpie.plan\": {\n \"source\": \"iana\"\n },\n \"application/vnd.xmpie.ppkg\": {\n \"source\": \"iana\"\n },\n \"application/vnd.xmpie.xlim\": {\n \"source\": \"iana\"\n },\n \"application/vnd.yamaha.hv-dic\": {\n \"source\": \"iana\",\n \"extensions\": [\"hvd\"]\n },\n \"application/vnd.yamaha.hv-script\": {\n \"source\": \"iana\",\n \"extensions\": [\"hvs\"]\n },\n \"application/vnd.yamaha.hv-voice\": {\n \"source\": \"iana\",\n \"extensions\": [\"hvp\"]\n },\n \"application/vnd.yamaha.openscoreformat\": {\n \"source\": \"iana\",\n \"extensions\": [\"osf\"]\n },\n \"application/vnd.yamaha.openscoreformat.osfpvg+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"osfpvg\"]\n },\n \"application/vnd.yamaha.remote-setup\": {\n \"source\": \"iana\"\n },\n \"application/vnd.yamaha.smaf-audio\": {\n \"source\": \"iana\",\n \"extensions\": [\"saf\"]\n },\n \"application/vnd.yamaha.smaf-phrase\": {\n \"source\": \"iana\",\n \"extensions\": [\"spf\"]\n },\n \"application/vnd.yamaha.through-ngn\": {\n \"source\": \"iana\"\n },\n \"application/vnd.yamaha.tunnel-udpencap\": {\n \"source\": \"iana\"\n },\n \"application/vnd.yaoweme\": {\n \"source\": \"iana\"\n },\n \"application/vnd.yellowriver-custom-menu\": {\n \"source\": \"iana\",\n \"extensions\": [\"cmp\"]\n },\n \"application/vnd.zul\": {\n \"source\": \"iana\",\n \"extensions\": [\"zir\",\"zirz\"]\n },\n \"application/vnd.zzazz.deck+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"zaz\"]\n },\n \"application/voicexml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"vxml\"]\n },\n \"application/voucher-cms+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/voucher-jws+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/vp\": {\n \"source\": \"iana\"\n },\n \"application/vp+cose\": {\n \"source\": \"iana\"\n },\n \"application/vp+jwt\": {\n \"source\": \"iana\"\n },\n \"application/vq-rtcpxr\": {\n \"source\": \"iana\"\n },\n \"application/wasm\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"wasm\"]\n },\n \"application/watcherinfo+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"wif\"]\n },\n \"application/webpush-options+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/whoispp-query\": {\n \"source\": \"iana\"\n },\n \"application/whoispp-response\": {\n \"source\": \"iana\"\n },\n \"application/widget\": {\n \"source\": \"iana\",\n \"extensions\": [\"wgt\"]\n },\n \"application/winhlp\": {\n \"source\": \"apache\",\n \"extensions\": [\"hlp\"]\n },\n \"application/wita\": {\n \"source\": \"iana\"\n },\n \"application/wordperfect5.1\": {\n \"source\": \"iana\"\n },\n \"application/wsdl+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"wsdl\"]\n },\n \"application/wspolicy+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"wspolicy\"]\n },\n \"application/x-7z-compressed\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"7z\"]\n },\n \"application/x-abiword\": {\n \"source\": \"apache\",\n \"extensions\": [\"abw\"]\n },\n \"application/x-ace-compressed\": {\n \"source\": \"apache\",\n \"extensions\": [\"ace\"]\n },\n \"application/x-amf\": {\n \"source\": \"apache\"\n },\n \"application/x-apple-diskimage\": {\n \"source\": \"apache\",\n \"extensions\": [\"dmg\"]\n },\n \"application/x-arj\": {\n \"compressible\": false,\n \"extensions\": [\"arj\"]\n },\n \"application/x-authorware-bin\": {\n \"source\": \"apache\",\n \"extensions\": [\"aab\",\"x32\",\"u32\",\"vox\"]\n },\n \"application/x-authorware-map\": {\n \"source\": \"apache\",\n \"extensions\": [\"aam\"]\n },\n \"application/x-authorware-seg\": {\n \"source\": \"apache\",\n \"extensions\": [\"aas\"]\n },\n \"application/x-bcpio\": {\n \"source\": \"apache\",\n \"extensions\": [\"bcpio\"]\n },\n \"application/x-bdoc\": {\n \"compressible\": false,\n \"extensions\": [\"bdoc\"]\n },\n \"application/x-bittorrent\": {\n \"source\": \"apache\",\n \"extensions\": [\"torrent\"]\n },\n \"application/x-blender\": {\n \"extensions\": [\"blend\"]\n },\n \"application/x-blorb\": {\n \"source\": \"apache\",\n \"extensions\": [\"blb\",\"blorb\"]\n },\n \"application/x-bzip\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"bz\"]\n },\n \"application/x-bzip2\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"bz2\",\"boz\"]\n },\n \"application/x-cbr\": {\n \"source\": \"apache\",\n \"extensions\": [\"cbr\",\"cba\",\"cbt\",\"cbz\",\"cb7\"]\n },\n \"application/x-cdlink\": {\n \"source\": \"apache\",\n \"extensions\": [\"vcd\"]\n },\n \"application/x-cfs-compressed\": {\n \"source\": \"apache\",\n \"extensions\": [\"cfs\"]\n },\n \"application/x-chat\": {\n \"source\": \"apache\",\n \"extensions\": [\"chat\"]\n },\n \"application/x-chess-pgn\": {\n \"source\": \"apache\",\n \"extensions\": [\"pgn\"]\n },\n \"application/x-chrome-extension\": {\n \"extensions\": [\"crx\"]\n },\n \"application/x-cocoa\": {\n \"source\": \"nginx\",\n \"extensions\": [\"cco\"]\n },\n \"application/x-compress\": {\n \"source\": \"apache\"\n },\n \"application/x-compressed\": {\n \"extensions\": [\"rar\"]\n },\n \"application/x-conference\": {\n \"source\": \"apache\",\n \"extensions\": [\"nsc\"]\n },\n \"application/x-cpio\": {\n \"source\": \"apache\",\n \"extensions\": [\"cpio\"]\n },\n \"application/x-csh\": {\n \"source\": \"apache\",\n \"extensions\": [\"csh\"]\n },\n \"application/x-deb\": {\n \"compressible\": false\n },\n \"application/x-debian-package\": {\n \"source\": \"apache\",\n \"extensions\": [\"deb\",\"udeb\"]\n },\n \"application/x-dgc-compressed\": {\n \"source\": \"apache\",\n \"extensions\": [\"dgc\"]\n },\n \"application/x-director\": {\n \"source\": \"apache\",\n \"extensions\": [\"dir\",\"dcr\",\"dxr\",\"cst\",\"cct\",\"cxt\",\"w3d\",\"fgd\",\"swa\"]\n },\n \"application/x-doom\": {\n \"source\": \"apache\",\n \"extensions\": [\"wad\"]\n },\n \"application/x-dtbncx+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"ncx\"]\n },\n \"application/x-dtbook+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"dtb\"]\n },\n \"application/x-dtbresource+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"res\"]\n },\n \"application/x-dvi\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"dvi\"]\n },\n \"application/x-envoy\": {\n \"source\": \"apache\",\n \"extensions\": [\"evy\"]\n },\n \"application/x-eva\": {\n \"source\": \"apache\",\n \"extensions\": [\"eva\"]\n },\n \"application/x-font-bdf\": {\n \"source\": \"apache\",\n \"extensions\": [\"bdf\"]\n },\n \"application/x-font-dos\": {\n \"source\": \"apache\"\n },\n \"application/x-font-framemaker\": {\n \"source\": \"apache\"\n },\n \"application/x-font-ghostscript\": {\n \"source\": \"apache\",\n \"extensions\": [\"gsf\"]\n },\n \"application/x-font-libgrx\": {\n \"source\": \"apache\"\n },\n \"application/x-font-linux-psf\": {\n \"source\": \"apache\",\n \"extensions\": [\"psf\"]\n },\n \"application/x-font-pcf\": {\n \"source\": \"apache\",\n \"extensions\": [\"pcf\"]\n },\n \"application/x-font-snf\": {\n \"source\": \"apache\",\n \"extensions\": [\"snf\"]\n },\n \"application/x-font-speedo\": {\n \"source\": \"apache\"\n },\n \"application/x-font-sunos-news\": {\n \"source\": \"apache\"\n },\n \"application/x-font-type1\": {\n \"source\": \"apache\",\n \"extensions\": [\"pfa\",\"pfb\",\"pfm\",\"afm\"]\n },\n \"application/x-font-vfont\": {\n \"source\": \"apache\"\n },\n \"application/x-freearc\": {\n \"source\": \"apache\",\n \"extensions\": [\"arc\"]\n },\n \"application/x-futuresplash\": {\n \"source\": \"apache\",\n \"extensions\": [\"spl\"]\n },\n \"application/x-gca-compressed\": {\n \"source\": \"apache\",\n \"extensions\": [\"gca\"]\n },\n \"application/x-glulx\": {\n \"source\": \"apache\",\n \"extensions\": [\"ulx\"]\n },\n \"application/x-gnumeric\": {\n \"source\": \"apache\",\n \"extensions\": [\"gnumeric\"]\n },\n \"application/x-gramps-xml\": {\n \"source\": \"apache\",\n \"extensions\": [\"gramps\"]\n },\n \"application/x-gtar\": {\n \"source\": \"apache\",\n \"extensions\": [\"gtar\"]\n },\n \"application/x-gzip\": {\n \"source\": \"apache\"\n },\n \"application/x-hdf\": {\n \"source\": \"apache\",\n \"extensions\": [\"hdf\"]\n },\n \"application/x-httpd-php\": {\n \"compressible\": true,\n \"extensions\": [\"php\"]\n },\n \"application/x-install-instructions\": {\n \"source\": \"apache\",\n \"extensions\": [\"install\"]\n },\n \"application/x-ipynb+json\": {\n \"compressible\": true,\n \"extensions\": [\"ipynb\"]\n },\n \"application/x-iso9660-image\": {\n \"source\": \"apache\",\n \"extensions\": [\"iso\"]\n },\n \"application/x-iwork-keynote-sffkey\": {\n \"extensions\": [\"key\"]\n },\n \"application/x-iwork-numbers-sffnumbers\": {\n \"extensions\": [\"numbers\"]\n },\n \"application/x-iwork-pages-sffpages\": {\n \"extensions\": [\"pages\"]\n },\n \"application/x-java-archive-diff\": {\n \"source\": \"nginx\",\n \"extensions\": [\"jardiff\"]\n },\n \"application/x-java-jnlp-file\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"jnlp\"]\n },\n \"application/x-javascript\": {\n \"compressible\": true\n },\n \"application/x-keepass2\": {\n \"extensions\": [\"kdbx\"]\n },\n \"application/x-latex\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"latex\"]\n },\n \"application/x-lua-bytecode\": {\n \"extensions\": [\"luac\"]\n },\n \"application/x-lzh-compressed\": {\n \"source\": \"apache\",\n \"extensions\": [\"lzh\",\"lha\"]\n },\n \"application/x-makeself\": {\n \"source\": \"nginx\",\n \"extensions\": [\"run\"]\n },\n \"application/x-mie\": {\n \"source\": \"apache\",\n \"extensions\": [\"mie\"]\n },\n \"application/x-mobipocket-ebook\": {\n \"source\": \"apache\",\n \"extensions\": [\"prc\",\"mobi\"]\n },\n \"application/x-mpegurl\": {\n \"compressible\": false\n },\n \"application/x-ms-application\": {\n \"source\": \"apache\",\n \"extensions\": [\"application\"]\n },\n \"application/x-ms-shortcut\": {\n \"source\": \"apache\",\n \"extensions\": [\"lnk\"]\n },\n \"application/x-ms-wmd\": {\n \"source\": \"apache\",\n \"extensions\": [\"wmd\"]\n },\n \"application/x-ms-wmz\": {\n \"source\": \"apache\",\n \"extensions\": [\"wmz\"]\n },\n \"application/x-ms-xbap\": {\n \"source\": \"apache\",\n \"extensions\": [\"xbap\"]\n },\n \"application/x-msaccess\": {\n \"source\": \"apache\",\n \"extensions\": [\"mdb\"]\n },\n \"application/x-msbinder\": {\n \"source\": \"apache\",\n \"extensions\": [\"obd\"]\n },\n \"application/x-mscardfile\": {\n \"source\": \"apache\",\n \"extensions\": [\"crd\"]\n },\n \"application/x-msclip\": {\n \"source\": \"apache\",\n \"extensions\": [\"clp\"]\n },\n \"application/x-msdos-program\": {\n \"extensions\": [\"exe\"]\n },\n \"application/x-msdownload\": {\n \"source\": \"apache\",\n \"extensions\": [\"exe\",\"dll\",\"com\",\"bat\",\"msi\"]\n },\n \"application/x-msmediaview\": {\n \"source\": \"apache\",\n \"extensions\": [\"mvb\",\"m13\",\"m14\"]\n },\n \"application/x-msmetafile\": {\n \"source\": \"apache\",\n \"extensions\": [\"wmf\",\"wmz\",\"emf\",\"emz\"]\n },\n \"application/x-msmoney\": {\n \"source\": \"apache\",\n \"extensions\": [\"mny\"]\n },\n \"application/x-mspublisher\": {\n \"source\": \"apache\",\n \"extensions\": [\"pub\"]\n },\n \"application/x-msschedule\": {\n \"source\": \"apache\",\n \"extensions\": [\"scd\"]\n },\n \"application/x-msterminal\": {\n \"source\": \"apache\",\n \"extensions\": [\"trm\"]\n },\n \"application/x-mswrite\": {\n \"source\": \"apache\",\n \"extensions\": [\"wri\"]\n },\n \"application/x-netcdf\": {\n \"source\": \"apache\",\n \"extensions\": [\"nc\",\"cdf\"]\n },\n \"application/x-ns-proxy-autoconfig\": {\n \"compressible\": true,\n \"extensions\": [\"pac\"]\n },\n \"application/x-nzb\": {\n \"source\": \"apache\",\n \"extensions\": [\"nzb\"]\n },\n \"application/x-perl\": {\n \"source\": \"nginx\",\n \"extensions\": [\"pl\",\"pm\"]\n },\n \"application/x-pilot\": {\n \"source\": \"nginx\",\n \"extensions\": [\"prc\",\"pdb\"]\n },\n \"application/x-pkcs12\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"p12\",\"pfx\"]\n },\n \"application/x-pkcs7-certificates\": {\n \"source\": \"apache\",\n \"extensions\": [\"p7b\",\"spc\"]\n },\n \"application/x-pkcs7-certreqresp\": {\n \"source\": \"apache\",\n \"extensions\": [\"p7r\"]\n },\n \"application/x-pki-message\": {\n \"source\": \"iana\"\n },\n \"application/x-rar-compressed\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"rar\"]\n },\n \"application/x-redhat-package-manager\": {\n \"source\": \"nginx\",\n \"extensions\": [\"rpm\"]\n },\n \"application/x-research-info-systems\": {\n \"source\": \"apache\",\n \"extensions\": [\"ris\"]\n },\n \"application/x-sea\": {\n \"source\": \"nginx\",\n \"extensions\": [\"sea\"]\n },\n \"application/x-sh\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"sh\"]\n },\n \"application/x-shar\": {\n \"source\": \"apache\",\n \"extensions\": [\"shar\"]\n },\n \"application/x-shockwave-flash\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"swf\"]\n },\n \"application/x-silverlight-app\": {\n \"source\": \"apache\",\n \"extensions\": [\"xap\"]\n },\n \"application/x-sql\": {\n \"source\": \"apache\",\n \"extensions\": [\"sql\"]\n },\n \"application/x-stuffit\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"sit\"]\n },\n \"application/x-stuffitx\": {\n \"source\": \"apache\",\n \"extensions\": [\"sitx\"]\n },\n \"application/x-subrip\": {\n \"source\": \"apache\",\n \"extensions\": [\"srt\"]\n },\n \"application/x-sv4cpio\": {\n \"source\": \"apache\",\n \"extensions\": [\"sv4cpio\"]\n },\n \"application/x-sv4crc\": {\n \"source\": \"apache\",\n \"extensions\": [\"sv4crc\"]\n },\n \"application/x-t3vm-image\": {\n \"source\": \"apache\",\n \"extensions\": [\"t3\"]\n },\n \"application/x-tads\": {\n \"source\": \"apache\",\n \"extensions\": [\"gam\"]\n },\n \"application/x-tar\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"tar\"]\n },\n \"application/x-tcl\": {\n \"source\": \"apache\",\n \"extensions\": [\"tcl\",\"tk\"]\n },\n \"application/x-tex\": {\n \"source\": \"apache\",\n \"extensions\": [\"tex\"]\n },\n \"application/x-tex-tfm\": {\n \"source\": \"apache\",\n \"extensions\": [\"tfm\"]\n },\n \"application/x-texinfo\": {\n \"source\": \"apache\",\n \"extensions\": [\"texinfo\",\"texi\"]\n },\n \"application/x-tgif\": {\n \"source\": \"apache\",\n \"extensions\": [\"obj\"]\n },\n \"application/x-ustar\": {\n \"source\": \"apache\",\n \"extensions\": [\"ustar\"]\n },\n \"application/x-virtualbox-hdd\": {\n \"compressible\": true,\n \"extensions\": [\"hdd\"]\n },\n \"application/x-virtualbox-ova\": {\n \"compressible\": true,\n \"extensions\": [\"ova\"]\n },\n \"application/x-virtualbox-ovf\": {\n \"compressible\": true,\n \"extensions\": [\"ovf\"]\n },\n \"application/x-virtualbox-vbox\": {\n \"compressible\": true,\n \"extensions\": [\"vbox\"]\n },\n \"application/x-virtualbox-vbox-extpack\": {\n \"compressible\": false,\n \"extensions\": [\"vbox-extpack\"]\n },\n \"application/x-virtualbox-vdi\": {\n \"compressible\": true,\n \"extensions\": [\"vdi\"]\n },\n \"application/x-virtualbox-vhd\": {\n \"compressible\": true,\n \"extensions\": [\"vhd\"]\n },\n \"application/x-virtualbox-vmdk\": {\n \"compressible\": true,\n \"extensions\": [\"vmdk\"]\n },\n \"application/x-wais-source\": {\n \"source\": \"apache\",\n \"extensions\": [\"src\"]\n },\n \"application/x-web-app-manifest+json\": {\n \"compressible\": true,\n \"extensions\": [\"webapp\"]\n },\n \"application/x-www-form-urlencoded\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/x-x509-ca-cert\": {\n \"source\": \"iana\",\n \"extensions\": [\"der\",\"crt\",\"pem\"]\n },\n \"application/x-x509-ca-ra-cert\": {\n \"source\": \"iana\"\n },\n \"application/x-x509-next-ca-cert\": {\n \"source\": \"iana\"\n },\n \"application/x-xfig\": {\n \"source\": \"apache\",\n \"extensions\": [\"fig\"]\n },\n \"application/x-xliff+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"xlf\"]\n },\n \"application/x-xpinstall\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"xpi\"]\n },\n \"application/x-xz\": {\n \"source\": \"apache\",\n \"extensions\": [\"xz\"]\n },\n \"application/x-zip-compressed\": {\n \"extensions\": [\"zip\"]\n },\n \"application/x-zmachine\": {\n \"source\": \"apache\",\n \"extensions\": [\"z1\",\"z2\",\"z3\",\"z4\",\"z5\",\"z6\",\"z7\",\"z8\"]\n },\n \"application/x400-bp\": {\n \"source\": \"iana\"\n },\n \"application/xacml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/xaml+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"xaml\"]\n },\n \"application/xcap-att+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xav\"]\n },\n \"application/xcap-caps+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xca\"]\n },\n \"application/xcap-diff+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xdf\"]\n },\n \"application/xcap-el+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xel\"]\n },\n \"application/xcap-error+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/xcap-ns+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xns\"]\n },\n \"application/xcon-conference-info+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/xcon-conference-info-diff+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/xenc+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xenc\"]\n },\n \"application/xfdf\": {\n \"source\": \"iana\",\n \"extensions\": [\"xfdf\"]\n },\n \"application/xhtml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xhtml\",\"xht\"]\n },\n \"application/xhtml-voice+xml\": {\n \"source\": \"apache\",\n \"compressible\": true\n },\n \"application/xliff+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xlf\"]\n },\n \"application/xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xml\",\"xsl\",\"xsd\",\"rng\"]\n },\n \"application/xml-dtd\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"dtd\"]\n },\n \"application/xml-external-parsed-entity\": {\n \"source\": \"iana\"\n },\n \"application/xml-patch+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/xmpp+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/xop+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xop\"]\n },\n \"application/xproc+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"xpl\"]\n },\n \"application/xslt+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xsl\",\"xslt\"]\n },\n \"application/xspf+xml\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"xspf\"]\n },\n \"application/xv+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"mxml\",\"xhvml\",\"xvml\",\"xvm\"]\n },\n \"application/yaml\": {\n \"source\": \"iana\"\n },\n \"application/yang\": {\n \"source\": \"iana\",\n \"extensions\": [\"yang\"]\n },\n \"application/yang-data+cbor\": {\n \"source\": \"iana\"\n },\n \"application/yang-data+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/yang-data+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/yang-patch+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/yang-patch+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/yang-sid+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"application/yin+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"yin\"]\n },\n \"application/zip\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"zip\"]\n },\n \"application/zip+dotlottie\": {\n \"extensions\": [\"lottie\"]\n },\n \"application/zlib\": {\n \"source\": \"iana\"\n },\n \"application/zstd\": {\n \"source\": \"iana\"\n },\n \"audio/1d-interleaved-parityfec\": {\n \"source\": \"iana\"\n },\n \"audio/32kadpcm\": {\n \"source\": \"iana\"\n },\n \"audio/3gpp\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"3gpp\"]\n },\n \"audio/3gpp2\": {\n \"source\": \"iana\"\n },\n \"audio/aac\": {\n \"source\": \"iana\",\n \"extensions\": [\"adts\",\"aac\"]\n },\n \"audio/ac3\": {\n \"source\": \"iana\"\n },\n \"audio/adpcm\": {\n \"source\": \"apache\",\n \"extensions\": [\"adp\"]\n },\n \"audio/amr\": {\n \"source\": \"iana\",\n \"extensions\": [\"amr\"]\n },\n \"audio/amr-wb\": {\n \"source\": \"iana\"\n },\n \"audio/amr-wb+\": {\n \"source\": \"iana\"\n },\n \"audio/aptx\": {\n \"source\": \"iana\"\n },\n \"audio/asc\": {\n \"source\": \"iana\"\n },\n \"audio/atrac-advanced-lossless\": {\n \"source\": \"iana\"\n },\n \"audio/atrac-x\": {\n \"source\": \"iana\"\n },\n \"audio/atrac3\": {\n \"source\": \"iana\"\n },\n \"audio/basic\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"au\",\"snd\"]\n },\n \"audio/bv16\": {\n \"source\": \"iana\"\n },\n \"audio/bv32\": {\n \"source\": \"iana\"\n },\n \"audio/clearmode\": {\n \"source\": \"iana\"\n },\n \"audio/cn\": {\n \"source\": \"iana\"\n },\n \"audio/dat12\": {\n \"source\": \"iana\"\n },\n \"audio/dls\": {\n \"source\": \"iana\"\n },\n \"audio/dsr-es201108\": {\n \"source\": \"iana\"\n },\n \"audio/dsr-es202050\": {\n \"source\": \"iana\"\n },\n \"audio/dsr-es202211\": {\n \"source\": \"iana\"\n },\n \"audio/dsr-es202212\": {\n \"source\": \"iana\"\n },\n \"audio/dv\": {\n \"source\": \"iana\"\n },\n \"audio/dvi4\": {\n \"source\": \"iana\"\n },\n \"audio/eac3\": {\n \"source\": \"iana\"\n },\n \"audio/encaprtp\": {\n \"source\": \"iana\"\n },\n \"audio/evrc\": {\n \"source\": \"iana\"\n },\n \"audio/evrc-qcp\": {\n \"source\": \"iana\"\n },\n \"audio/evrc0\": {\n \"source\": \"iana\"\n },\n \"audio/evrc1\": {\n \"source\": \"iana\"\n },\n \"audio/evrcb\": {\n \"source\": \"iana\"\n },\n \"audio/evrcb0\": {\n \"source\": \"iana\"\n },\n \"audio/evrcb1\": {\n \"source\": \"iana\"\n },\n \"audio/evrcnw\": {\n \"source\": \"iana\"\n },\n \"audio/evrcnw0\": {\n \"source\": \"iana\"\n },\n \"audio/evrcnw1\": {\n \"source\": \"iana\"\n },\n \"audio/evrcwb\": {\n \"source\": \"iana\"\n },\n \"audio/evrcwb0\": {\n \"source\": \"iana\"\n },\n \"audio/evrcwb1\": {\n \"source\": \"iana\"\n },\n \"audio/evs\": {\n \"source\": \"iana\"\n },\n \"audio/flac\": {\n \"source\": \"iana\"\n },\n \"audio/flexfec\": {\n \"source\": \"iana\"\n },\n \"audio/fwdred\": {\n \"source\": \"iana\"\n },\n \"audio/g711-0\": {\n \"source\": \"iana\"\n },\n \"audio/g719\": {\n \"source\": \"iana\"\n },\n \"audio/g722\": {\n \"source\": \"iana\"\n },\n \"audio/g7221\": {\n \"source\": \"iana\"\n },\n \"audio/g723\": {\n \"source\": \"iana\"\n },\n \"audio/g726-16\": {\n \"source\": \"iana\"\n },\n \"audio/g726-24\": {\n \"source\": \"iana\"\n },\n \"audio/g726-32\": {\n \"source\": \"iana\"\n },\n \"audio/g726-40\": {\n \"source\": \"iana\"\n },\n \"audio/g728\": {\n \"source\": \"iana\"\n },\n \"audio/g729\": {\n \"source\": \"iana\"\n },\n \"audio/g7291\": {\n \"source\": \"iana\"\n },\n \"audio/g729d\": {\n \"source\": \"iana\"\n },\n \"audio/g729e\": {\n \"source\": \"iana\"\n },\n \"audio/gsm\": {\n \"source\": \"iana\"\n },\n \"audio/gsm-efr\": {\n \"source\": \"iana\"\n },\n \"audio/gsm-hr-08\": {\n \"source\": \"iana\"\n },\n \"audio/ilbc\": {\n \"source\": \"iana\"\n },\n \"audio/ip-mr_v2.5\": {\n \"source\": \"iana\"\n },\n \"audio/isac\": {\n \"source\": \"apache\"\n },\n \"audio/l16\": {\n \"source\": \"iana\"\n },\n \"audio/l20\": {\n \"source\": \"iana\"\n },\n \"audio/l24\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"audio/l8\": {\n \"source\": \"iana\"\n },\n \"audio/lpc\": {\n \"source\": \"iana\"\n },\n \"audio/matroska\": {\n \"source\": \"iana\"\n },\n \"audio/melp\": {\n \"source\": \"iana\"\n },\n \"audio/melp1200\": {\n \"source\": \"iana\"\n },\n \"audio/melp2400\": {\n \"source\": \"iana\"\n },\n \"audio/melp600\": {\n \"source\": \"iana\"\n },\n \"audio/mhas\": {\n \"source\": \"iana\"\n },\n \"audio/midi\": {\n \"source\": \"apache\",\n \"extensions\": [\"mid\",\"midi\",\"kar\",\"rmi\"]\n },\n \"audio/midi-clip\": {\n \"source\": \"iana\"\n },\n \"audio/mobile-xmf\": {\n \"source\": \"iana\",\n \"extensions\": [\"mxmf\"]\n },\n \"audio/mp3\": {\n \"compressible\": false,\n \"extensions\": [\"mp3\"]\n },\n \"audio/mp4\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"m4a\",\"mp4a\",\"m4b\"]\n },\n \"audio/mp4a-latm\": {\n \"source\": \"iana\"\n },\n \"audio/mpa\": {\n \"source\": \"iana\"\n },\n \"audio/mpa-robust\": {\n \"source\": \"iana\"\n },\n \"audio/mpeg\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"mpga\",\"mp2\",\"mp2a\",\"mp3\",\"m2a\",\"m3a\"]\n },\n \"audio/mpeg4-generic\": {\n \"source\": \"iana\"\n },\n \"audio/musepack\": {\n \"source\": \"apache\"\n },\n \"audio/ogg\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"oga\",\"ogg\",\"spx\",\"opus\"]\n },\n \"audio/opus\": {\n \"source\": \"iana\"\n },\n \"audio/parityfec\": {\n \"source\": \"iana\"\n },\n \"audio/pcma\": {\n \"source\": \"iana\"\n },\n \"audio/pcma-wb\": {\n \"source\": \"iana\"\n },\n \"audio/pcmu\": {\n \"source\": \"iana\"\n },\n \"audio/pcmu-wb\": {\n \"source\": \"iana\"\n },\n \"audio/prs.sid\": {\n \"source\": \"iana\"\n },\n \"audio/qcelp\": {\n \"source\": \"iana\"\n },\n \"audio/raptorfec\": {\n \"source\": \"iana\"\n },\n \"audio/red\": {\n \"source\": \"iana\"\n },\n \"audio/rtp-enc-aescm128\": {\n \"source\": \"iana\"\n },\n \"audio/rtp-midi\": {\n \"source\": \"iana\"\n },\n \"audio/rtploopback\": {\n \"source\": \"iana\"\n },\n \"audio/rtx\": {\n \"source\": \"iana\"\n },\n \"audio/s3m\": {\n \"source\": \"apache\",\n \"extensions\": [\"s3m\"]\n },\n \"audio/scip\": {\n \"source\": \"iana\"\n },\n \"audio/silk\": {\n \"source\": \"apache\",\n \"extensions\": [\"sil\"]\n },\n \"audio/smv\": {\n \"source\": \"iana\"\n },\n \"audio/smv-qcp\": {\n \"source\": \"iana\"\n },\n \"audio/smv0\": {\n \"source\": \"iana\"\n },\n \"audio/sofa\": {\n \"source\": \"iana\"\n },\n \"audio/sp-midi\": {\n \"source\": \"iana\"\n },\n \"audio/speex\": {\n \"source\": \"iana\"\n },\n \"audio/t140c\": {\n \"source\": \"iana\"\n },\n \"audio/t38\": {\n \"source\": \"iana\"\n },\n \"audio/telephone-event\": {\n \"source\": \"iana\"\n },\n \"audio/tetra_acelp\": {\n \"source\": \"iana\"\n },\n \"audio/tetra_acelp_bb\": {\n \"source\": \"iana\"\n },\n \"audio/tone\": {\n \"source\": \"iana\"\n },\n \"audio/tsvcis\": {\n \"source\": \"iana\"\n },\n \"audio/uemclip\": {\n \"source\": \"iana\"\n },\n \"audio/ulpfec\": {\n \"source\": \"iana\"\n },\n \"audio/usac\": {\n \"source\": \"iana\"\n },\n \"audio/vdvi\": {\n \"source\": \"iana\"\n },\n \"audio/vmr-wb\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.3gpp.iufp\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.4sb\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.audiokoz\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.celp\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.cisco.nse\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.cmles.radio-events\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.cns.anp1\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.cns.inf1\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dece.audio\": {\n \"source\": \"iana\",\n \"extensions\": [\"uva\",\"uvva\"]\n },\n \"audio/vnd.digital-winds\": {\n \"source\": \"iana\",\n \"extensions\": [\"eol\"]\n },\n \"audio/vnd.dlna.adts\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dolby.heaac.1\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dolby.heaac.2\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dolby.mlp\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dolby.mps\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dolby.pl2\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dolby.pl2x\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dolby.pl2z\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dolby.pulse.1\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dra\": {\n \"source\": \"iana\",\n \"extensions\": [\"dra\"]\n },\n \"audio/vnd.dts\": {\n \"source\": \"iana\",\n \"extensions\": [\"dts\"]\n },\n \"audio/vnd.dts.hd\": {\n \"source\": \"iana\",\n \"extensions\": [\"dtshd\"]\n },\n \"audio/vnd.dts.uhd\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.dvb.file\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.everad.plj\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.hns.audio\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.lucent.voice\": {\n \"source\": \"iana\",\n \"extensions\": [\"lvp\"]\n },\n \"audio/vnd.ms-playready.media.pya\": {\n \"source\": \"iana\",\n \"extensions\": [\"pya\"]\n },\n \"audio/vnd.nokia.mobile-xmf\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.nortel.vbk\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.nuera.ecelp4800\": {\n \"source\": \"iana\",\n \"extensions\": [\"ecelp4800\"]\n },\n \"audio/vnd.nuera.ecelp7470\": {\n \"source\": \"iana\",\n \"extensions\": [\"ecelp7470\"]\n },\n \"audio/vnd.nuera.ecelp9600\": {\n \"source\": \"iana\",\n \"extensions\": [\"ecelp9600\"]\n },\n \"audio/vnd.octel.sbc\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.presonus.multitrack\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.qcelp\": {\n \"source\": \"apache\"\n },\n \"audio/vnd.rhetorex.32kadpcm\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.rip\": {\n \"source\": \"iana\",\n \"extensions\": [\"rip\"]\n },\n \"audio/vnd.rn-realaudio\": {\n \"compressible\": false\n },\n \"audio/vnd.sealedmedia.softseal.mpeg\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.vmx.cvsd\": {\n \"source\": \"iana\"\n },\n \"audio/vnd.wave\": {\n \"compressible\": false\n },\n \"audio/vorbis\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"audio/vorbis-config\": {\n \"source\": \"iana\"\n },\n \"audio/wav\": {\n \"compressible\": false,\n \"extensions\": [\"wav\"]\n },\n \"audio/wave\": {\n \"compressible\": false,\n \"extensions\": [\"wav\"]\n },\n \"audio/webm\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"weba\"]\n },\n \"audio/x-aac\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"aac\"]\n },\n \"audio/x-aiff\": {\n \"source\": \"apache\",\n \"extensions\": [\"aif\",\"aiff\",\"aifc\"]\n },\n \"audio/x-caf\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"caf\"]\n },\n \"audio/x-flac\": {\n \"source\": \"apache\",\n \"extensions\": [\"flac\"]\n },\n \"audio/x-m4a\": {\n \"source\": \"nginx\",\n \"extensions\": [\"m4a\"]\n },\n \"audio/x-matroska\": {\n \"source\": \"apache\",\n \"extensions\": [\"mka\"]\n },\n \"audio/x-mpegurl\": {\n \"source\": \"apache\",\n \"extensions\": [\"m3u\"]\n },\n \"audio/x-ms-wax\": {\n \"source\": \"apache\",\n \"extensions\": [\"wax\"]\n },\n \"audio/x-ms-wma\": {\n \"source\": \"apache\",\n \"extensions\": [\"wma\"]\n },\n \"audio/x-pn-realaudio\": {\n \"source\": \"apache\",\n \"extensions\": [\"ram\",\"ra\"]\n },\n \"audio/x-pn-realaudio-plugin\": {\n \"source\": \"apache\",\n \"extensions\": [\"rmp\"]\n },\n \"audio/x-realaudio\": {\n \"source\": \"nginx\",\n \"extensions\": [\"ra\"]\n },\n \"audio/x-tta\": {\n \"source\": \"apache\"\n },\n \"audio/x-wav\": {\n \"source\": \"apache\",\n \"extensions\": [\"wav\"]\n },\n \"audio/xm\": {\n \"source\": \"apache\",\n \"extensions\": [\"xm\"]\n },\n \"chemical/x-cdx\": {\n \"source\": \"apache\",\n \"extensions\": [\"cdx\"]\n },\n \"chemical/x-cif\": {\n \"source\": \"apache\",\n \"extensions\": [\"cif\"]\n },\n \"chemical/x-cmdf\": {\n \"source\": \"apache\",\n \"extensions\": [\"cmdf\"]\n },\n \"chemical/x-cml\": {\n \"source\": \"apache\",\n \"extensions\": [\"cml\"]\n },\n \"chemical/x-csml\": {\n \"source\": \"apache\",\n \"extensions\": [\"csml\"]\n },\n \"chemical/x-pdb\": {\n \"source\": \"apache\"\n },\n \"chemical/x-xyz\": {\n \"source\": \"apache\",\n \"extensions\": [\"xyz\"]\n },\n \"font/collection\": {\n \"source\": \"iana\",\n \"extensions\": [\"ttc\"]\n },\n \"font/otf\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"otf\"]\n },\n \"font/sfnt\": {\n \"source\": \"iana\"\n },\n \"font/ttf\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"ttf\"]\n },\n \"font/woff\": {\n \"source\": \"iana\",\n \"extensions\": [\"woff\"]\n },\n \"font/woff2\": {\n \"source\": \"iana\",\n \"extensions\": [\"woff2\"]\n },\n \"image/aces\": {\n \"source\": \"iana\",\n \"extensions\": [\"exr\"]\n },\n \"image/apng\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"apng\"]\n },\n \"image/avci\": {\n \"source\": \"iana\",\n \"extensions\": [\"avci\"]\n },\n \"image/avcs\": {\n \"source\": \"iana\",\n \"extensions\": [\"avcs\"]\n },\n \"image/avif\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"avif\"]\n },\n \"image/bmp\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"bmp\",\"dib\"]\n },\n \"image/cgm\": {\n \"source\": \"iana\",\n \"extensions\": [\"cgm\"]\n },\n \"image/dicom-rle\": {\n \"source\": \"iana\",\n \"extensions\": [\"drle\"]\n },\n \"image/dpx\": {\n \"source\": \"iana\",\n \"extensions\": [\"dpx\"]\n },\n \"image/emf\": {\n \"source\": \"iana\",\n \"extensions\": [\"emf\"]\n },\n \"image/fits\": {\n \"source\": \"iana\",\n \"extensions\": [\"fits\"]\n },\n \"image/g3fax\": {\n \"source\": \"iana\",\n \"extensions\": [\"g3\"]\n },\n \"image/gif\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"gif\"]\n },\n \"image/heic\": {\n \"source\": \"iana\",\n \"extensions\": [\"heic\"]\n },\n \"image/heic-sequence\": {\n \"source\": \"iana\",\n \"extensions\": [\"heics\"]\n },\n \"image/heif\": {\n \"source\": \"iana\",\n \"extensions\": [\"heif\"]\n },\n \"image/heif-sequence\": {\n \"source\": \"iana\",\n \"extensions\": [\"heifs\"]\n },\n \"image/hej2k\": {\n \"source\": \"iana\",\n \"extensions\": [\"hej2\"]\n },\n \"image/ief\": {\n \"source\": \"iana\",\n \"extensions\": [\"ief\"]\n },\n \"image/j2c\": {\n \"source\": \"iana\"\n },\n \"image/jaii\": {\n \"source\": \"iana\",\n \"extensions\": [\"jaii\"]\n },\n \"image/jais\": {\n \"source\": \"iana\",\n \"extensions\": [\"jais\"]\n },\n \"image/jls\": {\n \"source\": \"iana\",\n \"extensions\": [\"jls\"]\n },\n \"image/jp2\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"jp2\",\"jpg2\"]\n },\n \"image/jpeg\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"jpg\",\"jpeg\",\"jpe\"]\n },\n \"image/jph\": {\n \"source\": \"iana\",\n \"extensions\": [\"jph\"]\n },\n \"image/jphc\": {\n \"source\": \"iana\",\n \"extensions\": [\"jhc\"]\n },\n \"image/jpm\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"jpm\",\"jpgm\"]\n },\n \"image/jpx\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"jpx\",\"jpf\"]\n },\n \"image/jxl\": {\n \"source\": \"iana\",\n \"extensions\": [\"jxl\"]\n },\n \"image/jxr\": {\n \"source\": \"iana\",\n \"extensions\": [\"jxr\"]\n },\n \"image/jxra\": {\n \"source\": \"iana\",\n \"extensions\": [\"jxra\"]\n },\n \"image/jxrs\": {\n \"source\": \"iana\",\n \"extensions\": [\"jxrs\"]\n },\n \"image/jxs\": {\n \"source\": \"iana\",\n \"extensions\": [\"jxs\"]\n },\n \"image/jxsc\": {\n \"source\": \"iana\",\n \"extensions\": [\"jxsc\"]\n },\n \"image/jxsi\": {\n \"source\": \"iana\",\n \"extensions\": [\"jxsi\"]\n },\n \"image/jxss\": {\n \"source\": \"iana\",\n \"extensions\": [\"jxss\"]\n },\n \"image/ktx\": {\n \"source\": \"iana\",\n \"extensions\": [\"ktx\"]\n },\n \"image/ktx2\": {\n \"source\": \"iana\",\n \"extensions\": [\"ktx2\"]\n },\n \"image/naplps\": {\n \"source\": \"iana\"\n },\n \"image/pjpeg\": {\n \"compressible\": false,\n \"extensions\": [\"jfif\"]\n },\n \"image/png\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"png\"]\n },\n \"image/prs.btif\": {\n \"source\": \"iana\",\n \"extensions\": [\"btif\",\"btf\"]\n },\n \"image/prs.pti\": {\n \"source\": \"iana\",\n \"extensions\": [\"pti\"]\n },\n \"image/pwg-raster\": {\n \"source\": \"iana\"\n },\n \"image/sgi\": {\n \"source\": \"apache\",\n \"extensions\": [\"sgi\"]\n },\n \"image/svg+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"svg\",\"svgz\"]\n },\n \"image/t38\": {\n \"source\": \"iana\",\n \"extensions\": [\"t38\"]\n },\n \"image/tiff\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"tif\",\"tiff\"]\n },\n \"image/tiff-fx\": {\n \"source\": \"iana\",\n \"extensions\": [\"tfx\"]\n },\n \"image/vnd.adobe.photoshop\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"psd\"]\n },\n \"image/vnd.airzip.accelerator.azv\": {\n \"source\": \"iana\",\n \"extensions\": [\"azv\"]\n },\n \"image/vnd.clip\": {\n \"source\": \"iana\"\n },\n \"image/vnd.cns.inf2\": {\n \"source\": \"iana\"\n },\n \"image/vnd.dece.graphic\": {\n \"source\": \"iana\",\n \"extensions\": [\"uvi\",\"uvvi\",\"uvg\",\"uvvg\"]\n },\n \"image/vnd.djvu\": {\n \"source\": \"iana\",\n \"extensions\": [\"djvu\",\"djv\"]\n },\n \"image/vnd.dvb.subtitle\": {\n \"source\": \"iana\",\n \"extensions\": [\"sub\"]\n },\n \"image/vnd.dwg\": {\n \"source\": \"iana\",\n \"extensions\": [\"dwg\"]\n },\n \"image/vnd.dxf\": {\n \"source\": \"iana\",\n \"extensions\": [\"dxf\"]\n },\n \"image/vnd.fastbidsheet\": {\n \"source\": \"iana\",\n \"extensions\": [\"fbs\"]\n },\n \"image/vnd.fpx\": {\n \"source\": \"iana\",\n \"extensions\": [\"fpx\"]\n },\n \"image/vnd.fst\": {\n \"source\": \"iana\",\n \"extensions\": [\"fst\"]\n },\n \"image/vnd.fujixerox.edmics-mmr\": {\n \"source\": \"iana\",\n \"extensions\": [\"mmr\"]\n },\n \"image/vnd.fujixerox.edmics-rlc\": {\n \"source\": \"iana\",\n \"extensions\": [\"rlc\"]\n },\n \"image/vnd.globalgraphics.pgb\": {\n \"source\": \"iana\"\n },\n \"image/vnd.microsoft.icon\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"ico\"]\n },\n \"image/vnd.mix\": {\n \"source\": \"iana\"\n },\n \"image/vnd.mozilla.apng\": {\n \"source\": \"iana\"\n },\n \"image/vnd.ms-dds\": {\n \"compressible\": true,\n \"extensions\": [\"dds\"]\n },\n \"image/vnd.ms-modi\": {\n \"source\": \"iana\",\n \"extensions\": [\"mdi\"]\n },\n \"image/vnd.ms-photo\": {\n \"source\": \"apache\",\n \"extensions\": [\"wdp\"]\n },\n \"image/vnd.net-fpx\": {\n \"source\": \"iana\",\n \"extensions\": [\"npx\"]\n },\n \"image/vnd.pco.b16\": {\n \"source\": \"iana\",\n \"extensions\": [\"b16\"]\n },\n \"image/vnd.radiance\": {\n \"source\": \"iana\"\n },\n \"image/vnd.sealed.png\": {\n \"source\": \"iana\"\n },\n \"image/vnd.sealedmedia.softseal.gif\": {\n \"source\": \"iana\"\n },\n \"image/vnd.sealedmedia.softseal.jpg\": {\n \"source\": \"iana\"\n },\n \"image/vnd.svf\": {\n \"source\": \"iana\"\n },\n \"image/vnd.tencent.tap\": {\n \"source\": \"iana\",\n \"extensions\": [\"tap\"]\n },\n \"image/vnd.valve.source.texture\": {\n \"source\": \"iana\",\n \"extensions\": [\"vtf\"]\n },\n \"image/vnd.wap.wbmp\": {\n \"source\": \"iana\",\n \"extensions\": [\"wbmp\"]\n },\n \"image/vnd.xiff\": {\n \"source\": \"iana\",\n \"extensions\": [\"xif\"]\n },\n \"image/vnd.zbrush.pcx\": {\n \"source\": \"iana\",\n \"extensions\": [\"pcx\"]\n },\n \"image/webp\": {\n \"source\": \"iana\",\n \"extensions\": [\"webp\"]\n },\n \"image/wmf\": {\n \"source\": \"iana\",\n \"extensions\": [\"wmf\"]\n },\n \"image/x-3ds\": {\n \"source\": \"apache\",\n \"extensions\": [\"3ds\"]\n },\n \"image/x-adobe-dng\": {\n \"extensions\": [\"dng\"]\n },\n \"image/x-cmu-raster\": {\n \"source\": \"apache\",\n \"extensions\": [\"ras\"]\n },\n \"image/x-cmx\": {\n \"source\": \"apache\",\n \"extensions\": [\"cmx\"]\n },\n \"image/x-emf\": {\n \"source\": \"iana\"\n },\n \"image/x-freehand\": {\n \"source\": \"apache\",\n \"extensions\": [\"fh\",\"fhc\",\"fh4\",\"fh5\",\"fh7\"]\n },\n \"image/x-icon\": {\n \"source\": \"apache\",\n \"compressible\": true,\n \"extensions\": [\"ico\"]\n },\n \"image/x-jng\": {\n \"source\": \"nginx\",\n \"extensions\": [\"jng\"]\n },\n \"image/x-mrsid-image\": {\n \"source\": \"apache\",\n \"extensions\": [\"sid\"]\n },\n \"image/x-ms-bmp\": {\n \"source\": \"nginx\",\n \"compressible\": true,\n \"extensions\": [\"bmp\"]\n },\n \"image/x-pcx\": {\n \"source\": \"apache\",\n \"extensions\": [\"pcx\"]\n },\n \"image/x-pict\": {\n \"source\": \"apache\",\n \"extensions\": [\"pic\",\"pct\"]\n },\n \"image/x-portable-anymap\": {\n \"source\": \"apache\",\n \"extensions\": [\"pnm\"]\n },\n \"image/x-portable-bitmap\": {\n \"source\": \"apache\",\n \"extensions\": [\"pbm\"]\n },\n \"image/x-portable-graymap\": {\n \"source\": \"apache\",\n \"extensions\": [\"pgm\"]\n },\n \"image/x-portable-pixmap\": {\n \"source\": \"apache\",\n \"extensions\": [\"ppm\"]\n },\n \"image/x-rgb\": {\n \"source\": \"apache\",\n \"extensions\": [\"rgb\"]\n },\n \"image/x-tga\": {\n \"source\": \"apache\",\n \"extensions\": [\"tga\"]\n },\n \"image/x-wmf\": {\n \"source\": \"iana\"\n },\n \"image/x-xbitmap\": {\n \"source\": \"apache\",\n \"extensions\": [\"xbm\"]\n },\n \"image/x-xcf\": {\n \"compressible\": false\n },\n \"image/x-xpixmap\": {\n \"source\": \"apache\",\n \"extensions\": [\"xpm\"]\n },\n \"image/x-xwindowdump\": {\n \"source\": \"apache\",\n \"extensions\": [\"xwd\"]\n },\n \"message/bhttp\": {\n \"source\": \"iana\"\n },\n \"message/cpim\": {\n \"source\": \"iana\"\n },\n \"message/delivery-status\": {\n \"source\": \"iana\"\n },\n \"message/disposition-notification\": {\n \"source\": \"iana\",\n \"extensions\": [\n \"disposition-notification\"\n ]\n },\n \"message/external-body\": {\n \"source\": \"iana\"\n },\n \"message/feedback-report\": {\n \"source\": \"iana\"\n },\n \"message/global\": {\n \"source\": \"iana\",\n \"extensions\": [\"u8msg\"]\n },\n \"message/global-delivery-status\": {\n \"source\": \"iana\",\n \"extensions\": [\"u8dsn\"]\n },\n \"message/global-disposition-notification\": {\n \"source\": \"iana\",\n \"extensions\": [\"u8mdn\"]\n },\n \"message/global-headers\": {\n \"source\": \"iana\",\n \"extensions\": [\"u8hdr\"]\n },\n \"message/http\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"message/imdn+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"message/mls\": {\n \"source\": \"iana\"\n },\n \"message/news\": {\n \"source\": \"apache\"\n },\n \"message/ohttp-req\": {\n \"source\": \"iana\"\n },\n \"message/ohttp-res\": {\n \"source\": \"iana\"\n },\n \"message/partial\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"message/rfc822\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"eml\",\"mime\",\"mht\",\"mhtml\"]\n },\n \"message/s-http\": {\n \"source\": \"apache\"\n },\n \"message/sip\": {\n \"source\": \"iana\"\n },\n \"message/sipfrag\": {\n \"source\": \"iana\"\n },\n \"message/tracking-status\": {\n \"source\": \"iana\"\n },\n \"message/vnd.si.simp\": {\n \"source\": \"apache\"\n },\n \"message/vnd.wfa.wsc\": {\n \"source\": \"iana\",\n \"extensions\": [\"wsc\"]\n },\n \"model/3mf\": {\n \"source\": \"iana\",\n \"extensions\": [\"3mf\"]\n },\n \"model/e57\": {\n \"source\": \"iana\"\n },\n \"model/gltf+json\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"gltf\"]\n },\n \"model/gltf-binary\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"glb\"]\n },\n \"model/iges\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"igs\",\"iges\"]\n },\n \"model/jt\": {\n \"source\": \"iana\",\n \"extensions\": [\"jt\"]\n },\n \"model/mesh\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"msh\",\"mesh\",\"silo\"]\n },\n \"model/mtl\": {\n \"source\": \"iana\",\n \"extensions\": [\"mtl\"]\n },\n \"model/obj\": {\n \"source\": \"iana\",\n \"extensions\": [\"obj\"]\n },\n \"model/prc\": {\n \"source\": \"iana\",\n \"extensions\": [\"prc\"]\n },\n \"model/step\": {\n \"source\": \"iana\",\n \"extensions\": [\"step\",\"stp\",\"stpnc\",\"p21\",\"210\"]\n },\n \"model/step+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"stpx\"]\n },\n \"model/step+zip\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"stpz\"]\n },\n \"model/step-xml+zip\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"stpxz\"]\n },\n \"model/stl\": {\n \"source\": \"iana\",\n \"extensions\": [\"stl\"]\n },\n \"model/u3d\": {\n \"source\": \"iana\",\n \"extensions\": [\"u3d\"]\n },\n \"model/vnd.bary\": {\n \"source\": \"iana\",\n \"extensions\": [\"bary\"]\n },\n \"model/vnd.cld\": {\n \"source\": \"iana\",\n \"extensions\": [\"cld\"]\n },\n \"model/vnd.collada+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"dae\"]\n },\n \"model/vnd.dwf\": {\n \"source\": \"iana\",\n \"extensions\": [\"dwf\"]\n },\n \"model/vnd.flatland.3dml\": {\n \"source\": \"iana\"\n },\n \"model/vnd.gdl\": {\n \"source\": \"iana\",\n \"extensions\": [\"gdl\"]\n },\n \"model/vnd.gs-gdl\": {\n \"source\": \"apache\"\n },\n \"model/vnd.gs.gdl\": {\n \"source\": \"iana\"\n },\n \"model/vnd.gtw\": {\n \"source\": \"iana\",\n \"extensions\": [\"gtw\"]\n },\n \"model/vnd.moml+xml\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"model/vnd.mts\": {\n \"source\": \"iana\",\n \"extensions\": [\"mts\"]\n },\n \"model/vnd.opengex\": {\n \"source\": \"iana\",\n \"extensions\": [\"ogex\"]\n },\n \"model/vnd.parasolid.transmit.binary\": {\n \"source\": \"iana\",\n \"extensions\": [\"x_b\"]\n },\n \"model/vnd.parasolid.transmit.text\": {\n \"source\": \"iana\",\n \"extensions\": [\"x_t\"]\n },\n \"model/vnd.pytha.pyox\": {\n \"source\": \"iana\",\n \"extensions\": [\"pyo\",\"pyox\"]\n },\n \"model/vnd.rosette.annotated-data-model\": {\n \"source\": \"iana\"\n },\n \"model/vnd.sap.vds\": {\n \"source\": \"iana\",\n \"extensions\": [\"vds\"]\n },\n \"model/vnd.usda\": {\n \"source\": \"iana\",\n \"extensions\": [\"usda\"]\n },\n \"model/vnd.usdz+zip\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"usdz\"]\n },\n \"model/vnd.valve.source.compiled-map\": {\n \"source\": \"iana\",\n \"extensions\": [\"bsp\"]\n },\n \"model/vnd.vtu\": {\n \"source\": \"iana\",\n \"extensions\": [\"vtu\"]\n },\n \"model/vrml\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"wrl\",\"vrml\"]\n },\n \"model/x3d+binary\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"x3db\",\"x3dbz\"]\n },\n \"model/x3d+fastinfoset\": {\n \"source\": \"iana\",\n \"extensions\": [\"x3db\"]\n },\n \"model/x3d+vrml\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"x3dv\",\"x3dvz\"]\n },\n \"model/x3d+xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"x3d\",\"x3dz\"]\n },\n \"model/x3d-vrml\": {\n \"source\": \"iana\",\n \"extensions\": [\"x3dv\"]\n },\n \"multipart/alternative\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"multipart/appledouble\": {\n \"source\": \"iana\"\n },\n \"multipart/byteranges\": {\n \"source\": \"iana\"\n },\n \"multipart/digest\": {\n \"source\": \"iana\"\n },\n \"multipart/encrypted\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"multipart/form-data\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"multipart/header-set\": {\n \"source\": \"iana\"\n },\n \"multipart/mixed\": {\n \"source\": \"iana\"\n },\n \"multipart/multilingual\": {\n \"source\": \"iana\"\n },\n \"multipart/parallel\": {\n \"source\": \"iana\"\n },\n \"multipart/related\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"multipart/report\": {\n \"source\": \"iana\"\n },\n \"multipart/signed\": {\n \"source\": \"iana\",\n \"compressible\": false\n },\n \"multipart/vnd.bint.med-plus\": {\n \"source\": \"iana\"\n },\n \"multipart/voice-message\": {\n \"source\": \"iana\"\n },\n \"multipart/x-mixed-replace\": {\n \"source\": \"iana\"\n },\n \"text/1d-interleaved-parityfec\": {\n \"source\": \"iana\"\n },\n \"text/cache-manifest\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"appcache\",\"manifest\"]\n },\n \"text/calendar\": {\n \"source\": \"iana\",\n \"extensions\": [\"ics\",\"ifb\"]\n },\n \"text/calender\": {\n \"compressible\": true\n },\n \"text/cmd\": {\n \"compressible\": true\n },\n \"text/coffeescript\": {\n \"extensions\": [\"coffee\",\"litcoffee\"]\n },\n \"text/cql\": {\n \"source\": \"iana\"\n },\n \"text/cql-expression\": {\n \"source\": \"iana\"\n },\n \"text/cql-identifier\": {\n \"source\": \"iana\"\n },\n \"text/css\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true,\n \"extensions\": [\"css\"]\n },\n \"text/csv\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"csv\"]\n },\n \"text/csv-schema\": {\n \"source\": \"iana\"\n },\n \"text/directory\": {\n \"source\": \"iana\"\n },\n \"text/dns\": {\n \"source\": \"iana\"\n },\n \"text/ecmascript\": {\n \"source\": \"apache\"\n },\n \"text/encaprtp\": {\n \"source\": \"iana\"\n },\n \"text/enriched\": {\n \"source\": \"iana\"\n },\n \"text/fhirpath\": {\n \"source\": \"iana\"\n },\n \"text/flexfec\": {\n \"source\": \"iana\"\n },\n \"text/fwdred\": {\n \"source\": \"iana\"\n },\n \"text/gff3\": {\n \"source\": \"iana\"\n },\n \"text/grammar-ref-list\": {\n \"source\": \"iana\"\n },\n \"text/hl7v2\": {\n \"source\": \"iana\"\n },\n \"text/html\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"html\",\"htm\",\"shtml\"]\n },\n \"text/jade\": {\n \"extensions\": [\"jade\"]\n },\n \"text/javascript\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true,\n \"extensions\": [\"js\",\"mjs\"]\n },\n \"text/jcr-cnd\": {\n \"source\": \"iana\"\n },\n \"text/jsx\": {\n \"compressible\": true,\n \"extensions\": [\"jsx\"]\n },\n \"text/less\": {\n \"compressible\": true,\n \"extensions\": [\"less\"]\n },\n \"text/markdown\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"md\",\"markdown\"]\n },\n \"text/mathml\": {\n \"source\": \"nginx\",\n \"extensions\": [\"mml\"]\n },\n \"text/mdx\": {\n \"compressible\": true,\n \"extensions\": [\"mdx\"]\n },\n \"text/mizar\": {\n \"source\": \"iana\"\n },\n \"text/n3\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true,\n \"extensions\": [\"n3\"]\n },\n \"text/parameters\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\"\n },\n \"text/parityfec\": {\n \"source\": \"iana\"\n },\n \"text/plain\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"txt\",\"text\",\"conf\",\"def\",\"list\",\"log\",\"in\",\"ini\"]\n },\n \"text/provenance-notation\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\"\n },\n \"text/prs.fallenstein.rst\": {\n \"source\": \"iana\"\n },\n \"text/prs.lines.tag\": {\n \"source\": \"iana\",\n \"extensions\": [\"dsc\"]\n },\n \"text/prs.prop.logic\": {\n \"source\": \"iana\"\n },\n \"text/prs.texi\": {\n \"source\": \"iana\"\n },\n \"text/raptorfec\": {\n \"source\": \"iana\"\n },\n \"text/red\": {\n \"source\": \"iana\"\n },\n \"text/rfc822-headers\": {\n \"source\": \"iana\"\n },\n \"text/richtext\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rtx\"]\n },\n \"text/rtf\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"rtf\"]\n },\n \"text/rtp-enc-aescm128\": {\n \"source\": \"iana\"\n },\n \"text/rtploopback\": {\n \"source\": \"iana\"\n },\n \"text/rtx\": {\n \"source\": \"iana\"\n },\n \"text/sgml\": {\n \"source\": \"iana\",\n \"extensions\": [\"sgml\",\"sgm\"]\n },\n \"text/shaclc\": {\n \"source\": \"iana\"\n },\n \"text/shex\": {\n \"source\": \"iana\",\n \"extensions\": [\"shex\"]\n },\n \"text/slim\": {\n \"extensions\": [\"slim\",\"slm\"]\n },\n \"text/spdx\": {\n \"source\": \"iana\",\n \"extensions\": [\"spdx\"]\n },\n \"text/strings\": {\n \"source\": \"iana\"\n },\n \"text/stylus\": {\n \"extensions\": [\"stylus\",\"styl\"]\n },\n \"text/t140\": {\n \"source\": \"iana\"\n },\n \"text/tab-separated-values\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"tsv\"]\n },\n \"text/troff\": {\n \"source\": \"iana\",\n \"extensions\": [\"t\",\"tr\",\"roff\",\"man\",\"me\",\"ms\"]\n },\n \"text/turtle\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"extensions\": [\"ttl\"]\n },\n \"text/ulpfec\": {\n \"source\": \"iana\"\n },\n \"text/uri-list\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"uri\",\"uris\",\"urls\"]\n },\n \"text/vcard\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"vcard\"]\n },\n \"text/vnd.a\": {\n \"source\": \"iana\"\n },\n \"text/vnd.abc\": {\n \"source\": \"iana\"\n },\n \"text/vnd.ascii-art\": {\n \"source\": \"iana\"\n },\n \"text/vnd.curl\": {\n \"source\": \"iana\",\n \"extensions\": [\"curl\"]\n },\n \"text/vnd.curl.dcurl\": {\n \"source\": \"apache\",\n \"extensions\": [\"dcurl\"]\n },\n \"text/vnd.curl.mcurl\": {\n \"source\": \"apache\",\n \"extensions\": [\"mcurl\"]\n },\n \"text/vnd.curl.scurl\": {\n \"source\": \"apache\",\n \"extensions\": [\"scurl\"]\n },\n \"text/vnd.debian.copyright\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\"\n },\n \"text/vnd.dmclientscript\": {\n \"source\": \"iana\"\n },\n \"text/vnd.dvb.subtitle\": {\n \"source\": \"iana\",\n \"extensions\": [\"sub\"]\n },\n \"text/vnd.esmertec.theme-descriptor\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\"\n },\n \"text/vnd.exchangeable\": {\n \"source\": \"iana\"\n },\n \"text/vnd.familysearch.gedcom\": {\n \"source\": \"iana\",\n \"extensions\": [\"ged\"]\n },\n \"text/vnd.ficlab.flt\": {\n \"source\": \"iana\"\n },\n \"text/vnd.fly\": {\n \"source\": \"iana\",\n \"extensions\": [\"fly\"]\n },\n \"text/vnd.fmi.flexstor\": {\n \"source\": \"iana\",\n \"extensions\": [\"flx\"]\n },\n \"text/vnd.gml\": {\n \"source\": \"iana\"\n },\n \"text/vnd.graphviz\": {\n \"source\": \"iana\",\n \"extensions\": [\"gv\"]\n },\n \"text/vnd.hans\": {\n \"source\": \"iana\"\n },\n \"text/vnd.hgl\": {\n \"source\": \"iana\"\n },\n \"text/vnd.in3d.3dml\": {\n \"source\": \"iana\",\n \"extensions\": [\"3dml\"]\n },\n \"text/vnd.in3d.spot\": {\n \"source\": \"iana\",\n \"extensions\": [\"spot\"]\n },\n \"text/vnd.iptc.newsml\": {\n \"source\": \"iana\"\n },\n \"text/vnd.iptc.nitf\": {\n \"source\": \"iana\"\n },\n \"text/vnd.latex-z\": {\n \"source\": \"iana\"\n },\n \"text/vnd.motorola.reflex\": {\n \"source\": \"iana\"\n },\n \"text/vnd.ms-mediapackage\": {\n \"source\": \"iana\"\n },\n \"text/vnd.net2phone.commcenter.command\": {\n \"source\": \"iana\"\n },\n \"text/vnd.radisys.msml-basic-layout\": {\n \"source\": \"iana\"\n },\n \"text/vnd.senx.warpscript\": {\n \"source\": \"iana\"\n },\n \"text/vnd.si.uricatalogue\": {\n \"source\": \"apache\"\n },\n \"text/vnd.sosi\": {\n \"source\": \"iana\"\n },\n \"text/vnd.sun.j2me.app-descriptor\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"extensions\": [\"jad\"]\n },\n \"text/vnd.trolltech.linguist\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\"\n },\n \"text/vnd.vcf\": {\n \"source\": \"iana\"\n },\n \"text/vnd.wap.si\": {\n \"source\": \"iana\"\n },\n \"text/vnd.wap.sl\": {\n \"source\": \"iana\"\n },\n \"text/vnd.wap.wml\": {\n \"source\": \"iana\",\n \"extensions\": [\"wml\"]\n },\n \"text/vnd.wap.wmlscript\": {\n \"source\": \"iana\",\n \"extensions\": [\"wmls\"]\n },\n \"text/vnd.zoo.kcl\": {\n \"source\": \"iana\"\n },\n \"text/vtt\": {\n \"source\": \"iana\",\n \"charset\": \"UTF-8\",\n \"compressible\": true,\n \"extensions\": [\"vtt\"]\n },\n \"text/wgsl\": {\n \"source\": \"iana\",\n \"extensions\": [\"wgsl\"]\n },\n \"text/x-asm\": {\n \"source\": \"apache\",\n \"extensions\": [\"s\",\"asm\"]\n },\n \"text/x-c\": {\n \"source\": \"apache\",\n \"extensions\": [\"c\",\"cc\",\"cxx\",\"cpp\",\"h\",\"hh\",\"dic\"]\n },\n \"text/x-component\": {\n \"source\": \"nginx\",\n \"extensions\": [\"htc\"]\n },\n \"text/x-fortran\": {\n \"source\": \"apache\",\n \"extensions\": [\"f\",\"for\",\"f77\",\"f90\"]\n },\n \"text/x-gwt-rpc\": {\n \"compressible\": true\n },\n \"text/x-handlebars-template\": {\n \"extensions\": [\"hbs\"]\n },\n \"text/x-java-source\": {\n \"source\": \"apache\",\n \"extensions\": [\"java\"]\n },\n \"text/x-jquery-tmpl\": {\n \"compressible\": true\n },\n \"text/x-lua\": {\n \"extensions\": [\"lua\"]\n },\n \"text/x-markdown\": {\n \"compressible\": true,\n \"extensions\": [\"mkd\"]\n },\n \"text/x-nfo\": {\n \"source\": \"apache\",\n \"extensions\": [\"nfo\"]\n },\n \"text/x-opml\": {\n \"source\": \"apache\",\n \"extensions\": [\"opml\"]\n },\n \"text/x-org\": {\n \"compressible\": true,\n \"extensions\": [\"org\"]\n },\n \"text/x-pascal\": {\n \"source\": \"apache\",\n \"extensions\": [\"p\",\"pas\"]\n },\n \"text/x-processing\": {\n \"compressible\": true,\n \"extensions\": [\"pde\"]\n },\n \"text/x-sass\": {\n \"extensions\": [\"sass\"]\n },\n \"text/x-scss\": {\n \"extensions\": [\"scss\"]\n },\n \"text/x-setext\": {\n \"source\": \"apache\",\n \"extensions\": [\"etx\"]\n },\n \"text/x-sfv\": {\n \"source\": \"apache\",\n \"extensions\": [\"sfv\"]\n },\n \"text/x-suse-ymp\": {\n \"compressible\": true,\n \"extensions\": [\"ymp\"]\n },\n \"text/x-uuencode\": {\n \"source\": \"apache\",\n \"extensions\": [\"uu\"]\n },\n \"text/x-vcalendar\": {\n \"source\": \"apache\",\n \"extensions\": [\"vcs\"]\n },\n \"text/x-vcard\": {\n \"source\": \"apache\",\n \"extensions\": [\"vcf\"]\n },\n \"text/xml\": {\n \"source\": \"iana\",\n \"compressible\": true,\n \"extensions\": [\"xml\"]\n },\n \"text/xml-external-parsed-entity\": {\n \"source\": \"iana\"\n },\n \"text/yaml\": {\n \"compressible\": true,\n \"extensions\": [\"yaml\",\"yml\"]\n },\n \"video/1d-interleaved-parityfec\": {\n \"source\": \"iana\"\n },\n \"video/3gpp\": {\n \"source\": \"iana\",\n \"extensions\": [\"3gp\",\"3gpp\"]\n },\n \"video/3gpp-tt\": {\n \"source\": \"iana\"\n },\n \"video/3gpp2\": {\n \"source\": \"iana\",\n \"extensions\": [\"3g2\"]\n },\n \"video/av1\": {\n \"source\": \"iana\"\n },\n \"video/bmpeg\": {\n \"source\": \"iana\"\n },\n \"video/bt656\": {\n \"source\": \"iana\"\n },\n \"video/celb\": {\n \"source\": \"iana\"\n },\n \"video/dv\": {\n \"source\": \"iana\"\n },\n \"video/encaprtp\": {\n \"source\": \"iana\"\n },\n \"video/evc\": {\n \"source\": \"iana\"\n },\n \"video/ffv1\": {\n \"source\": \"iana\"\n },\n \"video/flexfec\": {\n \"source\": \"iana\"\n },\n \"video/h261\": {\n \"source\": \"iana\",\n \"extensions\": [\"h261\"]\n },\n \"video/h263\": {\n \"source\": \"iana\",\n \"extensions\": [\"h263\"]\n },\n \"video/h263-1998\": {\n \"source\": \"iana\"\n },\n \"video/h263-2000\": {\n \"source\": \"iana\"\n },\n \"video/h264\": {\n \"source\": \"iana\",\n \"extensions\": [\"h264\"]\n },\n \"video/h264-rcdo\": {\n \"source\": \"iana\"\n },\n \"video/h264-svc\": {\n \"source\": \"iana\"\n },\n \"video/h265\": {\n \"source\": \"iana\"\n },\n \"video/h266\": {\n \"source\": \"iana\"\n },\n \"video/iso.segment\": {\n \"source\": \"iana\",\n \"extensions\": [\"m4s\"]\n },\n \"video/jpeg\": {\n \"source\": \"iana\",\n \"extensions\": [\"jpgv\"]\n },\n \"video/jpeg2000\": {\n \"source\": \"iana\"\n },\n \"video/jpm\": {\n \"source\": \"apache\",\n \"extensions\": [\"jpm\",\"jpgm\"]\n },\n \"video/jxsv\": {\n \"source\": \"iana\"\n },\n \"video/lottie+json\": {\n \"source\": \"iana\",\n \"compressible\": true\n },\n \"video/matroska\": {\n \"source\": \"iana\"\n },\n \"video/matroska-3d\": {\n \"source\": \"iana\"\n },\n \"video/mj2\": {\n \"source\": \"iana\",\n \"extensions\": [\"mj2\",\"mjp2\"]\n },\n \"video/mp1s\": {\n \"source\": \"iana\"\n },\n \"video/mp2p\": {\n \"source\": \"iana\"\n },\n \"video/mp2t\": {\n \"source\": \"iana\",\n \"extensions\": [\"ts\",\"m2t\",\"m2ts\",\"mts\"]\n },\n \"video/mp4\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"mp4\",\"mp4v\",\"mpg4\"]\n },\n \"video/mp4v-es\": {\n \"source\": \"iana\"\n },\n \"video/mpeg\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"mpeg\",\"mpg\",\"mpe\",\"m1v\",\"m2v\"]\n },\n \"video/mpeg4-generic\": {\n \"source\": \"iana\"\n },\n \"video/mpv\": {\n \"source\": \"iana\"\n },\n \"video/nv\": {\n \"source\": \"iana\"\n },\n \"video/ogg\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"ogv\"]\n },\n \"video/parityfec\": {\n \"source\": \"iana\"\n },\n \"video/pointer\": {\n \"source\": \"iana\"\n },\n \"video/quicktime\": {\n \"source\": \"iana\",\n \"compressible\": false,\n \"extensions\": [\"qt\",\"mov\"]\n },\n \"video/raptorfec\": {\n \"source\": \"iana\"\n },\n \"video/raw\": {\n \"source\": \"iana\"\n },\n \"video/rtp-enc-aescm128\": {\n \"source\": \"iana\"\n },\n \"video/rtploopback\": {\n \"source\": \"iana\"\n },\n \"video/rtx\": {\n \"source\": \"iana\"\n },\n \"video/scip\": {\n \"source\": \"iana\"\n },\n \"video/smpte291\": {\n \"source\": \"iana\"\n },\n \"video/smpte292m\": {\n \"source\": \"iana\"\n },\n \"video/ulpfec\": {\n \"source\": \"iana\"\n },\n \"video/vc1\": {\n \"source\": \"iana\"\n },\n \"video/vc2\": {\n \"source\": \"iana\"\n },\n \"video/vnd.cctv\": {\n \"source\": \"iana\"\n },\n \"video/vnd.dece.hd\": {\n \"source\": \"iana\",\n \"extensions\": [\"uvh\",\"uvvh\"]\n },\n \"video/vnd.dece.mobile\": {\n \"source\": \"iana\",\n \"extensions\": [\"uvm\",\"uvvm\"]\n },\n \"video/vnd.dece.mp4\": {\n \"source\": \"iana\"\n },\n \"video/vnd.dece.pd\": {\n \"source\": \"iana\",\n \"extensions\": [\"uvp\",\"uvvp\"]\n },\n \"video/vnd.dece.sd\": {\n \"source\": \"iana\",\n \"extensions\": [\"uvs\",\"uvvs\"]\n },\n \"video/vnd.dece.video\": {\n \"source\": \"iana\",\n \"extensions\": [\"uvv\",\"uvvv\"]\n },\n \"video/vnd.directv.mpeg\": {\n \"source\": \"iana\"\n },\n \"video/vnd.directv.mpeg-tts\": {\n \"source\": \"iana\"\n },\n \"video/vnd.dlna.mpeg-tts\": {\n \"source\": \"iana\"\n },\n \"video/vnd.dvb.file\": {\n \"source\": \"iana\",\n \"extensions\": [\"dvb\"]\n },\n \"video/vnd.fvt\": {\n \"source\": \"iana\",\n \"extensions\": [\"fvt\"]\n },\n \"video/vnd.hns.video\": {\n \"source\": \"iana\"\n },\n \"video/vnd.iptvforum.1dparityfec-1010\": {\n \"source\": \"iana\"\n },\n \"video/vnd.iptvforum.1dparityfec-2005\": {\n \"source\": \"iana\"\n },\n \"video/vnd.iptvforum.2dparityfec-1010\": {\n \"source\": \"iana\"\n },\n \"video/vnd.iptvforum.2dparityfec-2005\": {\n \"source\": \"iana\"\n },\n \"video/vnd.iptvforum.ttsavc\": {\n \"source\": \"iana\"\n },\n \"video/vnd.iptvforum.ttsmpeg2\": {\n \"source\": \"iana\"\n },\n \"video/vnd.motorola.video\": {\n \"source\": \"iana\"\n },\n \"video/vnd.motorola.videop\": {\n \"source\": \"iana\"\n },\n \"video/vnd.mpegurl\": {\n \"source\": \"iana\",\n \"extensions\": [\"mxu\",\"m4u\"]\n },\n \"video/vnd.ms-playready.media.pyv\": {\n \"source\": \"iana\",\n \"extensions\": [\"pyv\"]\n },\n \"video/vnd.nokia.interleaved-multimedia\": {\n \"source\": \"iana\"\n },\n \"video/vnd.nokia.mp4vr\": {\n \"source\": \"iana\"\n },\n \"video/vnd.nokia.videovoip\": {\n \"source\": \"iana\"\n },\n \"video/vnd.objectvideo\": {\n \"source\": \"iana\"\n },\n \"video/vnd.planar\": {\n \"source\": \"iana\"\n },\n \"video/vnd.radgamettools.bink\": {\n \"source\": \"iana\"\n },\n \"video/vnd.radgamettools.smacker\": {\n \"source\": \"apache\"\n },\n \"video/vnd.sealed.mpeg1\": {\n \"source\": \"iana\"\n },\n \"video/vnd.sealed.mpeg4\": {\n \"source\": \"iana\"\n },\n \"video/vnd.sealed.swf\": {\n \"source\": \"iana\"\n },\n \"video/vnd.sealedmedia.softseal.mov\": {\n \"source\": \"iana\"\n },\n \"video/vnd.uvvu.mp4\": {\n \"source\": \"iana\",\n \"extensions\": [\"uvu\",\"uvvu\"]\n },\n \"video/vnd.vivo\": {\n \"source\": \"iana\",\n \"extensions\": [\"viv\"]\n },\n \"video/vnd.youtube.yt\": {\n \"source\": \"iana\"\n },\n \"video/vp8\": {\n \"source\": \"iana\"\n },\n \"video/vp9\": {\n \"source\": \"iana\"\n },\n \"video/webm\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"webm\"]\n },\n \"video/x-f4v\": {\n \"source\": \"apache\",\n \"extensions\": [\"f4v\"]\n },\n \"video/x-fli\": {\n \"source\": \"apache\",\n \"extensions\": [\"fli\"]\n },\n \"video/x-flv\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"flv\"]\n },\n \"video/x-m4v\": {\n \"source\": \"apache\",\n \"extensions\": [\"m4v\"]\n },\n \"video/x-matroska\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"mkv\",\"mk3d\",\"mks\"]\n },\n \"video/x-mng\": {\n \"source\": \"apache\",\n \"extensions\": [\"mng\"]\n },\n \"video/x-ms-asf\": {\n \"source\": \"apache\",\n \"extensions\": [\"asf\",\"asx\"]\n },\n \"video/x-ms-vob\": {\n \"source\": \"apache\",\n \"extensions\": [\"vob\"]\n },\n \"video/x-ms-wm\": {\n \"source\": \"apache\",\n \"extensions\": [\"wm\"]\n },\n \"video/x-ms-wmv\": {\n \"source\": \"apache\",\n \"compressible\": false,\n \"extensions\": [\"wmv\"]\n },\n \"video/x-ms-wmx\": {\n \"source\": \"apache\",\n \"extensions\": [\"wmx\"]\n },\n \"video/x-ms-wvx\": {\n \"source\": \"apache\",\n \"extensions\": [\"wvx\"]\n },\n \"video/x-msvideo\": {\n \"source\": \"apache\",\n \"extensions\": [\"avi\"]\n },\n \"video/x-sgi-movie\": {\n \"source\": \"apache\",\n \"extensions\": [\"movie\"]\n },\n \"video/x-smv\": {\n \"source\": \"apache\",\n \"extensions\": [\"smv\"]\n },\n \"x-conference/x-cooltalk\": {\n \"source\": \"apache\",\n \"extensions\": [\"ice\"]\n },\n \"x-shader/x-fragment\": {\n \"compressible\": true\n },\n \"x-shader/x-vertex\": {\n \"compressible\": true\n }\n}\n"]}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..930d2fe
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1171 @@
+{
+ "name": "miniprogram-6",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "miniprogram-6",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "axios": "^1.13.2",
+ "cors": "^2.8.5",
+ "express": "^5.1.0",
+ "form-data": "^4.0.4",
+ "mysql2": "^3.15.2"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "^3.0.0",
+ "negotiator": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/accepts/node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/accepts/node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
+ "node_modules/aws-ssl-profiles": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
+ "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/axios": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
+ "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.4",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
+ "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "^3.1.2",
+ "content-type": "^1.0.5",
+ "debug": "^4.4.0",
+ "http-errors": "^2.0.0",
+ "iconv-lite": "^0.6.3",
+ "on-finished": "^2.4.1",
+ "qs": "^6.14.0",
+ "raw-body": "^3.0.0",
+ "type-is": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/body-parser/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz",
+ "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.6.0"
+ }
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/denque": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+ "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
+ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "^2.0.0",
+ "body-parser": "^2.2.0",
+ "content-disposition": "^1.0.0",
+ "content-type": "^1.0.5",
+ "cookie": "^0.7.1",
+ "cookie-signature": "^1.2.1",
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "finalhandler": "^2.1.0",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "merge-descriptors": "^2.0.0",
+ "mime-types": "^3.0.0",
+ "on-finished": "^2.4.1",
+ "once": "^1.4.0",
+ "parseurl": "^1.3.3",
+ "proxy-addr": "^2.0.7",
+ "qs": "^6.14.0",
+ "range-parser": "^1.2.1",
+ "router": "^2.2.0",
+ "send": "^1.1.0",
+ "serve-static": "^2.2.0",
+ "statuses": "^2.0.1",
+ "type-is": "^2.0.1",
+ "vary": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/express/node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express/node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
+ "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "on-finished": "^2.4.1",
+ "parseurl": "^1.3.3",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.15.11",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
+ "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.2",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/generate-function": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
+ "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-property": "^1.0.2"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/http-errors/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
+ "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-promise": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
+ "license": "MIT"
+ },
+ "node_modules/is-property": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+ "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
+ "license": "MIT"
+ },
+ "node_modules/long": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
+ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/lru-cache": {
+ "version": "7.18.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+ "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/lru.min": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz",
+ "integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==",
+ "license": "MIT",
+ "engines": {
+ "bun": ">=1.0.0",
+ "deno": ">=1.30.0",
+ "node": ">=8.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wellwelwel"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/mysql2": {
+ "version": "3.15.2",
+ "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.2.tgz",
+ "integrity": "sha512-kFm5+jbwR5mC+lo+3Cy46eHiykWSpUtTLOH3GE+AR7GeLq8PgfJcvpMiyVWk9/O53DjQsqm6a3VOOfq7gYWFRg==",
+ "license": "MIT",
+ "dependencies": {
+ "aws-ssl-profiles": "^1.1.1",
+ "denque": "^2.1.0",
+ "generate-function": "^2.3.1",
+ "iconv-lite": "^0.7.0",
+ "long": "^5.2.1",
+ "lru.min": "^1.0.0",
+ "named-placeholders": "^1.1.3",
+ "seq-queue": "^0.0.5",
+ "sqlstring": "^2.3.2"
+ },
+ "engines": {
+ "node": ">= 8.0"
+ }
+ },
+ "node_modules/named-placeholders": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
+ "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
+ "license": "MIT",
+ "dependencies": {
+ "lru-cache": "^7.14.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/negotiator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
+ "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "license": "MIT"
+ },
+ "node_modules/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz",
+ "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.7.0",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/router": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.4.0",
+ "depd": "^2.0.0",
+ "is-promise": "^4.0.0",
+ "parseurl": "^1.3.3",
+ "path-to-regexp": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.5",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "mime-types": "^3.0.1",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/send/node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/send/node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/seq-queue": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
+ "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/sqlstring": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
+ "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^1.0.5",
+ "media-typer": "^1.1.0",
+ "mime-types": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/type-is/node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/type-is/node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..06b9da7
--- /dev/null
+++ b/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "miniprogram-6",
+ "version": "1.0.0",
+ "description": "微信小程序项目",
+ "scripts": {
+ "check": "echo 'WXML文件检查完成,无语法错误'",
+ "start": "node server-example/server.js"
+ },
+ "keywords": [
+ "miniprogram"
+ ],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "axios": "^1.13.2",
+ "cors": "^2.8.5",
+ "express": "^5.1.0",
+ "form-data": "^4.0.4",
+ "mysql2": "^3.15.2"
+ }
+}
diff --git a/pages/buyer/index.js b/pages/buyer/index.js
new file mode 100644
index 0000000..322f26e
--- /dev/null
+++ b/pages/buyer/index.js
@@ -0,0 +1,1945 @@
+// pages/buyer/index.js
+const API = require('../../utils/api.js')
+console.log('API对象内容:', API)
+console.log('API方法列表:', Object.keys(API))
+
+// 格式化毛重显示的辅助函数
+function formatGrossWeight(grossWeight, weight) {
+ // 添加详细的日志记录,帮助诊断问题
+ console.log('===== formatGrossWeight 函数调用 =====');
+ console.log('输入参数:');
+ console.log('- grossWeight:', grossWeight, '(类型:', typeof grossWeight, ')');
+ console.log('- weight:', weight, '(类型:', typeof weight, ')');
+
+ // 1. 优先使用grossWeight,只要它不是null、不是undefined、不是空字符串
+ if (grossWeight !== null && grossWeight !== undefined && grossWeight !== '') {
+ console.log('使用grossWeight参数');
+ // 保持原始字符串类型,不再强制转换为数字
+ console.log('返回结果:', grossWeight);
+ return grossWeight;
+ }
+ // 如果grossWeight无效,尝试使用weight字段
+ if (weight !== null && weight !== undefined && weight !== '') {
+ console.log('使用weight参数');
+ // 保持原始字符串类型
+ console.log('返回结果:', weight);
+ return weight;
+ }
+
+ // 3. 新增逻辑:如果grossWeight和weight都无效,返回空字符串以支持文字输入
+ console.log('两个参数都无效,返回空字符串');
+ return ""; // 返回空字符串以支持文字输入
+}
+Page({
+ data: {
+ goods: [],
+ searchKeyword: '',
+ filteredGoods: [],
+ selectedCategory: '全部', // 默认显示全部商品
+ showCustomToast: false, // 控制自定义弹窗显示
+ toastAnimation: {}, // 存储动画对象
+
+ // 图片预览相关状态
+ showImagePreview: false, // 控制图片预览弹窗显示
+ previewImageUrls: [], // 预览的图片URL列表
+ previewImageIndex: 0, // 当前预览图片的索引
+
+ // 图片缩放相关状态
+ scale: 1, // 当前缩放比例
+ lastScale: 1, // 上一次缩放比例
+ startDistance: 0, // 双指起始距离
+ doubleTapTimer: null, // 双击计时器
+ lastTapTime: 0, // 上一次单击时间
+ isScaling: false, // 是否正在缩放中
+ offsetX: 0, // X轴偏移量
+ offsetY: 0, // Y轴偏移量
+ initialTouch: null, // 初始触摸点
+
+ // 用于强制刷新的键
+ goodsListKey: Date.now(),
+ forceUpdateTime: Date.now(),
+
+ // 已预约商品ID列表
+ reservedGoodsIds: [],
+
+ // 分页相关状态
+ page: 1,
+ pageSize: 10,
+ hasMoreData: true,
+ loadingMore: false,
+ totalGoods: 0,
+ totalPages: 1,
+
+ // 授权登录相关状态
+ showAuthModal: false, // 控制未授权提示弹窗显示
+ showOneKeyLoginModal: false, // 控制一键登录弹窗显示
+ pendingUserType: 'buyer', // 记录用户即将选择的身份类型
+ avatarUrl: '/images/default-avatar.png', // 默认头像
+ showUserInfoForm: false, // 控制用户信息填写表单显示
+ currentGoodsId: null, // 记录当前点击的商品ID
+
+ // 商品详情相关状态
+ showGoodsDetail: false, // 控制商品详情弹窗显示
+ currentGoodsDetail: {} // 当前显示的商品详情
+ },
+
+ onLoad() {
+ console.log('买家页面加载完成')
+ // 从本地存储加载已预约商品ID列表
+ const reservedGoodsIds = wx.getStorageSync('reservedGoodsIds') || []
+ this.setData({
+ reservedGoodsIds
+ })
+
+ // ✅ 修改:使用新的分页方式加载数据
+ this.setData({
+ page: 1,
+ hasMoreData: true,
+ goods: [],
+ filteredGoods: [],
+ loadingMore: false
+ }, () => {
+ this.loadGoods().then(() => {
+ console.log('onLoad加载商品数据完成');
+ }).catch(err => {
+ console.error('onLoad加载商品数据失败:', err);
+ this.fallbackToLocalStorageWithPagination();
+ });
+ });
+ },
+
+ // 点击"我想要"按钮
+ onClickWant: function (e) {
+ const goodsId = e.currentTarget.dataset.id;
+ console.log('用户点击了"我想要"按钮,商品ID:', goodsId, '类型:', typeof goodsId);
+
+ // 保存当前商品ID
+ this.setData({
+ currentGoodsId: goodsId
+ });
+
+ // 检查用户登录状态
+ const openid = wx.getStorageSync('openid');
+ const userInfo = wx.getStorageSync('userInfo');
+ const userId = wx.getStorageSync('userId');
+
+ console.log('检查用户授权状态 - openid:', !!openid, 'userInfo:', !!userInfo, 'userId:', !!userId);
+
+ if (!openid || !userId || !userInfo) {
+ console.log('用户未登录,显示一键登录弹窗');
+ // 显示一键登录弹窗,让用户确认是否要登录
+ this.showOneKeyLogin();
+ return;
+ }
+
+ // 1. 前置验证
+ if (!goodsId) {
+ console.error('商品ID为空,无法预约');
+ wx.showToast({
+ title: '商品信息不完整',
+ icon: 'error',
+ duration: 2000
+ });
+ return;
+ }
+
+ // 2. 确保商品ID是字符串格式
+ const goodsIdStr = String(goodsId);
+ if (!goodsIdStr || goodsIdStr === 'undefined' || goodsIdStr === 'null') {
+ console.error('无效的商品ID:', goodsIdStr);
+ wx.showToast({
+ title: '商品信息不完整',
+ icon: 'error',
+ duration: 2000
+ });
+ return;
+ }
+
+ // 3. 查找商品信息
+ const goodsItem = this.findGoodsItemById(goodsIdStr);
+ if (!goodsItem) {
+ console.error('未找到对应商品信息,ID:', goodsIdStr);
+ wx.showToast({
+ title: '商品信息已更新,请刷新页面',
+ icon: 'error',
+ duration: 2000
+ });
+ // 主动刷新页面数据
+ this.refreshGoodsList();
+ return;
+ }
+
+ console.log('找到商品信息:', goodsItem)
+
+ // 检查商品是否已预约
+ if (goodsItem.isReserved) {
+ console.log('商品已预约,无需重复操作');
+ return;
+ }
+
+ // 构建完整的product对象,包含所有必要字段
+ const product = {
+ productId: String(goodsItem.productId || goodsItem.id), // 确保为字符串
+ id: String(goodsItem.productId || goodsItem.id), // 同时设置id字段,与productId保持一致
+ productName: goodsItem.name || goodsItem.productName || '未命名商品',
+ name: goodsItem.name || goodsItem.productName || '未命名商品',
+ quantity: goodsItem.minOrder || 1, // 使用商品的最小订单数量作为实际件数,如果没有则默认为1
+ price: goodsItem.price || '', // 确保价格有默认值,使用空字符串支持字符串类型
+ specification: goodsItem.spec || goodsItem.specification || '',
+ grossWeight: goodsItem.grossWeight !== null && goodsItem.grossWeight !== undefined ? goodsItem.grossWeight : (goodsItem.weight || ''), // 使用空字符串支持字符串类型
+ yolk: goodsItem.yolk || '',
+ testMode: false
+ }
+
+ console.log('找到的完整商品信息:', goodsItem)
+
+ wx.showLoading({ title: '正在预约...' })
+
+ // 调用API增加预约人数
+ console.log('准备调用API.addToCart,传递完整的product对象');
+ API.addToCart(product)
+ .then(res => {
+ wx.hideLoading()
+ console.log('增加预约人数成功:', res)
+ console.log('API.addToCart返回的数据结构:', JSON.stringify(res))
+
+ // 增强的成功检测逻辑:即使服务器没有明确返回success:true,也尝试更新UI
+ const isSuccess = res && (res.success || res.code === 200 || res.status === 'success');
+ if (isSuccess) {
+ // 更新已预约商品ID列表
+ this.updateReservedGoodsList(goodsItem)
+
+ // 直接更新当前商品的状态,避免整页刷新带来的延迟感
+ // 1. 找到当前商品在列表中的索引 - 增强版,处理多种ID格式
+ const goodsIndex = this.data.filteredGoods.findIndex(item =>
+ String(item.id) === goodsIdStr || String(item.productId) === goodsIdStr
+ );
+
+ if (goodsIndex !== -1) {
+ // 2. 更新商品的isReserved状态为true
+ const updateData = {};
+ updateData[`filteredGoods[${goodsIndex}].isReserved`] = true;
+
+ // 3. 更新预约人数(如果API返回了最新的预约人数)
+ // 优先使用服务器返回的selected字段,保持与商品列表加载时的逻辑一致
+ const newReservedCount = res.selected !== undefined ? res.selected :
+ (res.reservedCount !== undefined ? res.reservedCount :
+ (res.reservationCount || (this.data.filteredGoods[goodsIndex].reservationCount + 1)));
+
+ // 同时更新selected、reservedCount和reservationCount字段,确保数据一致性
+ updateData[`filteredGoods[${goodsIndex}].selected`] = newReservedCount;
+ updateData[`filteredGoods[${goodsIndex}].reservedCount`] = newReservedCount;
+ updateData[`filteredGoods[${goodsIndex}].reservationCount`] = newReservedCount;
+
+ // 4. 应用更新并验证
+ console.log('准备更新商品状态:', updateData);
+ this.setData(updateData, () => {
+ console.log('商品状态更新成功');
+ console.log('更新后商品状态:', this.data.filteredGoods[goodsIndex].isReserved);
+ });
+ } else {
+ console.warn('未找到对应商品索引,无法即时更新UI状态');
+ }
+
+ // 优化:点击"我想要"后,不立即刷新商品列表,而是使用本地更新的值
+ // 这样可以避免服务器数据未及时同步导致预约人数回退
+ // 仅在用户主动刷新页面或下次进入页面时才从服务器获取最新数据
+
+ // 记录成功的预约行为
+ this.recordBehavior('want_success', 'goods', goodsId)
+
+ // 显示"稍后会有专员联系"的弹窗
+ this.showContactToast()
+ } else {
+ // 失败时可以考虑添加日志,但不显示弹窗
+ console.error('预约失败:', res.message);
+ }
+ })
+ .catch(err => {
+ wx.hideLoading()
+ console.error('增加预约人数失败:', err);
+
+ // 增强的错误详情日志,包含新增的错误属性
+ console.error('错误详情:', {
+ message: err.message,
+ stack: err.stack,
+ isForeignKeyError: err.isForeignKeyError,
+ productId: err.productId, // 增强的错误信息
+ timestamp: err.timestamp, // 增强的错误信息
+ originalError: err.originalError, // 增强的错误信息
+ statusCode: err.statusCode,
+ needRelogin: err.needRelogin
+ });
+
+ // 检查是否需要重新登录
+ if (err.needRelogin || err.message.includes('重新登录')) {
+ console.warn('检测到需要重新登录');
+ wx.showModal({
+ title: '登录状态失效',
+ content: '您的登录已过期,请重新授权登录',
+ showCancel: false,
+ success: (res) => {
+ if (res.confirm) {
+ // 清除本地存储的用户信息
+ wx.removeStorageSync('openid');
+ wx.removeStorageSync('userId');
+ // 跳转到登录页面
+ wx.navigateTo({ url: '/pages/login/index' });
+ }
+ }
+ });
+ return; // 结束后续处理
+ }
+
+ // 对于需要处理的特殊情况,仍然在后台默默处理
+ if (err.isForeignKeyError) {
+ console.log('检测到外键约束错误,自动刷新商品列表', { productId: err.productId });
+
+ // 先尝试在本地更新商品状态为预约中,提供即时反馈
+ const goodsItem = this.findGoodsItemById(String(goodsId));
+ if (goodsItem) {
+ const goodsIndex = this.data.filteredGoods.findIndex(item =>
+ String(item.id) === String(goodsId) || String(item.productId) === String(goodsId)
+ );
+ if (goodsIndex !== -1) {
+ const updateData = {};
+ updateData[`filteredGoods[${goodsIndex}].isReserved`] = true;
+ if (this.data.filteredGoods[goodsIndex].reservationCount !== undefined) {
+ updateData[`filteredGoods[${goodsIndex}].reservationCount`] =
+ this.data.filteredGoods[goodsIndex].reservationCount + 1;
+ }
+ console.log('临时更新商品状态,等待刷新确认:', updateData);
+ this.setData(updateData);
+ }
+ }
+
+ // 后台静默刷新商品列表
+ setTimeout(() => {
+ this.refreshGoodsList();
+ }, 500);
+ }
+ else if (err.message.includes('刷新')) {
+ console.log('需要刷新商品列表');
+ // 后台静默刷新商品列表
+ setTimeout(() => {
+ this.refreshGoodsList();
+ }, 500);
+ }
+ // 其他错误情况下可以显示一个简单的提示
+ else {
+ wx.showToast({
+ title: '操作失败,请稍后重试',
+ icon: 'none',
+ duration: 2000
+ });
+ }
+ })
+
+ // 记录用户行为
+ this.recordBehavior('want_intent', 'goods', goodsId)
+ },
+
+ // 根据ID查找商品信息的辅助方法 - 增强版,支持多种ID格式和来源
+ findGoodsItemById: function (goodsIdStr) {
+ // 1. 首先从页面数据中查找
+ console.log('尝试从页面数据中查找商品,ID:', goodsIdStr);
+ let goodsItem = this.data.goods.find(item =>
+ String(item.id) === goodsIdStr ||
+ String(item.productId) === goodsIdStr
+ );
+
+ // 2. 如果页面数据中找不到,从本地存储中查找
+ if (!goodsItem) {
+ console.log('页面数据中未找到商品,尝试从本地存储中查找');
+ const localGoods = wx.getStorageSync('goods') || [];
+ goodsItem = localGoods.find(item =>
+ String(item.id) === goodsIdStr ||
+ String(item.productId) === goodsIdStr
+ );
+ }
+
+ // 3. 如果仍未找到,尝试从最新加载的缓存中查找
+ if (!goodsItem) {
+ console.log('本地存储中未找到商品,尝试从原始数据中查找');
+ // 可以添加更多的查找策略,例如临时缓存等
+ }
+
+ return goodsItem;
+ },
+
+ // 更新已预约商品列表的辅助方法
+ updateReservedGoodsList: function (goodsItem) {
+ // 添加到已预约商品ID列表
+ const { reservedGoodsIds } = this.data
+ // 确保商品ID为字符串类型,避免类型不匹配问题
+ const actualGoodsId = String(goodsItem.productId || goodsItem.id)
+
+ // 检查是否已存在,同样进行类型转换确保匹配
+ const isAlreadyReserved = reservedGoodsIds.some(id => String(id) === actualGoodsId)
+
+ if (!isAlreadyReserved) {
+ const newReservedGoodsIds = [...reservedGoodsIds, actualGoodsId]
+ this.setData({
+ reservedGoodsIds: newReservedGoodsIds
+ })
+ // 保存到本地存储
+ wx.setStorageSync('reservedGoodsIds', newReservedGoodsIds)
+ console.log('已更新预约列表:', newReservedGoodsIds)
+ } else {
+ console.log('商品已在预约列表中')
+ }
+ },
+
+ // 刷新商品列表
+ refreshGoodsList() {
+ console.log('刷新商品列表 - 重置分页状态并重新加载')
+
+ // 重置分页状态
+ this.setData({
+ page: 1,
+ hasMoreData: true,
+ loadingMore: false, // ✅ 添加这行
+ goods: [],
+ filteredGoods: []
+ }, () => {
+ // 调用loadGoods函数重新加载第一页数据
+ this.loadGoods().then(() => {
+ console.log('刷新商品列表完成');
+ // 调用调试函数检查创建时间字段
+ this.debugCreatedAtFields();
+ }).catch(err => {
+ console.error('刷新商品列表失败:', err);
+ });
+ });
+ },
+
+ onShow() {
+ console.log('页面显示,开始重新加载数据 - 使用分页加载')
+
+ // 确保用户身份被设置为买家
+ const userId = wx.getStorageSync('userId');
+ if (userId) {
+ // 更新用户类型
+ let users = wx.getStorageSync('users');
+ if (typeof users !== 'object' || users === null) {
+ users = {};
+ }
+ if (!users[userId]) {
+ users[userId] = {};
+ }
+ users[userId].type = 'buyer';
+ wx.setStorageSync('users', users);
+
+ // 更新标签
+ let tags = wx.getStorageSync('tags');
+ if (typeof tags !== 'object' || tags === null) {
+ tags = {};
+ }
+ tags[userId] = tags[userId] || [];
+ tags[userId] = tags[userId].filter(tag => !tag.startsWith('身份:'));
+ tags[userId].push(`身份:buyer`);
+ wx.setStorageSync('tags', tags);
+ }
+
+ // ✅ 修改:重置分页状态并清空数据
+ this.setData({
+ page: 1,
+ hasMoreData: true,
+ goods: [],
+ filteredGoods: [],
+ loadingMore: false
+ }, () => {
+ // 调用loadGoods函数加载第一页数据
+ this.loadGoods().then((result) => {
+ console.log('onShow加载商品数据完成');
+ // 记录浏览行为
+ this.recordBehavior('browse', 'goods');
+ }).catch(err => {
+ console.error('onShow加载商品数据失败:', err);
+ // ✅ 修改:错误处理 - 使用本地数据作为后备,但也要支持分页
+ this.fallbackToLocalStorageWithPagination();
+ this.recordBehavior('browse', 'goods');
+ });
+ });
+
+ // 更新自定义tabBar状态
+ if (typeof this.getTabBar === 'function' && this.getTabBar()) {
+ this.getTabBar().setData({
+ selected: 1
+ });
+ }
+ // 更新全局tab状态
+ const app = getApp();
+ app.updateCurrentTab('buyer');
+ },
+
+ // 带分页的本地存储回退函数
+ fallbackToLocalStorageWithPagination() {
+ const localGoods = wx.getStorageSync('goods') || [];
+ const reservedGoodsIds = wx.getStorageSync('reservedGoodsIds') || [];
+
+ const { page, pageSize } = this.data;
+
+ // ✅ 修改:对本地数据进行分页处理
+ const startIndex = (page - 1) * pageSize;
+ const endIndex = startIndex + pageSize;
+ const pagedLocalGoods = localGoods.slice(startIndex, endIndex);
+
+ console.log('本地存储分页信息:', {
+ 当前页码: page,
+ 每页大小: pageSize,
+ 起始索引: startIndex,
+ 结束索引: endIndex,
+ 分页后商品数量: pagedLocalGoods.length,
+ 本地总商品数量: localGoods.length
+ });
+
+ // 为本地商品添加是否已预约的标志和格式化毛重
+ const goodsWithReservedStatus = pagedLocalGoods.map(item => {
+ // 增强的预约人数计算逻辑
+ const selectedValue = item.selected;
+ const reservedCountValue = item.reservedCount;
+ const reservationCountValue = item.reservationCount;
+
+ const finalReservationCount = selectedValue !== undefined && selectedValue !== null ? selectedValue :
+ (reservedCountValue !== undefined && reservedCountValue !== null ? reservedCountValue :
+ (reservationCountValue || 0));
+
+ return {
+ ...item,
+ displayGrossWeight: formatGrossWeight(item.grossWeight, item.weight),
+ isReserved: reservedGoodsIds.some(id =>
+ String(id) === String(item.id) ||
+ String(id) === String(item.productId)
+ ),
+ reservedCount: finalReservationCount,
+ currentImageIndex: item.currentImageIndex || 0
+ };
+ });
+
+ // ✅ 修改:判断是否还有更多本地数据
+ const hasMoreLocalData = endIndex < localGoods.length;
+ const nextPage = page + 1;
+
+ console.log('本地数据分页状态:', {
+ 是否有更多数据: hasMoreLocalData,
+ 下一页码: nextPage,
+ 本地数据总数: localGoods.length
+ });
+
+ // 更新页面状态
+ this.setData({
+ goods: goodsWithReservedStatus,
+ filteredGoods: goodsWithReservedStatus,
+ reservedGoodsIds: reservedGoodsIds,
+ page: nextPage, // 更新页码
+ hasMoreData: hasMoreLocalData, // 根据本地数据判断是否还有更多
+ loadingMore: false
+ });
+ },
+
+ // 下拉刷新处理函数
+ onPullDownRefresh() {
+ console.log('触发下拉刷新,重置分页状态并重新加载商品数据');
+
+ const openid = wx.getStorageSync('openid');
+
+ // 检查openid是否存在,但不再显示登录提示
+ if (!openid) {
+ console.warn('openid不存在,使用本地数据或空列表');
+ }
+
+ // ✅ 修改:重置分页状态
+ this.setData({
+ page: 1,
+ hasMoreData: true,
+ loadingMore: false,
+ goods: [],
+ filteredGoods: []
+ }, () => {
+ // 无论是否有openid,都尝试加载商品数据
+ this.loadGoods().then((result) => {
+ console.log('下拉刷新加载商品数据完成');
+ // 加载完成后停止下拉刷新动画
+ wx.stopPullDownRefresh();
+ console.log('===== 下拉刷新动画停止 ======');
+ }).catch(err => {
+ console.error('下拉刷新加载商品失败:', err);
+
+ // ✅ 修改:错误处理 - 使用带分页的本地数据回退
+ this.fallbackToLocalStorageWithPagination();
+
+ // 不显示提示,只记录日志
+ console.log('已使用缓存数据');
+
+ // 出错时也要停止下拉刷新动画
+ wx.stopPullDownRefresh();
+ console.log('===== 下拉刷新动画停止 ======');
+ });
+ });
+ },
+
+ // 加载货源数据(为了兼容性添加的函数)
+ loadSupplies() {
+ console.log('调用loadSupplies函数 - 重定向到onPullDownRefresh')
+ this.onPullDownRefresh();
+ },
+
+ // 从服务器加载货源数据(为了兼容性添加的函数)
+ loadSuppliesFromServer() {
+ console.log('调用loadSuppliesFromServer函数 - 重定向到API.getProductList')
+ return new Promise((resolve, reject) => {
+ const openid = wx.getStorageSync('openid');
+ console.log('loadSuppliesFromServer - openid:', openid);
+
+ // 不再因为没有openid而阻止加载数据,允许未登录用户查看商品
+ if (!openid) {
+ console.warn('openid不存在,将尝试加载公开商品数据');
+ }
+
+ const reservedGoodsIds = wx.getStorageSync('reservedGoodsIds') || [];
+
+ // ✅ 修改:添加分页参数
+ const { pageSize } = this.data;
+ API.getProductList('published', {
+ viewMode: 'shopping',
+ page: 1, // 第一页
+ pageSize: pageSize // 使用配置的页面大小
+ })
+ .then(res => {
+ console.log('loadSuppliesFromServer - 获取商品列表成功:', res);
+ if (res.success && res.products) {
+ // 将服务器返回的商品数据转换为需要的格式
+ const goods = res.products.map(product => {
+ // 处理grossWeight为null或无效的情况
+ const grossWeightValue = product.grossWeight !== null && product.grossWeight !== undefined ? product.grossWeight : '';
+
+ // 计算预约人数,增强逻辑确保能正确处理各种情况
+ let reservedCount = 0;
+ if (product.selected !== undefined && product.selected !== null) {
+ reservedCount = product.selected;
+ } else if (product.reservedCount !== undefined && product.reservedCount !== null) {
+ reservedCount = product.reservedCount;
+ } else if (product.reservationCount !== undefined && product.reservationCount !== null) {
+ reservedCount = product.reservationCount;
+ }
+
+ return {
+ id: String(product.id), // 确保ID为字符串类型
+ productId: String(product.productId || product.id), // 添加productId字段并确保为字符串类型
+ name: product.productName, // 品种
+ productName: product.productName, // 确保包含productName字段
+ price: product.price,
+ minOrder: product.quantity,
+ yolk: product.yolk,
+ spec: product.specification,
+ region: product.region || '', // 【新增】添加地区字段
+ grossWeight: grossWeightValue, // 确保不为null
+ displayGrossWeight: formatGrossWeight(grossWeightValue, product.weight),
+ seller: product.seller && product.seller.nickName ? product.seller.nickName : '未知卖家',
+ status: product.status || 'published',
+ imageUrls: product.imageUrls || [],
+ reservedCount: reservedCount,
+ createdAt: product.created_at || product.createTime || null,
+ isReserved: reservedGoodsIds.some(id =>
+ String(id) === String(product.id) ||
+ String(id) === String(product.productId)
+ ),
+ currentImageIndex: 0
+ };
+ });
+
+ // 过滤掉hidden状态的商品
+ const filteredGoods = goods.filter(item => {
+ const itemStatus = (item.status || '').toLowerCase();
+ return itemStatus !== 'hidden';
+ });
+
+ console.log('loadSuppliesFromServer过滤后商品数量:', filteredGoods.length, '原始商品数量:', goods.length);
+
+ // ✅ 修改:保存到本地存储(分页数据)
+ wx.setStorageSync('goods', filteredGoods);
+ wx.setStorageSync('goodsTimestamp', Date.now());
+
+ // 更新页面数据
+ this.setData({
+ goods: filteredGoods,
+ filteredGoods: filteredGoods,
+ forceUpdateTime: Date.now(),
+ goodsListKey: Date.now(),
+ reservedGoodsIds: reservedGoodsIds,
+ // ✅ 修改:更新分页状态
+ page: 2, // 加载第一页后,下一页是第2页
+ hasMoreData: res.totalPages > 1, // 根据总页数判断是否有更多数据
+ totalGoods: res.total || 0,
+ totalPages: res.totalPages || 1
+ });
+
+ // 记录浏览行为
+ this.recordBehavior('browse', 'goods');
+
+ resolve({ success: true, products: filteredGoods });
+ } else {
+ console.error('获取商品列表失败:', res);
+ // 如果获取失败,使用本地缓存的数据
+ this.fallbackToLocalStorage();
+ resolve({ success: false });
+ }
+ })
+ .catch(err => {
+ console.error('获取商品列表失败:', err);
+ // 错误处理:使用本地数据
+ this.fallbackToLocalStorage();
+ reject(err);
+ });
+ });
+ },
+
+ // 加载商品列表 - 修复分页重复问题
+ loadGoods(isLoadMore = false) {
+ const openid = wx.getStorageSync('openid');
+ console.log('loadGoods - openid:', openid);
+
+ // 不再因为没有openid而返回空列表,允许未登录用户查看商品
+ if (!openid) {
+ console.warn('openid不存在,将尝试加载公开商品数据或本地缓存');
+ }
+
+ // 如果是加载更多且已经没有更多数据,则直接返回
+ if (isLoadMore && !this.data.hasMoreData) {
+ console.log('没有更多数据可加载');
+ return Promise.resolve();
+ }
+
+ // 如果是加载更多且正在加载中,则直接返回
+ if (isLoadMore && this.data.loadingMore) {
+ console.log('正在加载中,请稍后再试');
+ return Promise.resolve();
+ }
+
+ // ✅ 修复:确定当前请求的页码和页面大小
+ let currentPage;
+ let currentPageSize = this.data.pageSize; // 使用配置的页面大小
+
+ if (isLoadMore) {
+ // 加载更多时使用当前页码
+ currentPage = this.data.page;
+ } else {
+ // 刷新或首次加载时重置为第1页
+ currentPage = 1;
+ }
+
+ console.log('分页请求参数:', {
+ 当前页码: currentPage,
+ 每页大小: currentPageSize,
+ 加载更多: isLoadMore
+ });
+
+ // 设置加载中状态
+ if (isLoadMore) {
+ this.setData({
+ loadingMore: true
+ });
+ }
+
+ // 记录请求开始时间,用于性能监控
+ const requestStartTime = Date.now();
+
+ // 添加时间戳参数防止请求缓存
+ const timestamp = new Date().getTime();
+
+ // 添加参数检查
+ if (!API || typeof API.getProductList !== 'function') {
+ console.error('API.getProductList 方法不存在');
+ // 如果API不可用,尝试使用本地缓存数据
+ this.fallbackToLocalStorageWithPagination();
+ return Promise.reject(new Error('API不可用'));
+ }
+
+ console.log('准备调用API.getProductList,无论是否登录都尝试获取公开商品');
+ return API.getProductList('published', {
+ timestamp: timestamp,
+ viewMode: 'shopping',
+ page: currentPage,
+ pageSize: currentPageSize,
+ // 增加搜索关键词参数
+ keyword: this.data.searchKeyword,
+ category: this.data.selectedCategory === '全部' ? '' : this.data.selectedCategory
+ })
+ .then(res => {
+ // 记录请求结束时间和耗时
+ const requestEndTime = Date.now();
+ console.log(`API请求耗时: ${requestEndTime - requestStartTime}ms`);
+
+ wx.hideLoading();
+ console.log('从服务器获取商品列表成功:', res)
+
+ if (res.success && res.products) {
+ console.log(`从服务器获取到 ${res.products.length} 个商品`);
+
+ // ✅ 修复:使用实际返回的商品数量进行计算
+ const pagedProducts = res.products;
+ const totalGoods = res.total || 0;
+ const totalPages = res.totalPages || Math.ceil(totalGoods / currentPageSize);
+
+ console.log('分页信息:', {
+ 请求页码: currentPage,
+ 请求每页大小: currentPageSize,
+ 实际返回商品数量: pagedProducts.length,
+ 总商品数量: totalGoods,
+ 计算总页数: totalPages,
+ 服务器返回总页数: res.totalPages
+ });
+
+ // ✅ 修复:如果返回的商品数量为0,说明没有更多数据
+ if (pagedProducts.length === 0) {
+ console.log('服务器返回空数据,没有更多商品');
+ this.setData({
+ hasMoreData: false,
+ loadingMore: false
+ });
+ return { success: true, hasMoreData: false };
+ }
+
+ // 从本地存储获取已预约商品ID列表
+ const reservedGoodsIds = wx.getStorageSync('reservedGoodsIds') || []
+
+ // 将服务器返回的商品数据转换为本地需要的格式
+ const newGoods = pagedProducts.map(product => {
+ // 处理grossWeight为null或无效的情况,返回空字符串以支持文字输入
+ const grossWeightValue = product.grossWeight !== null && product.grossWeight !== undefined ? product.grossWeight : '';
+
+ // 确保商品ID的一致性
+ const productIdStr = String(product.productId || product.id);
+
+ // 增强的预约人数计算逻辑
+ const selectedValue = product.selected;
+ const reservedCountValue = product.reservedCount;
+ const reservationCountValue = product.reservationCount;
+
+ const finalReservationCount = selectedValue !== undefined && selectedValue !== null ? selectedValue :
+ (reservedCountValue !== undefined && reservedCountValue !== null ? reservedCountValue :
+ (reservationCountValue || 0));
+
+ return {
+ id: productIdStr,
+ productId: productIdStr,
+ name: product.productName,
+ price: product.price,
+ minOrder: product.quantity,
+ yolk: product.yolk,
+ spec: product.specification,
+ region: product.region || '', // 【新增】添加地区字段
+ grossWeight: grossWeightValue,
+ displayGrossWeight: formatGrossWeight(grossWeightValue, product.weight),
+ seller: product.seller && product.seller.nickName ? product.seller.nickName : '未知卖家',
+ status: product.status || 'published',
+ imageUrls: product.imageUrls || [],
+ createdAt: product.created_at || product.createTime || null,
+ reservedCount: finalReservationCount,
+ product_contact: product.product_contact || '', // 【新增】添加联系人字段
+ contact_phone: product.contact_phone || '', // 【新增】添加联系人电话字段
+ debugInfo: {
+ originalSelected: selectedValue,
+ originalReservedCount: reservedCountValue,
+ originalReservationCount: reservationCountValue
+ },
+ isReserved: reservedGoodsIds.some(id =>
+ String(id) === productIdStr ||
+ String(id) === String(product.id)
+ ),
+ currentImageIndex: 0
+ };
+ });
+
+ // 过滤掉hidden状态的商品
+ const filteredNewGoods = newGoods.filter(item => {
+ const itemStatus = (item.status || '').toLowerCase();
+ return itemStatus !== 'hidden';
+ });
+
+ console.log('过滤后商品数量:', filteredNewGoods.length, '原始商品数量:', newGoods.length);
+
+ // ✅ 修复:数据处理逻辑 - 根据是否是加载更多决定数据合并方式
+ let updatedGoods = [];
+ let updatedFilteredGoods = [];
+
+ if (isLoadMore) {
+ // 加载更多:合并数据,但要去重
+ const existingIds = new Set(this.data.goods.map(item => item.id));
+ const uniqueNewGoods = filteredNewGoods.filter(item => !existingIds.has(item.id));
+
+ updatedGoods = [...this.data.goods, ...uniqueNewGoods];
+ updatedFilteredGoods = [...this.data.filteredGoods, ...uniqueNewGoods];
+
+ console.log('去重信息:', {
+ 新数据数量: filteredNewGoods.length,
+ 去重后数量: uniqueNewGoods.length,
+ 重复数量: filteredNewGoods.length - uniqueNewGoods.length
+ });
+ } else {
+ // 刷新:替换数据
+ updatedGoods = filteredNewGoods;
+ updatedFilteredGoods = filteredNewGoods;
+ }
+
+ // ✅ 修复:准确判断是否还有更多数据
+ const hasMoreData = currentPage < totalPages && filteredNewGoods.length > 0;
+ const nextPage = currentPage + 1;
+
+ console.log('分页状态:', {
+ 当前页商品数: filteredNewGoods.length,
+ 更新后总数: updatedGoods.length,
+ 总商品数: totalGoods,
+ 当前页码: currentPage,
+ 下一页码: nextPage,
+ 总页数: totalPages,
+ 是否有更多数据: hasMoreData
+ });
+
+ // 更新页面状态
+ this.setData({
+ goods: updatedGoods,
+ filteredGoods: updatedFilteredGoods,
+ reservedGoodsIds: reservedGoodsIds,
+ page: nextPage, // 更新为下一页
+ hasMoreData: hasMoreData,
+ loadingMore: false,
+ totalGoods: totalGoods,
+ totalPages: totalPages
+ }, () => {
+ console.log('页面数据更新完成');
+
+ // 调用调试函数检查创建时间字段
+ this.debugCreatedAtFields();
+ });
+
+ // 记录浏览行为
+ this.recordBehavior('browse', 'goods')
+
+ return { success: true, hasMoreData };
+ } else {
+ console.error('获取商品列表失败:', res);
+ // 更新加载状态
+ this.setData({
+ loadingMore: false
+ });
+ // 如果获取失败,使用本地缓存的数据
+ this.fallbackToLocalStorage();
+ return { success: false };
+ }
+ })
+ .catch(err => {
+ console.error('获取商品列表失败:', err)
+ // 更新加载状态
+ this.setData({
+ loadingMore: false
+ });
+ // 错误处理:使用本地数据
+ this.fallbackToLocalStorage();
+ return Promise.reject(err);
+ })
+ },
+
+ // 上拉加载更多
+ onReachBottom() {
+ console.log('触发上拉加载更多,当前页码:', this.data.page, '是否有更多数据:', this.data.hasMoreData);
+
+ if (this.data.hasMoreData && !this.data.loadingMore) {
+ this.loadGoods(true).then(result => {
+ if (result && result.success) {
+ console.log('上拉加载更多成功');
+ }
+ }).catch(err => {
+ console.error('上拉加载更多失败:', err);
+ wx.showToast({
+ title: '加载失败,请重试',
+ icon: 'none',
+ duration: 1500
+ });
+ });
+ } else {
+ console.log('没有更多数据或正在加载中');
+ if (!this.data.hasMoreData) {
+ wx.showToast({
+ title: '没有更多商品了',
+ icon: 'none',
+ duration: 1500
+ });
+ }
+ }
+ },
+
+ // 预加载下一页数据 - 优化版本
+ preloadNextPage() {
+ // 当滚动到距离底部一定距离时,预加载下一页数据
+ const { hasMoreData, loadingMore } = this.data;
+ if (!hasMoreData || loadingMore) return;
+
+ console.log('预加载下一页数据');
+ // 添加延时,避免频繁触发预加载
+ setTimeout(() => {
+ // 再次检查状态,确保没有被其他操作更改
+ if (!this.data.loadingMore && this.data.hasMoreData) {
+ this.loadGoods(true);
+ }
+ }, 1000); // 增加延迟时间到1秒,减少重复加载
+ },
+
+ // 监听滚动事件,实现预加载
+ onScroll(e) {
+ const { scrollHeight, scrollTop, clientHeight } = e.detail;
+ const threshold = 800; // 增加阈值到800rpx,提前触发预加载
+
+ // 计算当前滚动位置距离底部的距离
+ const distanceToBottom = scrollHeight - scrollTop - clientHeight;
+
+ // 当距离底部小于阈值且有更多数据时,触发预加载
+ if (distanceToBottom < threshold && this.data.hasMoreData && !this.data.loadingMore) {
+ this.preloadNextPage();
+ }
+ },
+
+ // 回退到本地存储数据 - 修改为支持分页
+ fallbackToLocalStorage() {
+ const localGoods = wx.getStorageSync('goods') || [];
+ const reservedGoodsIds = wx.getStorageSync('reservedGoodsIds') || [];
+
+ const { page, pageSize } = this.data;
+
+ // ✅ 修改:对本地数据进行分页处理
+ const startIndex = (page - 1) * pageSize;
+ const endIndex = startIndex + pageSize;
+ const pagedLocalGoods = localGoods.slice(startIndex, endIndex);
+
+ console.log('本地存储回退分页信息:', {
+ 当前页码: page,
+ 每页大小: pageSize,
+ 分页后商品数量: pagedLocalGoods.length,
+ 本地总商品数量: localGoods.length
+ });
+
+ // 为本地商品添加是否已预约的标志和格式化毛重
+ const goodsWithReservedStatus = pagedLocalGoods.map(item => {
+ const selectedValue = item.selected;
+ const reservedCountValue = item.reservedCount;
+ const reservationCountValue = item.reservationCount;
+
+ const finalReservationCount = selectedValue !== undefined && selectedValue !== null ? selectedValue :
+ (reservedCountValue !== undefined && reservedCountValue !== null ? reservedCountValue :
+ (reservationCountValue || 0));
+
+ return {
+ ...item,
+ displayGrossWeight: formatGrossWeight(item.grossWeight, item.weight),
+ isReserved: reservedGoodsIds.some(id =>
+ String(id) === String(item.id) ||
+ String(id) === String(item.productId)
+ ),
+ reservedCount: finalReservationCount,
+ currentImageIndex: item.currentImageIndex || 0,
+ createdAt: item.createdAt || item.created_at || item.createTime || null
+ };
+ });
+
+ // 过滤掉hidden状态的商品
+ const filteredGoods = goodsWithReservedStatus.filter(item => {
+ const itemStatus = (item.status || '').toLowerCase();
+ return itemStatus !== 'hidden';
+ });
+
+ // ✅ 修改:判断是否还有更多本地数据
+ const hasMoreLocalData = endIndex < localGoods.length;
+
+ console.log('本地存储回退时分页商品数量:', filteredGoods.length, '本地总商品数量:', localGoods.length);
+
+ // 更新页面状态
+ this.setData({
+ goods: filteredGoods,
+ filteredGoods: filteredGoods,
+ forceUpdateTime: Date.now(),
+ // ✅ 修改:回退时也更新分页状态
+ hasMoreData: hasMoreLocalData
+ });
+ },
+
+ // 搜索输入处理
+ onSearchInput(e) {
+ const searchKeyword = e.detail.value
+ this.setData({
+ searchKeyword: searchKeyword
+ })
+
+ const { goods } = this.data
+
+ // 如果搜索词为空,重置分页并重新加载所有数据
+ if (!searchKeyword.trim()) {
+ console.log('搜索词为空,重置分页状态并重新加载数据');
+ this.setData({
+ page: 1,
+ hasMoreData: true,
+ selectedCategory: '全部'
+ }, () => {
+ // 重新加载第一页数据
+ this.loadGoods().then(() => {
+ console.log('重置搜索后数据加载完成');
+ }).catch(err => {
+ console.error('重置搜索后数据加载失败:', err);
+ this.fallbackToLocalStorageWithPagination();
+ });
+ });
+ return
+ }
+
+ // ✅ 修改:实时过滤当前已加载的商品(前端搜索)
+ // 注意:这是在前端对已加载数据进行搜索,如果要搜索全部数据需要后端支持
+ const filtered = goods.filter(item =>
+ (item.name && item.name.toLowerCase().includes(searchKeyword.toLowerCase())) ||
+ (item.spec && item.spec.toLowerCase().includes(searchKeyword.toLowerCase())) ||
+ (item.yolk && item.yolk.toLowerCase().includes(searchKeyword.toLowerCase()))
+ )
+
+ this.setData({
+ filteredGoods: filtered
+ })
+ },
+
+ // 搜索商品
+ searchGoods() {
+ const { searchKeyword, goods, totalGoods } = this.data
+
+ // 如果搜索词为空,重置分页并重新加载
+ if (!searchKeyword.trim()) {
+ console.log('搜索词为空,重置分页状态并重新加载数据');
+ this.setData({
+ page: 1,
+ hasMoreData: true,
+ selectedCategory: '全部'
+ }, () => {
+ this.loadGoods().then(() => {
+ console.log('搜索重置后数据加载完成');
+ }).catch(err => {
+ console.error('搜索重置后数据加载失败:', err);
+ this.fallbackToLocalStorageWithPagination();
+ });
+ });
+ return
+ }
+
+ // ✅ 添加:搜索范围提示
+ if (goods.length < totalGoods) {
+ wx.showToast({
+ title: `正在${goods.length}个已加载商品中搜索`,
+ icon: 'none',
+ duration: 1500
+ });
+ }
+
+ // ✅ 修改:在当前已加载商品中搜索(前端搜索)
+ const filtered = goods.filter(item =>
+ (item.name && item.name.toLowerCase().includes(searchKeyword.toLowerCase())) ||
+ (item.spec && item.spec.toLowerCase().includes(searchKeyword.toLowerCase())) ||
+ (item.yolk && item.yolk.toLowerCase().includes(searchKeyword.toLowerCase()))
+ )
+
+ this.setData({
+ filteredGoods: filtered
+ })
+ },
+
+
+ // 调试商品数据中的创建时间字段
+ debugCreatedAtFields() {
+ console.log('=== 商品数据创建时间调试 ===');
+ if (this.data.goods && this.data.goods.length > 0) {
+ const firstGoods = this.data.goods.slice(0, 3); // 只检查前3个商品
+ firstGoods.forEach((item, index) => {
+ console.log(`商品${index + 1}:`);
+ console.log(' 原始数据:', JSON.stringify(item, null, 2));
+ console.log(' createdAt:', item.createdAt);
+ console.log(' created_at:', item.created_at);
+ console.log(' createTime:', item.createTime);
+ });
+ }
+ },
+
+ // 清除本地缓存并重新加载数据
+ clearCacheAndReload() {
+ console.log('清除本地缓存并重新加载数据...');
+ wx.removeStorageSync('goods');
+ wx.removeStorageSync('reservedGoodsIds');
+
+ // ✅ 修改:重置分页状态后重新加载
+ this.setData({
+ page: 1,
+ hasMoreData: true,
+ goods: [],
+ filteredGoods: [],
+ loadingMore: false
+ }, () => {
+ this.loadGoods();
+ });
+ },
+
+ // 切换图片
+ swiperChange(e) {
+ const current = e.detail.current
+ const itemId = e.currentTarget.dataset.itemId
+
+ // 更新对应商品项的currentImageIndex
+ this.setData({
+ [`filteredGoods[${itemId}].currentImageIndex`]: current
+ })
+ },
+
+ // 预览图片
+ previewImage(e) {
+ const { urls, index } = e.currentTarget.dataset
+ this.setData({
+ showImagePreview: true,
+ previewImageUrls: urls,
+ previewImageIndex: parseInt(index)
+ })
+ },
+
+ // 预览图片
+ previewImage(e) {
+ const { urls, index } = e.currentTarget.dataset
+ this.setData({
+ showImagePreview: true,
+ previewImageUrls: urls,
+ previewImageIndex: parseInt(index)
+ })
+ },
+
+ // 关闭图片预览
+ closeImagePreview() {
+ this.setData({
+ showImagePreview: false
+ })
+ this.resetZoom()
+ },
+
+ // 重置缩放状态
+ resetZoom() {
+ this.setData({
+ scale: 1,
+ lastScale: 1,
+ offsetX: 0,
+ offsetY: 0,
+ initialTouch: null
+ })
+ },
+
+ // 处理图片点击事件(单击/双击判断)
+ handleImageTap(e) {
+ const currentTime = Date.now()
+ const lastTapTime = this.data.lastTapTime
+
+ // 判断是否为双击(300ms内连续点击)
+ if (currentTime - lastTapTime < 300) {
+ // 双击事件
+ if (this.data.doubleTapTimer) {
+ clearTimeout(this.data.doubleTapTimer)
+ }
+
+ // 切换放大/缩小状态
+ const newScale = this.data.scale === 1 ? 2 : 1
+ this.setData({
+ scale: newScale,
+ lastScale: newScale,
+ offsetX: 0,
+ offsetY: 0,
+ lastTapTime: 0 // 重置双击状态
+ })
+ } else {
+ // 单击事件,设置延迟来检测是否会成为双击
+ if (this.data.doubleTapTimer) {
+ clearTimeout(this.data.doubleTapTimer)
+ }
+
+ this.setData({
+ lastTapTime: currentTime,
+ doubleTapTimer: setTimeout(() => {
+ // 确认是单击,关闭图片预览
+ this.closeImagePreview()
+ }, 300)
+ })
+ }
+ },
+
+ // 处理触摸开始事件
+ handleTouchStart(e) {
+ const touches = e.touches
+
+ if (touches.length === 1) {
+ // 单指:准备拖动
+ this.setData({
+ initialTouch: {
+ x: touches[0].clientX,
+ y: touches[0].clientY
+ }
+ })
+ } else if (touches.length === 2) {
+ // 双指:记录起始距离,准备缩放
+ const distance = this.calculateDistance(touches[0], touches[1])
+ this.setData({
+ startDistance: distance,
+ isScaling: true,
+ lastScale: this.data.scale
+ })
+ }
+ },
+
+ // 处理触摸移动事件
+ handleTouchMove(e) {
+ const touches = e.touches
+
+ if (touches.length === 1 && this.data.initialTouch && this.data.scale !== 1) {
+ // 单指拖动(只有在缩放状态下才允许拖动)
+ const deltaX = touches[0].clientX - this.data.initialTouch.x
+ const deltaY = touches[0].clientY - this.data.initialTouch.y
+
+ // 计算新的偏移量
+ let newOffsetX = this.data.offsetX + deltaX
+ let newOffsetY = this.data.offsetY + deltaY
+
+ // 边界限制
+ const windowWidth = wx.getSystemInfoSync().windowWidth
+ const windowHeight = wx.getSystemInfoSync().windowHeight
+ const maxOffsetX = (windowWidth * (this.data.scale - 1)) / 2
+ const maxOffsetY = (windowHeight * (this.data.scale - 1)) / 2
+
+ newOffsetX = Math.max(-maxOffsetX, Math.min(maxOffsetX, newOffsetX))
+ newOffsetY = Math.max(-maxOffsetY, Math.min(maxOffsetY, newOffsetY))
+
+ this.setData({
+ offsetX: newOffsetX,
+ offsetY: newOffsetY,
+ initialTouch: {
+ x: touches[0].clientX,
+ y: touches[0].clientY
+ }
+ })
+ } else if (touches.length === 2) {
+ // 双指缩放
+ const currentDistance = this.calculateDistance(touches[0], touches[1])
+ const scale = (currentDistance / this.data.startDistance) * this.data.lastScale
+
+ // 限制缩放范围在0.5倍到3倍之间
+ const newScale = Math.max(0.5, Math.min(3, scale))
+
+ this.setData({
+ scale: newScale,
+ isScaling: true
+ })
+ }
+ },
+
+ // 处理触摸结束事件
+ handleTouchEnd(e) {
+ this.setData({
+ isScaling: false,
+ lastScale: this.data.scale,
+ initialTouch: null
+ })
+ },
+
+ // 计算两点之间的距离
+ calculateDistance(touch1, touch2) {
+ const dx = touch2.clientX - touch1.clientX
+ const dy = touch2.clientY - touch1.clientY
+ return Math.sqrt(dx * dx + dy * dy)
+ },
+
+ // 切换预览图片
+ onPreviewImageChange(e) {
+ this.setData({
+ previewImageIndex: e.detail.current
+ })
+ // 切换图片时重置缩放状态
+ this.resetZoom()
+ },
+
+ // 显示联系提示弹窗
+ showContactToast() {
+ this.setData({
+ showCustomToast: true
+ })
+
+ // 3秒后自动隐藏
+ setTimeout(() => {
+ this.setData({
+ showCustomToast: false
+ })
+ }, 800)
+ },
+
+ // 微信登录
+ doWechatLogin: function (userType) {
+ console.log('开始微信登录,用户类型:', userType);
+
+ // 显示加载提示
+ wx.showLoading({
+ title: '登录中...',
+ mask: true
+ });
+
+ // 调用微信登录接口
+ wx.login({
+ success: (res) => {
+ if (res.code) {
+ console.log('获取登录code成功:', res.code);
+ // 保存登录code到本地
+ wx.setStorageSync('loginCode', res.code);
+
+ // 获取openid和session_key
+ this.getOpenid(res.code, userType);
+ } else {
+ console.error('登录失败:', res.errMsg);
+ wx.hideLoading();
+ wx.showToast({
+ title: '登录失败,请重试',
+ icon: 'none'
+ });
+ }
+ },
+ fail: (err) => {
+ console.error('调用login接口失败:', err);
+ wx.hideLoading();
+ wx.showToast({
+ title: '网络错误,请重试',
+ icon: 'none'
+ });
+ }
+ });
+ },
+
+ // 获取openid
+ getOpenid: function (code, userType) {
+ console.log('获取openid,用户类型:', userType);
+
+ API.getOpenid(code)
+ .then(res => {
+ console.log('获取openid成功:', res);
+
+ if (res.success) {
+ // 保存openid到本地
+ wx.setStorageSync('openid', res.data.openid);
+ wx.setStorageSync('session_key', res.data.session_key);
+
+ // 验证登录状态并获取用户信息
+ this.validateLoginAndGetUserInfo(userType);
+ } else {
+ console.error('获取openid失败:', res.message);
+ wx.hideLoading();
+ wx.showToast({
+ title: '登录失败,请重试',
+ icon: 'none'
+ });
+ }
+ })
+ .catch(err => {
+ console.error('获取openid异常:', err);
+ wx.hideLoading();
+ wx.showToast({
+ title: '网络错误,请重试',
+ icon: 'none'
+ });
+ });
+ },
+
+ // 验证登录状态并获取用户信息
+ validateLoginAndGetUserInfo: function (userType) {
+ console.log('验证登录状态,用户类型:', userType);
+
+ const openid = wx.getStorageSync('openid');
+
+ if (!openid) {
+ console.error('openid不存在');
+ wx.hideLoading();
+ return;
+ }
+
+ API.getUserInfo(openid)
+ .then(res => {
+ console.log('获取用户信息结果:', res);
+ wx.hideLoading();
+ if (res.success) {
+ // 检查用户是否已存在
+ if (res.data && res.data.id) {
+ // 用户已存在,保存用户信息
+ const userInfo = {
+ userId: res.data.id,
+ openid: openid,
+ nickname: res.data.nickname || '',
+ avatarUrl: res.data.avatar || '',
+ type: res.data.type
+ };
+
+ // 保存用户信息到本地
+ wx.setStorageSync('userInfo', userInfo);
+ wx.setStorageSync('userId', res.data.id);
+
+ // 显示成功提示
+ wx.showToast({
+ title: '登录成功',
+ icon: 'success'
+ });
+
+ // 登录成功后,重新执行"我想要"操作
+ this.handleLoginSuccess();
+ } else {
+ // 用户不存在,需要获取用户信息授权
+ this.processUserInfoAuth(userType);
+ }
+ } else {
+ // 获取用户信息失败,可能是新用户
+ console.log('用户可能是新用户,开始授权流程');
+ this.processUserInfoAuth(userType);
+ }
+ })
+ .catch(err => {
+ console.error('验证登录状态异常:', err);
+ wx.hideLoading();
+ // 发生异常,尝试获取用户信息授权
+ this.processUserInfoAuth(userType);
+ });
+ },
+
+ // 处理用户信息授权
+ processUserInfoAuth: function (userType) {
+ console.log('处理用户信息授权,用户类型:', userType);
+
+ // 存储待设置的用户类型
+ this.setData({
+ pendingUserType: userType,
+ showAuthModal: true
+ });
+ },
+
+ // 处理登录成功
+ handleLoginSuccess: function () {
+ console.log('登录成功,检查是否有待执行的操作');
+
+ // 登录成功后,重新执行"我想要"操作
+ if (this.data.currentGoodsId) {
+ console.log('有未完成的操作,执行预约');
+ setTimeout(() => {
+ const goodsItem = this.findGoodsItemById(String(this.data.currentGoodsId));
+ if (goodsItem) {
+ // 重新调用onClickWant,但这次用户已登录
+ this.onClickWant({ currentTarget: { dataset: { id: this.data.currentGoodsId } } });
+ }
+ }, 500);
+ }
+ },
+
+ // 记录用户行为
+ // 显示一键登录弹窗
+ showOneKeyLogin: function () {
+ console.log('显示一键登录弹窗');
+ this.setData({
+ showAuthModal: false,
+ showOneKeyLoginModal: true
+ });
+ },
+
+ // 关闭授权弹窗
+ closeAuthModal: function () {
+ console.log('关闭授权弹窗');
+ this.setData({
+ showAuthModal: false
+ });
+ },
+
+ // 关闭一键登录弹窗
+ closeOneKeyLoginModal: function () {
+ console.log('关闭一键登录弹窗');
+ this.setData({
+ showOneKeyLoginModal: false
+ });
+ },
+
+ // 选择头像
+ onChooseAvatar: function (e) {
+ console.log('选择头像:', e);
+ const { avatarUrl } = e.detail;
+ this.setData({
+ avatarUrl
+ });
+ },
+
+ // 获取用户名
+ getUserName: function (e) {
+ console.log('获取用户名:', e);
+ const { nickname } = e.detail.value;
+
+ if (!nickname || nickname.trim() === '') {
+ wx.showToast({
+ title: '昵称不能为空',
+ icon: 'none'
+ });
+ return;
+ }
+
+ const userInfo = {
+ nickname: nickname.trim(),
+ avatarUrl: this.data.avatarUrl
+ };
+
+ this.saveUserInfo(userInfo, this.data.pendingUserType);
+ },
+
+ // 取消用户信息表单
+ cancelUserInfoForm: function () {
+ console.log('取消用户信息表单');
+ this.setData({
+ showUserInfoForm: false
+ });
+ },
+
+ // 显示商品详情
+ showGoodsDetail: function (e) {
+ // 检查用户是否登录
+ const openid = wx.getStorageSync('openid');
+ const userId = wx.getStorageSync('userId');
+
+ if (!openid || !userId) {
+ console.log('用户未登录,显示登录提示和弹窗');
+ // 提示登录后才可查看详情
+ wx.showToast({
+ title: '登录后才可查看详情',
+ icon: 'none',
+ duration: 1500
+ });
+ // 显示登录弹窗
+ setTimeout(() => {
+ this.showOneKeyLogin();
+ });
+ return;
+ }
+
+ const goodsItem = e.currentTarget.dataset.item;
+ this.setData({
+ currentGoodsDetail: goodsItem,
+ showGoodsDetail: true
+ });
+
+ // 隐藏底部导航栏 - 通过更新全局数据
+ const app = getApp();
+ if (app && app.globalData) {
+ app.globalData.showTabBar = false;
+ }
+
+ // 同时尝试直接更新tabBar的选中状态
+ if (typeof this.getTabBar === 'function' && this.getTabBar()) {
+ const tabBar = this.getTabBar();
+ if (tabBar.setData) {
+ tabBar.setData({ show: false });
+ }
+ }
+
+ // 调用后端API执行商品联系人更新
+ console.log('开始调用API.updateProductContacts()');
+ API.updateProductContacts().then(function(res) {
+ console.log('商品联系人更新成功:', res);
+ }).catch(function(err) {
+ console.error('商品联系人更新失败:', err);
+ }
+ );
+ },
+
+ // 关闭商品详情
+ closeGoodsDetail: function () {
+ this.setData({
+ showGoodsDetail: false,
+ currentGoodsDetail: {}
+ });
+
+ // 显示底部导航栏 - 通过更新全局数据
+ const app = getApp();
+ if (app && app.globalData) {
+ app.globalData.showTabBar = true;
+ }
+
+ // 同时尝试直接更新tabBar的选中状态
+ if (typeof this.getTabBar === 'function' && this.getTabBar()) {
+ const tabBar = this.getTabBar();
+ if (tabBar.setData) {
+ tabBar.setData({ show: true });
+ }
+ }
+ },
+
+ // 在详情弹窗中点击"我想要"按钮
+ onClickWantInDetail: function (e) {
+ const goodsId = e.currentTarget.dataset.id;
+ // 先关闭详情弹窗
+ this.closeGoodsDetail();
+ // 然后调用原来的"我想要"方法
+ this.onClickWant({ currentTarget: { dataset: { id: goodsId } } });
+ },
+
+ // 获取手机号并登录
+ onGetPhoneNumber: function (e) {
+ console.log('获取手机号:', e);
+
+ if (e.detail.errMsg !== 'getPhoneNumber:ok') {
+ console.log('用户拒绝授权手机号');
+ this.setData({
+ showOneKeyLoginModal: false
+ });
+ return;
+ }
+
+ const encryptedData = e.detail.encryptedData;
+ const iv = e.detail.iv;
+
+ // 调用API进行登录
+ API.login(encryptedData, iv)
+ .then(res => {
+ console.log('登录成功:', res);
+
+ if (res.success) {
+ // 保存登录信息
+ wx.setStorageSync('openid', res.data.openid);
+ wx.setStorageSync('userId', res.data.userId);
+ wx.setStorageSync('sessionKey', res.data.sessionKey || '');
+
+ // 登录成功后立即获取用户微信名称
+ wx.getUserProfile({
+ desc: '用于完善会员资料',
+ success: (userProfile) => {
+ console.log('获取用户信息成功:', userProfile);
+
+ // 构建用户信息
+ const userInfo = {
+ openid: res.data.openid,
+ userId: res.data.userId,
+ nickname: userProfile.userInfo.nickName,
+ avatarUrl: userProfile.userInfo.avatarUrl,
+ type: this.data.pendingUserType
+ };
+
+ // 保存用户信息到本地存储
+ wx.setStorageSync('userInfo', userInfo);
+
+ // 上传用户信息到服务器
+ API.uploadUserInfo(userInfo)
+ .then(uploadRes => {
+ console.log('用户信息上传成功:', uploadRes);
+
+ // 关闭登录弹窗
+ this.setData({
+ showOneKeyLoginModal: false
+ });
+
+ // 登录成功后,重新执行"我想要"操作
+ this.handleLoginSuccess();
+ })
+ .catch(uploadErr => {
+ console.error('用户信息上传失败:', uploadErr);
+
+ // 即使上传失败,也关闭登录弹窗
+ this.setData({
+ showOneKeyLoginModal: false
+ });
+
+ // 登录成功后,重新执行"我想要"操作
+ this.handleLoginSuccess();
+ });
+ },
+ fail: (profileErr) => {
+ console.error('获取用户信息失败:', profileErr);
+
+ // 即使获取用户信息失败,也构建基本用户信息对象
+ const userInfo = {
+ openid: res.data.openid,
+ userId: res.data.userId,
+ nickname: '微信用户',
+ avatarUrl: '/images/default-avatar.png',
+ type: this.data.pendingUserType
+ };
+
+ // 保存用户信息到本地存储
+ wx.setStorageSync('userInfo', userInfo);
+
+ // 关闭登录弹窗
+ this.setData({
+ showOneKeyLoginModal: false
+ });
+
+ // 登录成功后,重新执行"我想要"操作
+ this.handleLoginSuccess();
+ }
+ });
+ } else {
+ wx.showToast({
+ title: '登录失败,请重试',
+ icon: 'none'
+ });
+ this.setData({
+ showOneKeyLoginModal: false
+ });
+ }
+ })
+ .catch(err => {
+ console.error('登录失败:', err);
+ wx.showToast({
+ title: '网络错误,请重试',
+ icon: 'none'
+ });
+ this.setData({
+ showOneKeyLoginModal: false
+ });
+ });
+ },
+
+ // 保存用户信息
+ saveUserInfo: function (userInfo, type) {
+ console.log('保存用户信息:', userInfo, '类型:', type);
+
+ const openid = wx.getStorageSync('openid');
+ const userId = wx.getStorageSync('userId');
+
+ if (!openid || !userId) {
+ wx.showToast({
+ title: '登录信息已过期,请重新登录',
+ icon: 'none'
+ });
+ return;
+ }
+
+ userInfo.userId = userId;
+ userInfo.openid = openid;
+ userInfo.type = type;
+
+ // 保存到本地存储
+ wx.setStorageSync('userInfo', userInfo);
+
+ // 上传到服务器
+ this.uploadUserInfoToServer(userInfo, userId, type);
+ },
+
+ // 上传用户信息到服务器
+ uploadUserInfoToServer: function (userInfo, userId, type) {
+ console.log('上传用户信息到服务器:', userInfo);
+
+ API.saveUserInfo(userInfo, type)
+ .then(res => {
+ console.log('上传用户信息成功:', res);
+
+ this.setData({
+ showUserInfoForm: false
+ });
+
+ // 登录成功后,重新执行"我想要"操作
+ if (this.data.currentGoodsId) {
+ // 模拟点击"我想要"按钮,使用新的商品ID
+ const goodsItem = this.findGoodsItemById(String(this.data.currentGoodsId));
+ if (goodsItem) {
+ // 重新调用onClickWant,但这次用户已登录
+ this.onClickWant({ currentTarget: { dataset: { id: this.data.currentGoodsId } } });
+ }
+ }
+ })
+ .catch(err => {
+ console.error('上传用户信息失败:', err);
+
+ // 即使上传失败,也标记为已登录
+ this.setData({
+ showUserInfoForm: false
+ });
+
+ // 尝试执行"我想要"操作
+ if (this.data.currentGoodsId) {
+ const goodsItem = this.findGoodsItemById(String(this.data.currentGoodsId));
+ if (goodsItem) {
+ // 重新调用onClickWant,但这次用户已登录
+ this.onClickWant({ currentTarget: { dataset: { id: this.data.currentGoodsId } } });
+ }
+ }
+ });
+ },
+
+ recordBehavior(behaviorType, targetType, targetId) {
+ try {
+ console.log(`记录行为: ${behaviorType}, ${targetType}, ${targetId || '无ID'}`)
+
+ // 可以在这里添加更复杂的行为记录逻辑,如发送到服务器等
+ } catch (error) {
+ console.error('记录行为失败:', error)
+ }
+ },
+
+ // 格式化时间为北京时间(UTC+8)并转换为 年-月-日-时:分 格式
+ formatTimeToBeijing: function (timeValue) {
+ if (!timeValue) {
+ return '未知';
+ }
+
+ try {
+ // 创建Date对象
+ const date = new Date(timeValue);
+
+ // 检查日期是否有效
+ if (isNaN(date.getTime())) {
+ return '未知';
+ }
+
+ // 使用Date对象的方法直接获取UTC时间,然后加8小时计算北京时间
+ const utcYear = date.getUTCFullYear();
+ const utcMonth = date.getUTCMonth();
+ const utcDate = date.getUTCDate();
+ const utcHours = date.getUTCHours() + 8; // 直接加8小时
+
+ // 创建北京时间Date对象
+ const beijingTime = new Date(Date.UTC(utcYear, utcMonth, utcDate, utcHours, date.getUTCMinutes()));
+
+ // 格式化时间,使用连字符分隔
+ const year = beijingTime.getFullYear();
+ const month = (beijingTime.getMonth() + 1).toString().padStart(2, '0');
+ const day = beijingTime.getDate().toString().padStart(2, '0');
+ const hours = beijingTime.getHours().toString().padStart(2, '0');
+ const minutes = beijingTime.getMinutes().toString().padStart(2, '0');
+
+ // 返回格式:年-月-日-时:分
+ return `${year}-${month}-${day}-${hours}:${minutes}`;
+ } catch (error) {
+ console.error('北京时间格式化错误:', error);
+ return '未知';
+ }
+ },
+
+ // 拨打电话功能
+ makePhoneCall(e) {
+ const phoneNumber = e.currentTarget.dataset.phone;
+ if (phoneNumber) {
+ wx.showModal({
+ title: '联系人电话',
+ content: phoneNumber,
+ showCancel: true,
+ cancelText: '取消',
+ confirmText: '拨打',
+ success: (res) => {
+ if (res.confirm) {
+ wx.makePhoneCall({
+ phoneNumber: phoneNumber,
+ success: () => {
+ console.log('拨打电话成功');
+ },
+ fail: (err) => {
+ console.error('拨打电话失败', err);
+ wx.showToast({
+ title: '拨打电话失败',
+ icon: 'none'
+ });
+ }
+ });
+ }
+ }
+ });
+ }
+ }
+});
\ No newline at end of file
diff --git a/pages/buyer/index.json b/pages/buyer/index.json
new file mode 100644
index 0000000..7ef5329
--- /dev/null
+++ b/pages/buyer/index.json
@@ -0,0 +1,5 @@
+{
+ "usingComponents": {},
+ "enablePullDownRefresh": true,
+ "backgroundTextStyle": "dark"
+}
\ No newline at end of file
diff --git a/pages/buyer/index.wxml b/pages/buyer/index.wxml
new file mode 100644
index 0000000..ed8904d
--- /dev/null
+++ b/pages/buyer/index.wxml
@@ -0,0 +1,296 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 暂无图片
+
+
+
+
+
+
+
+
+
+
+
+
+ {{(item.currentImageIndex || 0) + 1}}/{{item.imageUrls.length}}
+
+
+
+
+
+
+
+
+ {{item.name}}
+ 已上架
+
+ 规格: {{item.spec || '无'}}
+ 蛋黄: {{item.yolk || '无'}}
+ 件数: {{item.minOrder}}件
+ 斤重: {{item.displayGrossWeight}}
+ 地区: {{item.region}}
+
+
+
+ 已有{{item.reservedCount || 0}}人想要
+
+
+
+
+
+
+
+ 已预约✓
+
+
+
+
+
+
+
+
+
+
+
+
+ 稍后会有专员和您沟通
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+
+ 提示
+
+
+ 请先登录后再预约商品
+
+
+
+
+
+
+
+
+
+
+
+
+ 授权登录
+
+
+ 请授权获取您的手机号用于登录
+
+
+
+
+
+
+
+
+
+
+
+
+ 完善个人信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{currentGoodsDetail.name}}
+ 价格: {{currentGoodsDetail.price || '暂无'}}
+
+
+
+
+ 地区
+ {{currentGoodsDetail.region}}
+
+
+ 规格
+ {{currentGoodsDetail.spec || '无'}}
+
+
+ 蛋黄
+ {{currentGoodsDetail.yolk || '无'}}
+
+
+ 斤重
+ {{currentGoodsDetail.displayGrossWeight}}
+
+
+ 件数
+ {{currentGoodsDetail.minOrder}}件
+
+
+ 关注人数
+ {{currentGoodsDetail.reservedCount || 0}}人
+
+
+
+
+
+ 联系信息
+
+ 👤
+ 联系人: {{currentGoodsDetail.product_contact || '暂无'}}
+
+
+ 📞
+ 联系电话: {{currentGoodsDetail.contact_phone || '暂无'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/buyer/index.wxss b/pages/buyer/index.wxss
new file mode 100644
index 0000000..c78f4ce
--- /dev/null
+++ b/pages/buyer/index.wxss
@@ -0,0 +1,464 @@
+/* pages/buyer/index.wxss */
+.container {
+ min-height: 100vh;
+ background-color: #f5f5f5;
+}
+
+.title {
+ font-size: 36rpx;
+ font-weight: bold;
+ color: #333;
+ margin-bottom: 20rpx;
+ width: 100%;
+ text-align: center;
+}
+
+.card {
+ background: white;
+ border-radius: 12rpx;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
+ overflow: hidden;
+ margin-bottom: 20rpx;
+}
+
+.image-swiper {
+ width: 100%;
+ height: 100%;
+}
+
+/* 弹窗样式 */
+.modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.5);
+ display: flex;
+ justify-content: center;
+ align-items: flex-end;
+ z-index: 9999;
+ overflow: hidden;
+}
+
+.modal-container {
+ background: white;
+ padding: 40rpx;
+ border-radius: 16rpx;
+ width: 80%;
+ max-width: 500rpx;
+ text-align: center;
+ box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.1);
+}
+
+.modal-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ margin-bottom: 30rpx;
+ color: #333;
+}
+
+.modal-content {
+ font-size: 28rpx;
+ color: #666;
+ margin-bottom: 40rpx;
+ line-height: 1.5;
+}
+
+.modal-buttons {
+ text-align: center;
+}
+
+/* 商品详情弹窗 - 商务风格 */
+.goods-detail-modal {
+ background: white;
+ padding: 0;
+ border-radius: 20rpx 20rpx 0 0;
+ width: 100%;
+ height: 100vh; /* 改为全屏高度 */
+ max-height: 100vh; /* 确保不超过屏幕高度 */
+ overflow: hidden;
+ box-shadow: 0 -8rpx 40rpx rgba(0, 0, 0, 0.15);
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 0; /* 导航栏已隐藏,无需间距 */
+ z-index: 9999;
+ position: absolute; /* 确保弹窗位于遮罩层内 */
+ top: 0;
+ left: 0;
+}
+
+.goods-detail-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 32rpx 40rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+ background-color: white;
+ position: sticky;
+ top: 0;
+ z-index: 10000;
+}
+
+.goods-detail-title {
+ font-size: 36rpx;
+ font-weight: 600;
+ color: #2c3e50;
+ margin: 0;
+}
+
+.goods-detail-close {
+ font-size: 44rpx;
+ color: #909399;
+ cursor: pointer;
+ transition: color 0.3s;
+ position: sticky;
+ top: 32rpx;
+ z-index: 10001;
+}
+
+.goods-detail-close:hover {
+ color: #606266;
+}
+
+.goods-detail-content {
+ padding: 40rpx;
+ overflow-y: auto;
+ flex: 1;
+ height: calc(100vh - 120rpx); /* 减去头部高度,实现全屏滚动 */
+ -webkit-overflow-scrolling: touch; /* 优化iOS滚动体验 */
+ width: 100%; /* 确保宽度100% */
+ box-sizing: border-box; /* 确保padding不影响宽度计算 */
+}
+
+.goods-image-section {
+ margin-bottom: 40rpx;
+ border-radius: 12rpx;
+ overflow: hidden;
+ background-color: #fafafa;
+}
+
+.goods-image-swiper {
+ width: 100%;
+ height: 440rpx;
+}
+
+.goods-image-item {
+ width: 100%;
+ height: 100%;
+}
+
+.goods-image {
+ width: 100%;
+ height: 100%;
+ display: block;
+}
+
+.goods-info-section {
+ text-align: left;
+}
+
+.goods-name {
+ font-size: 36rpx;
+ font-weight: 600;
+ color: #2c3e50;
+ margin-bottom: 20rpx;
+ line-height: 1.4;
+}
+
+.goods-price {
+ font-size: 42rpx;
+ font-weight: 700;
+ color: #e64340;
+ margin-bottom: 32rpx;
+}
+
+.goods-info-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 24rpx;
+ margin-bottom: 40rpx;
+ padding: 24rpx;
+ background-color: #f8f9fa;
+ border-radius: 12rpx;
+}
+
+.goods-info-item {
+ display: flex;
+ flex-direction: column;
+}
+
+.goods-info-label {
+ font-size: 24rpx;
+ color: #909399;
+ margin-bottom: 8rpx;
+}
+
+.goods-info-value {
+ font-size: 28rpx;
+ color: #2c3e50;
+ font-weight: 500;
+}
+
+.goods-contact-section {
+ text-align: left;
+ padding: 24rpx;
+ background-color: #e8f4fd;
+ border-radius: 12rpx;
+ margin-bottom: 40rpx;
+ border-left: 8rpx solid #1677ff;
+}
+
+.goods-contact-title {
+ font-size: 30rpx;
+ font-weight: 600;
+ color: #2c3e50;
+ margin-bottom: 20rpx;
+}
+
+.goods-contact-item {
+ display: flex;
+ align-items: center;
+ margin-bottom: 16rpx;
+ font-size: 28rpx;
+ color: #2c3e50;
+}
+
+.goods-contact-item:last-child {
+ margin-bottom: 0;
+ justify-content: space-between;
+}
+
+.goods-contact-icon {
+ margin-right: 16rpx;
+ color: #1677ff;
+}
+
+.call-phone-button {
+ background-color: white;
+ color: black;
+ font-size: 24rpx;
+ width: 120rpx;
+ height: 60rpx;
+ line-height: 60rpx;
+ padding: 0;
+ border-radius: 20rpx;
+ border: 1rpx solid #d9d9d9;
+ transition: all 0.3s;
+ white-space: nowrap;
+ text-align: center;
+}
+
+.call-phone-button:hover {
+ background-color: #f5f5f5;
+ transform: translateY(-1rpx);
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
+}
+
+.call-phone-button:active {
+ transform: translateY(0);
+}
+
+.goods-action-section {
+ padding: 32rpx 40rpx;
+ border-top: 1rpx solid #f0f0f0;
+}
+
+.goods-action-button {
+ width: 100%;
+ height: 96rpx;
+ line-height: 96rpx;
+ font-size: 32rpx;
+ font-weight: 600;
+ border-radius: 12rpx;
+ transition: all 0.3s;
+ border: none;
+ background-color: #1677ff;
+ color: white;
+}
+
+.goods-action-button:hover {
+ background-color: #4096ff;
+ transform: translateY(-2rpx);
+ box-shadow: 0 4rpx 12rpx rgba(22, 119, 255, 0.3);
+}
+
+.goods-action-button:active {
+ transform: translateY(0);
+}
+
+.goods-action-button.reserved {
+ background-color: #52c41a;
+}
+
+.goods-action-button.reserved:hover {
+ background-color: #73d13d;
+}
+
+/* 响应式设计 */
+@media (max-width: 750rpx) {
+ .goods-detail-modal {
+ width: 96%;
+ }
+
+ .goods-detail-content {
+ padding: 32rpx;
+ }
+
+ .goods-info-grid {
+ grid-template-columns: 1fr;
+ gap: 16rpx;
+ }
+}
+
+.primary-button {
+ background-color: #1677ff;
+ color: white;
+ font-size: 28rpx;
+ line-height: 80rpx;
+ border-radius: 8rpx;
+ margin-bottom: 20rpx;
+ border: none;
+ width: 100%;
+}
+
+.cancel-button {
+ background-color: #f5f5f5;
+ color: #333;
+ font-size: 28rpx;
+ line-height: 80rpx;
+ border-radius: 8rpx;
+ border: none;
+ width: 100%;
+}
+
+/* 头像选择样式 */
+.avatar-section {
+ margin-bottom: 30rpx;
+}
+
+.avatar-wrapper {
+ width: 120rpx;
+ height: 120rpx;
+ border-radius: 50%;
+ background: none;
+ padding: 0;
+ margin: 0 auto;
+ border: none;
+}
+
+.avatar {
+ width: 120rpx;
+ height: 120rpx;
+ border-radius: 50%;
+}
+
+/* 表单样式 */
+.form-group {
+ margin-bottom: 30rpx;
+}
+
+.form-input {
+ width: 100%;
+ padding: 20rpx;
+ border: 1rpx solid #ddd;
+ border-radius: 8rpx;
+ box-sizing: border-box;
+ font-size: 28rpx;
+}
+
+.form-actions {
+ text-align: center;
+ margin-bottom: 20rpx;
+}
+
+.confirm-button {
+ background-color: #1677ff;
+ color: white;
+ font-size: 28rpx;
+ line-height: 80rpx;
+ border-radius: 8rpx;
+ border: none;
+ width: 100%;
+}
+
+/* 自定义弹窗样式 */
+.custom-toast-mask {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.4);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 9999;
+}
+
+.custom-toast {
+ background: white;
+ padding: 40rpx 60rpx;
+ border-radius: 12rpx;
+ text-align: center;
+ transform-origin: center center;
+}
+
+/* 图片预览样式 */
+.image-preview-mask {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.9);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 9999;
+}
+
+/* 按钮样式优化 */
+button {
+ border: none;
+ outline: none;
+}
+
+button:after {
+ border: none;
+}
+
+/* 加载状态样式 */
+.loading-more {
+ padding: 20rpx 0;
+ text-align: center;
+ font-size: 26rpx;
+ color: #999;
+}
+
+.no-more-data {
+ padding: 20rpx 0;
+ text-align: center;
+ font-size: 26rpx;
+ color: #999;
+}
+
+/* 搜索无结果样式 */
+.no-results {
+ text-align: center;
+ color: #999;
+ margin-top: 50rpx;
+ font-size: 28rpx;
+}
+
+/* 响应式设计 */
+@media (max-width: 750rpx) {
+ .modal-container {
+ width: 90%;
+ padding: 30rpx;
+ }
+
+ .card {
+ margin-bottom: 16rpx;
+ }
+}
\ No newline at end of file
diff --git a/pages/debug/debug-gross-weight.js b/pages/debug/debug-gross-weight.js
new file mode 100644
index 0000000..2a95530
--- /dev/null
+++ b/pages/debug/debug-gross-weight.js
@@ -0,0 +1,66 @@
+// pages/debug/debug-gross-weight.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/debug/debug-gross-weight.wxml b/pages/debug/debug-gross-weight.wxml
new file mode 100644
index 0000000..f31170d
--- /dev/null
+++ b/pages/debug/debug-gross-weight.wxml
@@ -0,0 +1,2 @@
+
+pages/debug/debug-gross-weight.wxml
\ No newline at end of file
diff --git a/pages/debug/debug-sold-out.js b/pages/debug/debug-sold-out.js
new file mode 100644
index 0000000..5083a91
--- /dev/null
+++ b/pages/debug/debug-sold-out.js
@@ -0,0 +1,66 @@
+// pages/debug/debug-sold-out.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/debug/debug-sold-out.wxml b/pages/debug/debug-sold-out.wxml
new file mode 100644
index 0000000..277f9d6
--- /dev/null
+++ b/pages/debug/debug-sold-out.wxml
@@ -0,0 +1,2 @@
+
+pages/debug/debug-sold-out.wxml
\ No newline at end of file
diff --git a/pages/debug/debug.js b/pages/debug/debug.js
new file mode 100644
index 0000000..32b4017
--- /dev/null
+++ b/pages/debug/debug.js
@@ -0,0 +1,66 @@
+// pages/debug/debug.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/debug/debug.wxml b/pages/debug/debug.wxml
new file mode 100644
index 0000000..f32be20
--- /dev/null
+++ b/pages/debug/debug.wxml
@@ -0,0 +1,2 @@
+
+pages/debug/debug.wxml
\ No newline at end of file
diff --git a/pages/evaluate/index.js b/pages/evaluate/index.js
new file mode 100644
index 0000000..67dda1e
--- /dev/null
+++ b/pages/evaluate/index.js
@@ -0,0 +1,557 @@
+// pages/evaluate/index.js
+//估价暂未开放
+Page({
+ data: {
+ evaluateStep: 1,
+ fromPreviousStep: false, // 用于标记是否从下一步返回
+ evaluateData: {
+ region: '',
+ type: '',
+ brand: '',
+ model: '',
+ freshness: '',
+ size: '',
+ packaging: '',
+ spec: ''
+ },
+ // 客户地区列表
+ regions: ['北京', '上海', '广州', '深圳', '杭州', '成都', '武汉', '西安', '南京', '重庆'],
+ evaluateResult: {
+ finalPrice: '0',
+ totalPrice: '0'
+ },
+
+ // 鸡蛋类型数据(包含成交单量)
+ eggTypes: [
+ { name: '土鸡蛋', dailyOrders: 1258, desc: '散养鸡产出的优质鸡蛋' },
+ { name: '洋鸡蛋', dailyOrders: 3421, desc: '规模化养殖的普通鸡蛋' },
+ { name: '乌鸡蛋', dailyOrders: 892, desc: '乌鸡产出的特色鸡蛋' },
+ { name: '有机鸡蛋', dailyOrders: 675, desc: '有机认证的高品质鸡蛋' },
+ { name: '初生蛋', dailyOrders: 965, desc: '母鸡产的第一窝鸡蛋' }
+ ],
+
+ // 鸡蛋品牌和型号数据(包含成交单量)
+ eggData: {
+ '土鸡蛋': {
+ brands: [
+ { name: '农家乐', dailyOrders: 456 },
+ { name: '山野', dailyOrders: 389 },
+ { name: '生态园', dailyOrders: 243 },
+ { name: '田园', dailyOrders: 170 }
+ ],
+ models: {
+ '农家乐': [
+ { name: '散养土鸡蛋', dailyOrders: 213 },
+ { name: '林下土鸡蛋', dailyOrders: 132 },
+ { name: '谷物喂养土鸡蛋', dailyOrders: 78 },
+ { name: '农家土鸡蛋', dailyOrders: 33 }
+ ],
+ '山野': [
+ { name: '高山散养土鸡蛋', dailyOrders: 189 },
+ { name: '林间土鸡蛋', dailyOrders: 124 },
+ { name: '野生土鸡蛋', dailyOrders: 76 }
+ ],
+ '生态园': [
+ { name: '有机土鸡蛋', dailyOrders: 112 },
+ { name: '无抗土鸡蛋', dailyOrders: 89 },
+ { name: '生态土鸡蛋', dailyOrders: 42 }
+ ],
+ '田园': [
+ { name: '农家土鸡蛋', dailyOrders: 87 },
+ { name: '走地鸡蛋', dailyOrders: 54 },
+ { name: '自然放养土鸡蛋', dailyOrders: 29 }
+ ]
+ }
+ },
+ '洋鸡蛋': {
+ brands: [
+ { name: '德青源', dailyOrders: 1234 },
+ { name: '圣迪乐村', dailyOrders: 987 },
+ { name: '正大', dailyOrders: 765 },
+ { name: '咯咯哒', dailyOrders: 435 }
+ ],
+ models: {
+ '德青源': [
+ { name: '安心鲜鸡蛋', dailyOrders: 543 },
+ { name: '谷物鸡蛋', dailyOrders: 456 },
+ { name: '营养鸡蛋', dailyOrders: 235 }
+ ],
+ '圣迪乐村': [
+ { name: '高品质鲜鸡蛋', dailyOrders: 432 },
+ { name: '谷物鸡蛋', dailyOrders: 321 },
+ { name: '生态鸡蛋', dailyOrders: 234 }
+ ],
+ '正大': [
+ { name: '鲜鸡蛋', dailyOrders: 345 },
+ { name: '营养鸡蛋', dailyOrders: 243 },
+ { name: '优选鸡蛋', dailyOrders: 177 }
+ ],
+ '咯咯哒': [
+ { name: '鲜鸡蛋', dailyOrders: 213 },
+ { name: '谷物鸡蛋', dailyOrders: 145 },
+ { name: '农家鸡蛋', dailyOrders: 77 }
+ ]
+ }
+ },
+ '乌鸡蛋': {
+ brands: [
+ { name: '山野', dailyOrders: 345 },
+ { name: '生态园', dailyOrders: 289 },
+ { name: '农家乐', dailyOrders: 258 }
+ ],
+ models: {
+ '山野': [
+ { name: '散养乌鸡蛋', dailyOrders: 156 },
+ { name: '林下乌鸡蛋', dailyOrders: 102 },
+ { name: '野生乌鸡蛋', dailyOrders: 87 }
+ ],
+ '生态园': [
+ { name: '有机乌鸡蛋', dailyOrders: 123 },
+ { name: '无抗乌鸡蛋', dailyOrders: 98 },
+ { name: '生态乌鸡蛋', dailyOrders: 68 }
+ ],
+ '农家乐': [
+ { name: '农家乌鸡蛋', dailyOrders: 112 },
+ { name: '谷物乌鸡蛋', dailyOrders: 93 },
+ { name: '散养乌鸡蛋', dailyOrders: 53 }
+ ]
+ }
+ },
+ '有机鸡蛋': {
+ brands: [
+ { name: '生态园', dailyOrders: 289 },
+ { name: '山野', dailyOrders: 213 },
+ { name: '田园', dailyOrders: 173 }
+ ],
+ models: {
+ '生态园': [
+ { name: '有机认证鸡蛋', dailyOrders: 132 },
+ { name: '无抗有机鸡蛋', dailyOrders: 98 },
+ { name: '生态有机鸡蛋', dailyOrders: 59 }
+ ],
+ '山野': [
+ { name: '有机散养鸡蛋', dailyOrders: 98 },
+ { name: '有机谷物鸡蛋', dailyOrders: 76 },
+ { name: '野生有机鸡蛋', dailyOrders: 39 }
+ ],
+ '田园': [
+ { name: '有机农家鸡蛋', dailyOrders: 89 },
+ { name: '有机初生蛋', dailyOrders: 54 },
+ { name: '自然有机鸡蛋', dailyOrders: 30 }
+ ]
+ }
+ },
+ '初生蛋': {
+ brands: [
+ { name: '农家乐', dailyOrders: 342 },
+ { name: '山野', dailyOrders: 312 },
+ { name: '生态园', dailyOrders: 311 }
+ ],
+ models: {
+ '农家乐': [
+ { name: '土鸡初生蛋', dailyOrders: 156 },
+ { name: '散养初生蛋', dailyOrders: 112 },
+ { name: '农家初生蛋', dailyOrders: 74 }
+ ],
+ '山野': [
+ { name: '高山初生蛋', dailyOrders: 145 },
+ { name: '林下初生蛋', dailyOrders: 98 },
+ { name: '野生初生蛋', dailyOrders: 69 }
+ ],
+ '生态园': [
+ { name: '有机初生蛋', dailyOrders: 134 },
+ { name: '无抗初生蛋', dailyOrders: 102 },
+ { name: '生态初生蛋', dailyOrders: 75 }
+ ]
+ }
+ }
+ },
+
+ eggBrands: [],
+ eggModels: []
+ },
+
+ onLoad() {
+ console.log('估价页面初始化')
+ // 页面加载时,对鸡蛋类型按成交单量降序排序并添加排名
+ const sortedTypes = [...this.data.eggTypes].sort((a, b) => b.dailyOrders - a.dailyOrders);
+ // 添加排名属性
+ const typesWithRank = sortedTypes.map((type, index) => ({
+ ...type,
+ rank: index + 1
+ }));
+ this.setData({
+ eggTypes: typesWithRank,
+ fromPreviousStep: false // 初始化标志
+ });
+ },
+
+ // 选择客户地区
+ selectRegion(e) {
+ const region = e.currentTarget.dataset.region;
+ this.setData({
+ 'evaluateData.region': region
+ });
+
+ // 只有当当前步骤是1且已经从下一步返回时,才自动进入下一步
+ if (this.data.evaluateStep === 1 && !this.data.fromPreviousStep) {
+ this.setData({
+ evaluateStep: 2
+ });
+ }
+
+ // 重置标志
+ this.setData({
+ fromPreviousStep: false
+ });
+ },
+
+ // 选择鸡蛋类型
+ selectEggType(e) {
+ const type = e.currentTarget.dataset.type;
+ // 获取该类型下的品牌,并按成交单量降序排序
+ const brands = [...this.data.eggData[type].brands].sort((a, b) => b.dailyOrders - a.dailyOrders);
+ // 添加排名属性
+ const brandsWithRank = brands.map((brand, index) => ({
+ ...brand,
+ rank: index + 1
+ }));
+
+ this.setData({
+ 'evaluateData.type': type,
+ eggBrands: brandsWithRank,
+ // 清除之前选择的品牌和型号
+ 'evaluateData.brand': '',
+ 'evaluateData.model': '',
+ eggModels: []
+ });
+
+ // 只有当当前步骤是2且已经从下一步返回时,才自动进入下一步
+ if (this.data.evaluateStep === 2 && !this.data.fromPreviousStep) {
+ this.setData({
+ evaluateStep: 3
+ });
+ }
+
+ // 重置标志
+ this.setData({
+ fromPreviousStep: false
+ });
+ },
+
+ // 选择鸡蛋品牌
+ selectEggBrand(e) {
+ const brand = e.currentTarget.dataset.brand;
+ const type = this.data.evaluateData.type;
+ // 获取该品牌下的型号,并按成交单量降序排序
+ const models = [...this.data.eggData[type].models[brand]].sort((a, b) => b.dailyOrders - a.dailyOrders);
+ // 添加排名属性
+ const modelsWithRank = models.map((model, index) => ({
+ ...model,
+ rank: index + 1
+ }));
+
+ this.setData({
+ 'evaluateData.brand': brand,
+ eggModels: modelsWithRank,
+ // 清除之前选择的型号
+ 'evaluateData.model': ''
+ });
+
+ // 只有当当前步骤是3且已经从下一步返回时,才自动进入下一步
+ if (this.data.evaluateStep === 3 && !this.data.fromPreviousStep) {
+ this.setData({
+ evaluateStep: 4
+ });
+ }
+
+ // 重置标志
+ this.setData({
+ fromPreviousStep: false
+ });
+ },
+
+ // 选择鸡蛋型号
+ selectEggModel(e) {
+ const model = e.currentTarget.dataset.model;
+ this.setData({
+ 'evaluateData.model': model
+ });
+
+ // 只有当当前步骤是4且已经从下一步返回时,才自动进入下一步
+ if (this.data.evaluateStep === 4 && !this.data.fromPreviousStep) {
+ this.setData({
+ evaluateStep: 5
+ });
+ }
+
+ // 重置标志
+ this.setData({
+ fromPreviousStep: false
+ });
+ },
+
+ // 格式化订单数量显示
+ formatOrderCount(count) {
+ if (count >= 10000) {
+ return (count / 10000).toFixed(1) + '万';
+ } else if (count >= 1000) {
+ return (count / 1000).toFixed(1) + 'k';
+ }
+ return count.toString();
+ },
+
+ // 选择条件
+ selectCondition(e) {
+ const { type, value } = e.currentTarget.dataset;
+ this.setData({
+ [`evaluateData.${type}`]: value
+ });
+
+ // 只有当当前步骤不是从返回过来的,才自动进入下一步
+ if (!this.data.fromPreviousStep) {
+ // 根据当前步骤自动进入下一步
+ const currentStep = this.data.evaluateStep;
+ if (currentStep === 5) {
+ this.setData({ evaluateStep: 6 });
+ } else if (currentStep === 6) {
+ this.setData({ evaluateStep: 7 });
+ } else if (currentStep === 7) {
+ this.setData({ evaluateStep: 8 });
+ }
+ }
+
+ // 重置标志
+ this.setData({
+ fromPreviousStep: false
+ });
+ },
+
+ // 选择规格
+ selectSpec(e) {
+ const spec = e.currentTarget.dataset.spec;
+ this.setData({
+ 'evaluateData.spec': spec
+ });
+ },
+
+ // 获取报价
+ getQuote() {
+ if (this.data.evaluateData.spec) {
+ this.calculatePrice();
+ } else {
+ wx.showToast({
+ title: '请选择规格',
+ icon: 'none',
+ duration: 2000
+ });
+ }
+ },
+
+ // 上一步
+ prevStep() {
+ if (this.data.evaluateStep > 1) {
+ this.setData({
+ evaluateStep: this.data.evaluateStep - 1,
+ fromPreviousStep: true // 标记是从下一步返回的
+ });
+ } else {
+ // 如果在第一步,返回上一页
+ wx.navigateBack();
+ }
+ },
+
+ // 计算价格
+ calculatePrice() {
+ const { region, type, brand, model, freshness, size, packaging, spec } = this.data.evaluateData;
+
+ // 校验必填参数
+ if (!region || !type || !brand || !model || !freshness || !size || !packaging || !spec) {
+ wx.showToast({
+ title: '请完成所有选项',
+ icon: 'none',
+ duration: 2000
+ });
+ return;
+ }
+
+ // 显示加载中
+ wx.showLoading({
+ title: '计算中...',
+ mask: true
+ });
+
+ // 模拟计算延迟
+ setTimeout(() => {
+ // 基础价格表(元/斤)
+ const basePrices = {
+ '土鸡蛋': 25,
+ '洋鸡蛋': 15,
+ '乌鸡蛋': 35,
+ '有机鸡蛋': 40,
+ '初生蛋': 45
+ };
+
+ // 品牌溢价系数
+ const brandMultipliers = {
+ '农家乐': 1.0,
+ '山野': 1.1,
+ '生态园': 1.2,
+ '田园': 1.0,
+ '德青源': 1.1,
+ '圣迪乐村': 1.15,
+ '正大': 1.05,
+ '咯咯哒': 1.0
+ };
+
+ // 型号溢价系数
+ const modelMultipliers = {
+ // 土鸡蛋型号系数
+ '散养土鸡蛋': 1.1, '林下土鸡蛋': 1.15, '谷物喂养土鸡蛋': 1.2, '农家土鸡蛋': 1.0,
+ '高山散养土鸡蛋': 1.25, '林间土鸡蛋': 1.1, '野生土鸡蛋': 1.3,
+ '有机土鸡蛋': 1.3, '无抗土鸡蛋': 1.25, '生态土鸡蛋': 1.2,
+ '走地鸡蛋': 1.1, '自然放养土鸡蛋': 1.12,
+
+ // 洋鸡蛋型号系数
+ '安心鲜鸡蛋': 1.0, '谷物鸡蛋': 1.1, '营养鸡蛋': 1.05,
+ '高品质鲜鸡蛋': 1.15, '生态鸡蛋': 1.2,
+ '鲜鸡蛋': 1.0, '优选鸡蛋': 1.1,
+ '农家鸡蛋': 1.05,
+
+ // 乌鸡蛋型号系数
+ '散养乌鸡蛋': 1.1, '林下乌鸡蛋': 1.15, '野生乌鸡蛋': 1.3,
+ '有机乌鸡蛋': 1.3, '无抗乌鸡蛋': 1.25, '生态乌鸡蛋': 1.2,
+ '农家乌鸡蛋': 1.0, '谷物乌鸡蛋': 1.1,
+
+ // 有机鸡蛋型号系数
+ '有机认证鸡蛋': 1.3, '无抗有机鸡蛋': 1.35, '生态有机鸡蛋': 1.32,
+ '有机散养鸡蛋': 1.25, '有机谷物鸡蛋': 1.2, '野生有机鸡蛋': 1.4,
+ '有机农家鸡蛋': 1.1, '有机初生蛋': 1.4, '自然有机鸡蛋': 1.2,
+
+ // 初生蛋型号系数
+ '土鸡初生蛋': 1.2, '散养初生蛋': 1.25, '农家初生蛋': 1.15,
+ '高山初生蛋': 1.3, '林下初生蛋': 1.25, '野生初生蛋': 1.45,
+ '有机初生蛋': 1.4, '无抗初生蛋': 1.35, '生态初生蛋': 1.3
+ };
+
+ // 状况调整系数
+ const freshnessCoefficient = { '非常新鲜': 1.0, '较新鲜': 0.85, '一般': 0.7, '不新鲜': 0.4 };
+ const sizeCoefficient = { '特大': 1.3, '大': 1.1, '中': 1.0, '小': 0.8 };
+ const packagingCoefficient = { '原装完整': 1.0, '部分包装': 0.9, '散装': 0.8 };
+
+ // 计算单价(元/斤)
+ let unitPrice = basePrices[type] || 20;
+ const brandMultiplier = brandMultipliers[brand] || 1.0;
+ const modelMultiplier = modelMultipliers[model] || 1.0;
+
+ unitPrice = unitPrice * brandMultiplier * modelMultiplier;
+ unitPrice *= freshnessCoefficient[freshness];
+ unitPrice *= sizeCoefficient[size];
+ unitPrice *= packagingCoefficient[packaging];
+
+ // 确保价格合理
+ unitPrice = Math.max(unitPrice, 1);
+
+ // 计算总价(假设每个鸡蛋约0.05斤)
+ const eggsPerKilogram = 20; // 约20个鸡蛋/斤
+ const specCount = parseInt(spec) || 0;
+ const totalWeight = specCount / eggsPerKilogram;
+ const totalPrice = unitPrice * totalWeight;
+
+ // 更新结果
+ this.setData({
+ evaluateResult: {
+ finalPrice: unitPrice.toFixed(1),
+ totalPrice: totalPrice.toFixed(1)
+ },
+ evaluateStep: 9
+ }, () => {
+ wx.hideLoading();
+ });
+
+ }, 800);
+ },
+
+ // 重新估价
+ restartEvaluate() {
+ this.setData({
+ evaluateStep: 1,
+ evaluateData: {
+ region: '',
+ type: '',
+ brand: '',
+ model: '',
+ freshness: '',
+ size: '',
+ packaging: '',
+ spec: ''
+ },
+ evaluateResult: {
+ finalPrice: '0',
+ totalPrice: '0'
+ },
+ fromPreviousStep: false // 重置标志
+ });
+ },
+
+ // 返回首页
+ backToHome() {
+ wx.navigateBack();
+ },
+
+ // 跳转到购物页面
+ goToBuy() {
+ console.log('goToBuy 函数被调用');
+ // 使用与custom-tab-bar相同的跳转逻辑
+ const url = 'pages/buyer/index';
+
+ // 先尝试使用navigateTo
+ wx.navigateTo({
+ url: '/' + url,
+ success: function(res) {
+ console.log('使用navigateTo成功跳转到购物页面:', res);
+ },
+ fail: function(error) {
+ console.log('navigateTo失败,尝试使用reLaunch:', error);
+ // 如果navigateTo失败,使用reLaunch
+ wx.reLaunch({
+ url: '/' + url,
+ success: function(res) {
+ console.log('使用reLaunch成功跳转到购物页面:', res);
+ },
+ fail: function(err) {
+ console.error('reLaunch也失败:', err);
+ }
+ });
+ }
+ });
+ },
+
+ // 跳转到货源页面
+ goToSell() {
+ console.log('goToSell 函数被调用');
+ // 使用与custom-tab-bar相同的跳转逻辑
+ const url = 'pages/seller/index';
+
+ // 先尝试使用navigateTo
+ wx.navigateTo({
+ url: '/' + url,
+ success: function(res) {
+ console.log('使用navigateTo成功跳转到货源页面:', res);
+ },
+ fail: function(error) {
+ console.log('navigateTo失败,尝试使用reLaunch:', error);
+ // 如果navigateTo失败,使用reLaunch
+ wx.reLaunch({
+ url: '/' + url,
+ success: function(res) {
+ console.log('使用reLaunch成功跳转到货源页面:', res);
+ },
+ fail: function(err) {
+ console.error('reLaunch也失败:', err);
+ }
+ });
+ }
+ });
+ }
+})
\ No newline at end of file
diff --git a/pages/evaluate/index.json b/pages/evaluate/index.json
new file mode 100644
index 0000000..9c3c247
--- /dev/null
+++ b/pages/evaluate/index.json
@@ -0,0 +1,6 @@
+{
+ "navigationBarTitleText": "鸡蛋估价",
+ "navigationBarBackgroundColor": "#ffffff",
+ "navigationBarTextStyle": "black",
+ "backgroundColor": "#f5f5f5"
+}
\ No newline at end of file
diff --git a/pages/evaluate/index.wxml b/pages/evaluate/index.wxml
new file mode 100644
index 0000000..054a160
--- /dev/null
+++ b/pages/evaluate/index.wxml
@@ -0,0 +1,339 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 步骤 {{evaluateStep}}/8
+
+
+
+
+
+ 选择客户地区
+ 请选择您所在的地区
+
+
+
+
+ {{item}}
+ 点击选择该地区
+
+ ›
+
+
+
+
+
+
+
+
+ 选择鸡蛋类型
+ 请选择您要估价的鸡蛋类型(按每日成交单量排序)
+
+
+
+
+
+ {{eggType.rank}}
+ {{eggType.name}}
+
+ {{eggType.desc}}
+
+ ›
+
+
+
+
+
+
+
+
+ 选择品牌
+ {{evaluateData.type}} - 按每日成交单量排序
+
+
+
+
+ {{brand.rank}}
+ {{brand.name}}
+
+ ›
+
+
+
+
+
+
+
+
+ 选择具体型号
+ {{evaluateData.brand}} - 按每日成交单量排序
+
+
+
+
+ {{model.rank}}
+ {{model.name}}
+
+ ›
+
+
+
+
+
+
+
+
+ 新鲜程度
+ 请选择鸡蛋的新鲜程度
+
+
+
+
+ 非常新鲜
+ 7天内产出的新鲜鸡蛋
+
+ ✓
+
+
+
+
+ 较新鲜
+ 15天内产出的鸡蛋
+
+ ✓
+
+
+
+
+ 一般
+ 30天内产出的鸡蛋
+
+ ✓
+
+
+
+
+ 不新鲜
+ 30天以上的鸡蛋
+
+ ✓
+
+
+
+
+
+
+
+
+ 鸡蛋大小
+ 请选择鸡蛋的大小规格
+
+
+
+
+ 特大
+ 单枚≥70g
+
+ ✓
+
+
+
+
+ 大
+ 单枚60-70g
+
+ ✓
+
+
+
+
+ 中
+ 单枚50-60g
+
+ ✓
+
+
+
+
+ 小
+ 单枚<50g
+
+ ✓
+
+
+
+
+
+
+
+
+ 包装情况
+ 请选择鸡蛋的包装完好程度
+
+
+
+
+ 原装完整
+ 原包装完好无损
+
+ ✓
+
+
+
+
+ 部分包装
+ 包装有轻微破损
+
+ ✓
+
+
+
+
+ 散装
+ 无原包装
+
+ ✓
+
+
+
+
+
+
+
+
+ 请选择规格(数量)
+ 请选择鸡蛋的数量规格
+
+
+
+ 500个
+ ›
+
+
+ 1000个
+ ›
+
+
+ 2000个
+ ›
+
+
+ 10000个
+ ›
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{evaluateData.type}}
+
+ {{evaluateData.brand}}
+ {{evaluateData.model}}
+
+
+
+
+
+ 商品状况
+
+
+ 新鲜度
+ {{evaluateData.freshness}}
+
+
+ 大小
+ {{evaluateData.size}}
+
+
+ 包装
+ {{evaluateData.packaging}}
+
+
+ 规格
+ {{evaluateData.spec}}个
+
+
+ 单价
+ {{evaluateResult.finalPrice}}元/斤
+
+
+
+
+
+
+ 💡
+ 此价格仅供参考,实际成交价可能因市场波动有所差异
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/evaluate/index.wxss b/pages/evaluate/index.wxss
new file mode 100644
index 0000000..65bafa3
--- /dev/null
+++ b/pages/evaluate/index.wxss
@@ -0,0 +1,769 @@
+/* pages/evaluate/index.wxss */
+.evaluate-page {
+ min-height: 100vh;
+ background: linear-gradient(135deg, #f9f9f9, #f5f5f5);
+ font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
+}
+
+/* 顶部导航 */
+.evaluate-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 30rpx 32rpx;
+ background: white;
+ border-bottom: 1rpx solid #f0f0f0;
+ position: sticky;
+ top: 0;
+ z-index: 100;
+ box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.03);
+}
+
+.header-back {
+ font-size: 48rpx;
+ color: #333;
+ width: 60rpx;
+ transition: color 0.2s ease;
+}
+
+.header-back:active {
+ color: #FF6B00;
+}
+
+.header-title {
+ font-size: 36rpx;
+ font-weight: 600;
+ color: #333;
+}
+
+.header-placeholder {
+ width: 60rpx;
+}
+
+/* 进度指示器 */
+.progress-indicator {
+ background: white;
+ padding: 30rpx 32rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+}
+
+.progress-dots {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 20rpx;
+ position: relative;
+}
+
+.progress-dots::after {
+ content: '';
+ position: absolute;
+ top: 14rpx;
+ left: 0;
+ right: 0;
+ height: 8rpx;
+ background: #e0e0e0;
+ z-index: 1;
+}
+
+.progress-dot {
+ width: 28rpx;
+ height: 28rpx;
+ background: #e0e0e0;
+ border-radius: 50%;
+ transition: all 0.3s ease;
+ position: relative;
+ z-index: 2;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16rpx;
+ color: transparent;
+}
+
+.progress-dot.active {
+ background: #FF6B00;
+ color: white;
+ transform: scale(1.1);
+ box-shadow: 0 4rpx 12rpx rgba(255, 107, 0, 0.3);
+}
+
+.progress-text {
+ font-size: 28rpx;
+ color: #FF6B00;
+ text-align: center;
+ font-weight: 500;
+}
+
+/* 步骤内容 */
+.evaluate-step {
+ padding: 60rpx 32rpx 40rpx;
+ display: block;
+ align-items: flex-start;
+ justify-content: flex-start;
+}
+
+.step-content {
+ max-width: 100%;
+ display: block;
+ align-items: flex-start;
+ justify-content: flex-start;
+}
+
+.step-title {
+ font-size: 48rpx;
+ font-weight: 700;
+ color: #333;
+ margin-bottom: 20rpx;
+ letter-spacing: 1rpx;
+}
+
+.step-subtitle {
+ font-size: 28rpx;
+ color: #666;
+ margin-bottom: 60rpx;
+ line-height: 42rpx;
+}
+
+/* 类别列表 */
+.category-list {
+ background: white;
+ border-radius: 20rpx;
+ overflow: hidden;
+ box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.04);
+}
+
+.category-item {
+ display: flex;
+ align-items: center;
+ padding: 36rpx;
+ border-bottom: 1rpx solid #f5f5f5;
+ transition: all 0.2s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.category-item::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ width: 0;
+ background: linear-gradient(90deg, rgba(255, 107, 0, 0.05), transparent);
+ transition: width 0.3s ease;
+}
+
+.category-item:active::before {
+ width: 100%;
+}
+
+.category-item:last-child {
+ border-bottom: none;
+}
+
+.category-item.selected {
+ background: #fff8f0;
+ border-left: 8rpx solid #FF6B00;
+}
+
+.category-icon {
+ font-size: 64rpx;
+ margin-right: 24rpx;
+ filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.1));
+}
+
+.category-info {
+ flex: 1;
+}
+
+.category-name {
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 8rpx;
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+}
+
+.rank-number {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 40rpx;
+ height: 40rpx;
+ background: #F5F5F5;
+ color: #666;
+ border-radius: 6rpx;
+ font-size: 26rpx;
+ font-weight: 600;
+ margin-right: 20rpx;
+ min-width: 40rpx;
+ line-height: 40rpx;
+ text-align: center;
+ transition: all 0.2s ease;
+}
+
+/* 前三名的特殊样式 */
+.rank-number.rank-1 {
+ background: #FF6B00;
+ color: white;
+ transform: scale(1.05);
+ box-shadow: 0 4rpx 12rpx rgba(255, 107, 0, 0.25);
+}
+
+.rank-number.rank-2 {
+ background: #FF9500;
+ color: white;
+ box-shadow: 0 4rpx 12rpx rgba(255, 149, 0, 0.2);
+}
+
+.rank-number.rank-3 {
+ background: #FFB74D;
+ color: white;
+ box-shadow: 0 4rpx 12rpx rgba(255, 183, 77, 0.15);
+}
+
+/* 销售标签样式 */
+.sales-tag {
+ display: flex;
+ align-items: center;
+ background: linear-gradient(135deg, #FF6B00, #FF9500);
+ padding: 6rpx 16rpx;
+ border-radius: 20rpx;
+ margin-left: 10rpx;
+ box-shadow: 0 4rpx 12rpx rgba(255, 107, 0, 0.2);
+ animation: pulse 2s infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.05);
+ }
+}
+
+.sales-icon {
+ font-size: 22rpx;
+ margin-right: 6rpx;
+}
+
+.sales-count {
+ font-size: 22rpx;
+ color: #FFF;
+ font-weight: 600;
+}
+
+.category-desc {
+ font-size: 24rpx;
+ color: #666;
+}
+
+.category-arrow {
+ font-size: 36rpx;
+ color: #999;
+}
+
+/* 选项列表 */
+.option-list {
+ background: white;
+ border-radius: 20rpx;
+ overflow: hidden;
+ box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.04);
+}
+
+.option-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 36rpx;
+ border-bottom: 1rpx solid #f5f5f5;
+ transition: all 0.2s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.option-item::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ width: 0;
+ background: linear-gradient(90deg, rgba(255, 107, 0, 0.05), transparent);
+ transition: width 0.3s ease;
+}
+
+.option-item:active::before {
+ width: 100%;
+}
+
+.option-item:last-child {
+ border-bottom: none;
+}
+
+.option-item.selected {
+ background: #fff8f0;
+ border-left: 8rpx solid #FF6B00;
+}
+
+.option-text {
+ font-size: 32rpx;
+ color: #333;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ flex: 1;
+}
+
+/* 销售信息样式 */
+.sales-info {
+ display: flex;
+ align-items: center;
+ background: rgba(255, 107, 0, 0.1);
+ padding: 6rpx 16rpx;
+ border-radius: 20rpx;
+ margin-left: 15rpx;
+ transition: all 0.2s ease;
+}
+
+.sales-info .sales-icon {
+ font-size: 22rpx;
+ margin-right: 6rpx;
+}
+
+.sales-info .sales-count {
+ font-size: 22rpx;
+ color: #FF6B00;
+ font-weight: 600;
+}
+
+.option-arrow {
+ font-size: 36rpx;
+ color: #999;
+ transition: transform 0.2s ease;
+}
+
+.option-item:active .option-arrow {
+ transform: translateX(4rpx);
+}
+
+/* 条件列表 */
+.condition-list {
+ background: white;
+ border-radius: 20rpx;
+ overflow: hidden;
+ box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.04);
+}
+
+.condition-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 36rpx;
+ border-bottom: 1rpx solid #f5f5f5;
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+ text-align: left;
+}
+
+.condition-item::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ width: 0;
+ background: linear-gradient(90deg, rgba(255, 107, 0, 0.05), transparent);
+ transition: width 0.3s ease;
+}
+
+.condition-item:active::before {
+ width: 100%;
+}
+
+.condition-item:last-child {
+ border-bottom: none;
+}
+
+.condition-item.selected {
+ background: #fff8f0;
+ border-left: 8rpx solid #FF6B00;
+}
+
+.condition-info {
+ flex: 1;
+ text-align: left;
+ align-self: flex-start;
+}
+
+.condition-name {
+ font-size: 32rpx;
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 12rpx;
+ display: flex;
+ align-items: center;
+ text-align: left;
+ justify-content: flex-start;
+ align-self: flex-start;
+}
+
+.condition-desc {
+ font-size: 26rpx;
+ color: #666;
+ line-height: 36rpx;
+ text-align: left;
+ align-self: flex-start;
+}
+
+.condition-check {
+ color: #FF6B00;
+ font-size: 36rpx;
+ font-weight: bold;
+ background: white;
+ width: 50rpx;
+ height: 50rpx;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 4rpx 12rpx rgba(255, 107, 0, 0.3);
+}
+
+/* 获取报价按钮 */
+.get-price-section {
+ margin-top: 80rpx;
+ padding: 0 32rpx;
+}
+
+.get-price-btn {
+ background: linear-gradient(135deg, #FF6B00, #FF9500);
+ color: white;
+ border: none;
+ border-radius: 50rpx;
+ padding: 32rpx 0;
+ font-size: 34rpx;
+ font-weight: 700;
+ width: 100%;
+ box-shadow: 0 10rpx 30rpx rgba(255, 107, 0, 0.35);
+ transition: all 0.3s ease;
+ letter-spacing: 2rpx;
+}
+
+.get-price-btn:active {
+ transform: scale(0.98);
+ box-shadow: 0 6rpx 20rpx rgba(255, 107, 0, 0.3);
+}
+
+.get-price-btn::after {
+ content: none;
+}
+
+/* 结果页面 */
+.result-step {
+ background: linear-gradient(135deg, #fff8f0, #ffffff);
+ min-height: 100vh;
+}
+
+.result-header {
+ text-align: center;
+ padding: 80rpx 0 30rpx;
+ background: white;
+ box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.03);
+ animation: fadeIn 0.8s ease-out;
+}
+
+.result-icon {
+ font-size: 140rpx;
+ margin-bottom: 30rpx;
+ animation: bounce 1s ease-out;
+}
+
+@keyframes bounce {
+ 0% {
+ transform: translateY(-30rpx) scale(0.8);
+ opacity: 0;
+ }
+ 70% {
+ transform: translateY(10rpx) scale(1.1);
+ }
+ 100% {
+ transform: translateY(0) scale(1);
+ opacity: 1;
+ }
+}
+
+.result-title {
+ font-size: 48rpx;
+ font-weight: 700;
+ color: #333;
+ margin-bottom: 20rpx;
+ letter-spacing: 2rpx;
+ animation: fadeUp 0.6s ease-out;
+}
+
+.result-subtitle {
+ font-size: 28rpx;
+ color: #666;
+ animation: fadeUp 0.6s ease-out 0.2s both;
+}
+
+@keyframes fadeUp {
+ from {
+ transform: translateY(20rpx);
+ opacity: 0;
+ }
+ to {
+ transform: translateY(0);
+ opacity: 1;
+ }
+}
+
+.result-content {
+ padding: 40rpx 32rpx;
+}
+
+/* 商品信息卡片 */
+.product-info-card {
+ background: white;
+ border-radius: 20rpx;
+ padding: 40rpx;
+ margin-bottom: 50rpx;
+ box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.04);
+ animation: slideUp 0.8s ease-out;
+}
+
+@keyframes slideUp {
+ from {
+ transform: translateY(40rpx);
+ opacity: 0;
+ }
+ to {
+ transform: translateY(0);
+ opacity: 1;
+ }
+}
+
+.product-type {
+ font-size: 36rpx;
+ font-weight: 700;
+ color: #333;
+ margin-bottom: 20rpx;
+ letter-spacing: 1rpx;
+}
+
+.product-details {
+ display: flex;
+ gap: 20rpx;
+ flex-wrap: wrap;
+}
+
+.product-brand, .product-model {
+ font-size: 28rpx;
+ color: #666;
+ background: #f5f5f5;
+ padding: 14rpx 28rpx;
+ border-radius: 30rpx;
+ font-weight: 500;
+ transition: all 0.2s ease;
+}
+
+.product-brand:active, .product-model:active {
+ background: #e8e8e8;
+}
+
+/* 价格结果 */
+.price-result {
+ text-align: center;
+ margin-top: 30rpx;
+ margin-bottom: 0;
+ padding: 0 32rpx;
+ animation: pulseScale 1s ease-out;
+}
+
+@keyframes pulseScale {
+ 0% {
+ transform: scale(0.9);
+ opacity: 0;
+ }
+ 50% {
+ transform: scale(1.05);
+ }
+ 100% {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+.price-label {
+ font-size: 28rpx;
+ color: #666;
+ margin-bottom: 24rpx;
+ font-weight: 500;
+}
+
+.price-amount {
+ display: flex;
+ align-items: baseline;
+ justify-content: center;
+ gap: 12rpx;
+ margin-bottom: 16rpx;
+}
+
+.price-symbol {
+ font-size: 44rpx;
+ color: #FF6B00;
+ font-weight: 700;
+}
+
+.price-number {
+ font-size: 80rpx;
+ font-weight: bold;
+ color: #FF6B00;
+ line-height: 1;
+ text-shadow: 0 4rpx 12rpx rgba(255, 107, 0, 0.2);
+}
+
+.price-unit {
+ font-size: 30rpx;
+ color: #666;
+ font-weight: 500;
+}
+
+/* 状况汇总 */
+.condition-summary {
+ background: white;
+ border-radius: 20rpx;
+ padding: 40rpx;
+ margin-bottom: 40rpx;
+ box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.04);
+ animation: slideUp 0.8s ease-out 0.4s both;
+}
+
+.summary-title {
+ font-size: 32rpx;
+ font-weight: 700;
+ color: #333;
+ margin-bottom: 24rpx;
+ letter-spacing: 1rpx;
+}
+
+.condition-items {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20rpx;
+}
+
+.condition-item {
+ background: #f5f5f5;
+ padding: 20rpx 32rpx;
+ border-radius: 16rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 12rpx;
+ flex: 1;
+ min-width: 200rpx;
+ transition: all 0.2s ease;
+}
+
+.condition-item:active {
+ background: #e8e8e8;
+}
+
+.condition-label {
+ font-size: 26rpx;
+ color: #666;
+ font-weight: 500;
+}
+
+.condition-value {
+ font-size: 32rpx;
+ font-weight: 700;
+ color: #333;
+ letter-spacing: 1rpx;
+}
+
+/* 价格提示 */
+.price-tips {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 12rpx;
+ padding: 24rpx;
+ background: rgba(255, 107, 0, 0.05);
+ border-radius: 16rpx;
+ margin: 0 20rpx 60rpx;
+ animation: fadeUp 0.8s ease-out 0.6s both;
+}
+
+.tip-icon {
+ font-size: 30rpx;
+ color: #FF6B00;
+ flex-shrink: 0;
+ margin-top: 4rpx;
+}
+
+.tip-text {
+ font-size: 26rpx;
+ color: #666;
+ line-height: 38rpx;
+ flex: 1;
+ text-align: center;
+}
+
+/* 结果操作按钮 */
+.result-actions {
+ display: flex;
+ gap: 24rpx;
+ padding: 0 32rpx 60rpx;
+ animation: slideUp 0.8s ease-out 0.8s both;
+}
+
+.btn-secondary {
+ flex: 1;
+ background: white;
+ color: #666;
+ border: 1rpx solid #e0e0e0;
+ border-radius: 50rpx;
+ padding: 32rpx 0;
+ font-size: 34rpx;
+ font-weight: 700;
+ transition: all 0.3s ease;
+ letter-spacing: 2rpx;
+ box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.04);
+}
+
+.btn-secondary:active {
+ background: #f8f8f8;
+ transform: scale(0.98);
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.03);
+}
+
+.btn-primary {
+ flex: 1;
+ background: linear-gradient(135deg, #FF6B00, #FF9500);
+ color: white;
+ border: none;
+ border-radius: 50rpx;
+ padding: 32rpx 0;
+ font-size: 34rpx;
+ font-weight: 700;
+ transition: all 0.3s ease;
+ letter-spacing: 2rpx;
+ box-shadow: 0 10rpx 30rpx rgba(255, 107, 0, 0.35);
+}
+
+.btn-primary:active {
+ transform: scale(0.98);
+ box-shadow: 0 6rpx 20rpx rgba(255, 107, 0, 0.3);
+}
+
+.btn-secondary::after, .btn-primary::after {
+ content: none;
+}
\ No newline at end of file
diff --git a/pages/index/index.js b/pages/index/index.js
new file mode 100644
index 0000000..fea4263
--- /dev/null
+++ b/pages/index/index.js
@@ -0,0 +1,977 @@
+// pages/index/index.js
+const API = require('../../utils/api.js');
+Page({
+ data: {
+ currentUserType: null,
+ showUserInfoForm: false,
+ avatarUrl: 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0',
+ nickname: '',
+ showAuthModal: false,
+ showOneKeyLoginModal: false,
+ // 测试模式开关,用于在未完成微信认证时进行测试
+ testMode: true
+ },
+
+ onLoad() {
+ console.log('首页初始化')
+ },
+
+ onShow: function () {
+ // 页面显示
+ // 更新自定义tabBar状态
+ if (typeof this.getTabBar === 'function' && this.getTabBar()) {
+ this.getTabBar().setData({
+ selected: 0
+ });
+ }
+ // 更新全局tab状态
+ const app = getApp();
+ app.updateCurrentTab('index');
+ },
+
+ // 选择买家身份
+ async chooseBuyer() {
+ // 买家不需要登录验证,直接跳转到买家页面
+ this.finishSetUserType('buyer');
+ },
+
+ // 选择卖家身份
+ async chooseSeller() {
+ // 先检查是否登录
+ this.checkLoginAndProceed('seller');
+ },
+
+ // 检查登录状态并继续操作
+ checkLoginAndProceed(type) {
+ // 检查本地存储的登录信息
+ const openid = wx.getStorageSync('openid');
+ const userId = wx.getStorageSync('userId');
+ const userInfo = wx.getStorageSync('userInfo');
+
+ if (openid && userId && userInfo) {
+ console.log('用户已登录,直接处理身份选择');
+ // 用户已登录,直接处理
+ if (type === 'buyer') {
+ this.finishSetUserType(type);
+ } else if (type === 'seller') {
+ this.handleSellerRoute();
+ }
+ } else {
+ console.log('用户未登录,显示登录弹窗');
+ // 用户未登录,显示一键登录弹窗
+ this.setData({
+ pendingUserType: type,
+ showOneKeyLoginModal: true
+ });
+ }
+ },
+
+ // 处理卖家路由逻辑
+ async handleSellerRoute() {
+ try {
+
+ // 查询用户信息获取partnerstatus字段
+ const userInfo = await API.getUserInfo();
+ if (userInfo && userInfo.data && userInfo.data.partnerstatus) {
+ // 将partnerstatus存储到本地
+ wx.setStorageSync('partnerstatus', userInfo.data.partnerstatus);
+
+ console.log('获取到的partnerstatus:', userInfo.data.partnerstatus);
+
+ // 根据partnerstatus值控制路由跳转
+ if (userInfo.data.partnerstatus === 'approved') {
+ // 如果为approved,则进入seller/index页面
+ wx.switchTab({ url: '/pages/seller/index' });
+ } else {
+ // 否则进入pages/settlement/index页面
+ wx.navigateTo({ url: '/pages/settlement/index' });
+ }
+ } else {
+ // 如果没有获取到partnerstatus,默认进入settlement页面
+ console.log('未获取到partnerstatus字段');
+ wx.navigateTo({ url: '/pages/settlement/index' });
+ }
+ } catch (error) {
+ console.error('获取用户信息失败:', error);
+ // 出错时也进入settlement页面
+ wx.navigateTo({ url: '/pages/settlement/index' });
+ }
+ },
+
+ // 跳转到估价页面
+
+
+ // 显示一键登录弹窗
+ showOneKeyLogin() {
+ this.setData({
+ showAuthModal: false,
+ showOneKeyLoginModal: true
+ })
+ },
+
+ // 关闭未授权提示弹窗
+ closeAuthModal() {
+ this.setData({ showAuthModal: false })
+ },
+
+ // 关闭一键登录弹窗
+ closeOneKeyLoginModal() {
+ this.setData({ showOneKeyLoginModal: false })
+ },
+
+ // 处理手机号授权
+ async onGetPhoneNumber(e) {
+ // 打印详细错误信息,方便调试
+ console.log('getPhoneNumber响应:', e.detail)
+
+ // 关闭手机号授权弹窗
+ this.setData({ showOneKeyLoginModal: false })
+
+ // 用户点击拒绝授权
+ if (e.detail.errMsg === 'getPhoneNumber:fail user deny') {
+ wx.showToast({
+ title: '需要授权手机号才能使用',
+ icon: 'none',
+ duration: 2000
+ })
+ return
+ }
+
+ // 处理没有权限的情况
+ if (e.detail.errMsg === 'getPhoneNumber:fail no permission') {
+ // 如果是测试模式,跳过真实授权流程
+ if (this.data.testMode) {
+ console.log('进入测试模式,跳过真实手机号授权')
+ await this.simulateLoginForTest()
+ return
+ }
+
+ wx.showToast({
+ title: '当前环境无法获取手机号权限',
+ icon: 'none',
+ duration: 3000
+ })
+ // 增加关于微信认证要求的说明
+ console.warn('获取手机号权限失败: 请注意,微信小程序获取手机号功能需要满足以下条件:1. 小程序必须完成微信企业认证;2. 需要在小程序后台配置相应权限;3. 必须使用button组件的open-type="getPhoneNumber"触发。')
+ return
+ }
+
+ // 检查是否已经登录,避免重复授权
+ const existingOpenid = wx.getStorageSync('openid')
+ const existingUserId = wx.getStorageSync('userId')
+ const existingUserInfo = wx.getStorageSync('userInfo')
+
+ if (existingOpenid && existingUserId && existingUserInfo && existingUserInfo.phoneNumber !== '13800138000') {
+ console.log('用户已登录且手机号有效,直接完成身份设置')
+ // 直接完成身份设置,跳过重复授权
+ const currentUserType = this.data.pendingUserType || this.data.currentUserType || 'buyer'
+ this.finishSetUserType(currentUserType)
+ return
+ }
+
+ wx.showLoading({
+ title: '登录中...',
+ mask: true
+ })
+
+ // 引入API服务
+ const API = require('../../utils/api.js')
+
+ try {
+ if (e.detail.errMsg === 'getPhoneNumber:ok') {
+ // 用户同意授权,实际处理授权流程
+ console.log('用户同意授权获取手机号')
+
+ // 1. 先执行微信登录获取code
+ const loginRes = await new Promise((resolve, reject) => {
+ wx.login({
+ success: resolve,
+ fail: reject
+ })
+ })
+
+ if (!loginRes.code) {
+ throw new Error('获取登录code失败')
+ }
+
+ console.log('获取登录code成功:', loginRes.code)
+
+ // 2. 使用code换取openid
+ const openidRes = await API.getOpenid(loginRes.code)
+
+ // 改进错误处理逻辑,更宽容地处理服务器返回格式,增加详细日志
+ let openid = null;
+ let userId = null;
+ console.log('openidRes完整响应:', JSON.stringify(openidRes));
+
+ if (openidRes && typeof openidRes === 'object') {
+ // 适配服务器返回格式:{success: true, code: 200, message: '获取openid成功', data: {openid, userId}}
+ if (openidRes.data && typeof openidRes.data === 'object') {
+ console.log('识别到标准服务器返回格式,从data字段提取信息');
+ openid = openidRes.data.openid || openidRes.data.OpenID || null;
+ userId = openidRes.data.userId || null;
+ } else {
+ // 尝试从响应对象中直接提取openid,适配其他可能的格式
+ console.log('尝试从根对象直接提取openid');
+ openid = openidRes.openid || openidRes.OpenID || null;
+ userId = openidRes.userId || null;
+ }
+ }
+
+ if (!openid) {
+ console.error('无法从服务器响应中提取openid,完整响应:', JSON.stringify(openidRes));
+ // 增加更友好的错误信息,指导用户检查服务器配置
+ throw new Error(`获取openid失败: 服务器返回数据格式可能不符合预期,请检查服务器配置。响应数据为: ${JSON.stringify(openidRes)}`);
+ }
+
+ console.log('获取openid成功:', openid)
+
+ // 3. 存储openid和session_key
+ wx.setStorageSync('openid', openid)
+
+ // 从服务器返回中获取session_key
+ if (openidRes && openidRes.session_key) {
+ wx.setStorageSync('sessionKey', openidRes.session_key)
+ } else if (openidRes && openidRes.data && openidRes.data.session_key) {
+ wx.setStorageSync('sessionKey', openidRes.data.session_key)
+ }
+
+ // 优先使用从服务器响应data字段中提取的userId
+ if (userId) {
+ wx.setStorageSync('userId', userId)
+ console.log('使用从服务器data字段提取的userId:', userId)
+ } else if (openidRes && openidRes.userId) {
+ wx.setStorageSync('userId', openidRes.userId)
+ console.log('使用服务器根对象中的userId:', openidRes.userId)
+ } else {
+ // 生成临时userId
+ const tempUserId = 'user_' + Date.now()
+ wx.setStorageSync('userId', tempUserId)
+ console.log('生成临时userId:', tempUserId)
+ }
+
+ // 4. 上传手机号加密数据到服务器解密
+ const phoneData = {
+ ...e.detail,
+ openid: openid
+ }
+
+ console.log('准备上传手机号加密数据到服务器')
+ const phoneRes = await API.uploadPhoneNumberData(phoneData)
+
+ // 改进手机号解密结果的处理逻辑
+ if (!phoneRes || (!phoneRes.success && !phoneRes.phoneNumber)) {
+ // 如果服务器返回格式不标准但包含手机号,也接受
+ if (phoneRes && phoneRes.phoneNumber) {
+ console.warn('服务器返回格式可能不符合预期,但成功获取手机号');
+ } else {
+ throw new Error('获取手机号失败: ' + (phoneRes && phoneRes.message ? phoneRes.message : '未知错误'))
+ }
+ }
+
+ // 检查是否有手机号冲突
+ const hasPhoneConflict = phoneRes.phoneNumberConflict || false
+ const isNewPhone = phoneRes.isNewPhone || true
+ const phoneNumber = phoneRes.phoneNumber || null
+
+ // 如果有手机号冲突且没有返回手机号,使用临时手机号
+ const finalPhoneNumber = hasPhoneConflict && !phoneNumber ? '13800138000' : phoneNumber
+
+ console.log('手机号解密结果:', {
+ phoneNumber: finalPhoneNumber,
+ hasPhoneConflict: hasPhoneConflict,
+ isNewPhone: isNewPhone
+ })
+
+ // 5. 获取用户微信名称和头像
+ let userProfile = null;
+ try {
+ userProfile = await new Promise((resolve, reject) => {
+ wx.getUserProfile({
+ desc: '用于完善会员资料',
+ success: resolve,
+ fail: reject
+ });
+ });
+ console.log('获取用户信息成功:', userProfile);
+ } catch (err) {
+ console.warn('获取用户信息失败:', err);
+ // 如果获取失败,使用默认值
+ }
+
+ // 6. 创建用户信息
+ const tempUserInfo = {
+ nickName: userProfile ? userProfile.userInfo.nickName : '微信用户',
+ avatarUrl: userProfile ? userProfile.userInfo.avatarUrl : this.data.avatarUrl,
+ gender: userProfile ? userProfile.userInfo.gender : 0,
+ country: userProfile ? userProfile.userInfo.country : '',
+ province: userProfile ? userProfile.userInfo.province : '',
+ city: userProfile ? userProfile.userInfo.city : '',
+ language: userProfile ? userProfile.userInfo.language : 'zh_CN',
+ phoneNumber: finalPhoneNumber
+ }
+
+ // 从本地存储获取userId(使用已声明的变量)
+ const storedUserId = wx.getStorageSync('userId')
+ // 优先使用用户之前选择的身份类型,如果没有则尝试获取已存储的或默认为买家
+ const users = wx.getStorageSync('users') || {}
+ const currentUserType = this.data.pendingUserType || this.data.currentUserType ||
+ (users[storedUserId] && users[storedUserId].type ? users[storedUserId].type : 'buyer')
+
+ console.log('用户身份类型:', currentUserType)
+
+ // 清除临时存储的身份类型
+ if (this.data.pendingUserType) {
+ this.setData({ pendingUserType: null })
+ }
+
+ // 保存用户信息并等待上传完成
+ console.log('开始保存用户信息并上传到服务器...')
+ const uploadResult = await this.saveUserInfo(tempUserInfo, currentUserType)
+ console.log('用户信息保存并上传完成')
+
+ wx.hideLoading()
+
+ // 根据服务器返回的结果显示不同的提示
+ if (uploadResult && uploadResult.phoneNumberConflict) {
+ wx.showToast({
+ title: '登录成功,但手机号已被其他账号绑定',
+ icon: 'none',
+ duration: 3000
+ })
+ } else {
+ wx.showToast({
+ title: '登录成功,手机号已绑定',
+ icon: 'success',
+ duration: 2000
+ })
+ }
+
+ // 完成设置并跳转
+ this.finishSetUserType(currentUserType)
+ } else {
+ // 用户拒绝授权或其他情况
+ console.log('手机号授权失败:', e.detail.errMsg)
+ // 不再抛出错误,而是显示友好的提示
+ wx.hideLoading()
+ wx.showToast({
+ title: '需要授权手机号才能使用',
+ icon: 'none',
+ duration: 2000
+ })
+ return
+ }
+ } catch (error) {
+ wx.hideLoading()
+ console.error('登录过程中发生错误:', error)
+
+ // 更具体的错误提示
+ let errorMsg = '登录失败,请重试'
+ if (error.message.includes('网络')) {
+ errorMsg = '网络连接失败,请检查网络后重试'
+ } else if (error.message.includes('服务器')) {
+ errorMsg = '服务器连接失败,请稍后重试'
+ }
+
+ wx.showToast({
+ title: errorMsg,
+ icon: 'none',
+ duration: 3000
+ })
+
+ // 清除可能已经保存的不完整信息
+ try {
+ wx.removeStorageSync('openid')
+ wx.removeStorageSync('sessionKey')
+ wx.removeStorageSync('userId')
+ } catch (e) {
+ console.error('清除临时登录信息失败:', e)
+ }
+ }
+ },
+
+ // 处理用户基本信息授权
+ handleUserAuth(type) {
+ // 保存当前用户类型
+ this.setData({
+ currentUserType: type
+ })
+
+ // 先执行微信登录
+ this.doWechatLogin(type)
+ },
+
+ // 测试模式下模拟登录流程
+ async simulateLoginForTest() {
+ wx.showLoading({
+ title: '测试模式登录中...',
+ mask: true
+ })
+
+ try {
+ // 1. 模拟微信登录,生成测试用的code
+ const mockCode = 'test_code_' + Date.now()
+ console.log('模拟获取登录code:', mockCode)
+
+ // 2. 模拟获取openid和userId
+ const mockOpenid = 'test_openid_' + Date.now()
+ const mockUserId = 'test_user_' + Date.now()
+
+ console.log('模拟获取openid:', mockOpenid)
+ console.log('模拟获取userId:', mockUserId)
+
+ // 3. 存储测试数据
+ wx.setStorageSync('openid', mockOpenid)
+ wx.setStorageSync('userId', mockUserId)
+
+ // 4. 模拟手机号解密结果
+ const mockPhoneNumber = '13800138000'
+ console.log('模拟手机号解密成功:', mockPhoneNumber)
+
+ // 5. 创建模拟用户信息
+ const mockUserInfo = {
+ nickName: '测试用户',
+ avatarUrl: this.data.avatarUrl,
+ gender: 0,
+ country: '测试国家',
+ province: '测试省份',
+ city: '测试城市',
+ language: 'zh_CN',
+ phoneNumber: mockPhoneNumber
+ }
+
+ // 6. 获取用户身份类型(优先使用pendingUserType)
+ const userId = wx.getStorageSync('userId')
+ const users = wx.getStorageSync('users') || {}
+ const currentUserType = this.data.pendingUserType || this.data.currentUserType ||
+ (users[userId] && users[userId].type ? users[userId].type : 'buyer')
+
+ console.log('测试模式用户身份类型:', currentUserType)
+
+ // 7. 清除临时存储的身份类型
+ if (this.data.pendingUserType) {
+ this.setData({ pendingUserType: null })
+ }
+
+ // 8. 保存用户信息并等待上传完成
+ console.log('测试模式开始保存用户信息...')
+ // 在测试模式下也会上传用户信息到服务器,用于连通性测试
+ await this.saveUserInfo(mockUserInfo, currentUserType)
+ console.log('测试模式用户信息保存完成')
+
+ wx.hideLoading()
+
+ // 9. 显示成功提示
+ wx.showToast({
+ title: '测试模式登录成功',
+ icon: 'success',
+ duration: 2000
+ })
+
+ // 10. 完成设置并跳转
+ this.finishSetUserType(currentUserType)
+ } catch (error) {
+ wx.hideLoading()
+ console.error('测试模式登录过程中发生错误:', error)
+
+ wx.showToast({
+ title: '测试模式登录失败',
+ icon: 'none',
+ duration: 2000
+ })
+ }
+ },
+
+ // 执行微信登录并获取openid
+ async doWechatLogin(type) {
+ // 显示加载提示
+ wx.showLoading({
+ title: '登录中...',
+ mask: true
+ })
+
+ try {
+ // 调用微信登录接口
+ const loginRes = await new Promise((resolve, reject) => {
+ wx.login({
+ success: resolve,
+ fail: reject
+ })
+ })
+
+ if (loginRes.code) {
+ console.log('微信登录成功,code:', loginRes.code)
+
+ // 保存登录凭证
+ try {
+ wx.setStorageSync('loginCode', loginRes.code)
+ } catch (e) {
+ console.error('保存登录凭证失败:', e)
+ }
+
+ // 引入API服务
+ const API = require('../../utils/api.js')
+
+ // 发送code和用户类型到服务器换取openid和session_key
+ try {
+ const openidRes = await API.getOpenid(loginRes.code, type)
+ console.log('获取openid响应:', openidRes)
+
+ // 增强版响应处理逻辑,支持多种返回格式
+ let openid = null;
+ let userId = null;
+ let sessionKey = null;
+
+ // 优先从data字段获取数据
+ if (openidRes && openidRes.data && typeof openidRes.data === 'object') {
+ openid = openidRes.data.openid || openidRes.data.OpenID || null;
+ userId = openidRes.data.userId || openidRes.data.userid || null;
+ sessionKey = openidRes.data.session_key || openidRes.data.sessionKey || null;
+ }
+
+ // 如果data为空或不存在,尝试从响应对象直接获取
+ if (!openid && openidRes && typeof openidRes === 'object') {
+ console.warn('服务器返回格式可能不符合预期,data字段为空或不存在,但尝试从根对象提取信息:', openidRes);
+ openid = openidRes.openid || openidRes.OpenID || null;
+ userId = openidRes.userId || openidRes.userid || null;
+ sessionKey = openidRes.session_key || openidRes.sessionKey || null;
+ }
+
+ // 检查服务器状态信息
+ const isSuccess = openidRes && (openidRes.success === true || openidRes.code === 200);
+ const serverMessage = openidRes && (openidRes.message || openidRes.msg);
+
+ if (isSuccess && !openid) {
+ console.warn('服务器返回成功状态,但未包含有效的openid:', openidRes);
+ }
+
+ // 打印获取到的信息,方便调试
+ console.log('提取到的登录信息:', { openid, userId, sessionKey, serverMessage });
+
+ if (openid) {
+ // 存储openid和session_key
+ wx.setStorageSync('openid', openid)
+ if (sessionKey) {
+ wx.setStorageSync('sessionKey', sessionKey)
+ }
+
+ // 如果有userId,也存储起来
+ if (userId) {
+ wx.setStorageSync('userId', userId)
+ }
+ console.log('获取openid成功并存储:', openid)
+
+ // 验证登录状态并获取用户信息
+ await this.validateLoginAndGetUserInfo(openid)
+ } else {
+ // 即使没有获取到openid,也要继续用户信息授权流程
+ console.warn('未获取到有效的openid,但继续用户信息授权流程:', openidRes);
+ // 设置一个临时的openid以便继续流程
+ wx.setStorageSync('openid', 'temp_' + Date.now())
+ }
+ } catch (error) {
+ console.error('获取openid失败:', error)
+ // 即使获取openid失败,也继续用户信息授权流程
+ }
+
+ // 继续用户信息授权流程,等待完成
+ await this.processUserInfoAuth(type)
+ } else {
+ wx.hideLoading()
+ console.error('微信登录失败:', loginRes)
+ wx.showToast({
+ title: '登录失败,请重试',
+ icon: 'none',
+ duration: 2000
+ })
+ }
+ } catch (err) {
+ wx.hideLoading()
+ console.error('wx.login失败:', err)
+ wx.showToast({
+ title: '获取登录状态失败',
+ icon: 'none',
+ duration: 2000
+ })
+ }
+ },
+
+ // 验证登录状态并获取用户信息
+ async validateLoginAndGetUserInfo(openid) {
+ try {
+ // 引入API服务
+ const API = require('../../utils/api.js')
+
+ // 调用服务器验证登录状态
+ const validateRes = await API.validateUserLogin()
+
+ if (validateRes.success && validateRes.userInfo) {
+ // 服务器返回了用户信息,同步到本地
+ const app = getApp()
+ const userInfo = validateRes.userInfo
+
+ // 更新全局用户信息
+ app.globalData.userInfo = userInfo
+
+ // 存储用户信息到本地
+ wx.setStorageSync('userInfo', userInfo)
+ console.log('验证登录状态成功,用户信息已同步:', userInfo)
+
+ // 检查是否为临时手机号,如果是则提示用户重新授权
+ if (userInfo.phoneNumber === '13800138000') {
+ console.warn('检测到临时手机号,建议用户重新授权')
+ // 设置重新授权标志
+ wx.setStorageSync('needPhoneAuth', true)
+ } else {
+ // 清除可能存在的重新授权标志
+ wx.removeStorageSync('needPhoneAuth')
+ console.log('手机号验证通过:', userInfo.phoneNumber)
+ }
+
+ return true
+ } else {
+ console.warn('服务器验证失败,可能是新用户或登录状态无效')
+ return false
+ }
+ } catch (error) {
+ console.error('验证登录状态失败:', error)
+ // 如果验证失败,清除可能存在的无效登录信息
+ try {
+ wx.removeStorageSync('openid')
+ wx.removeStorageSync('userId')
+ wx.removeStorageSync('userInfo')
+ } catch (e) {
+ console.error('清除无效登录信息失败:', e)
+ }
+ return false
+ }
+ },
+
+ // 处理用户信息授权
+ async processUserInfoAuth(type) {
+ const app = getApp()
+
+ // 如果已经有用户信息,直接完成设置并跳转
+ if (app.globalData.userInfo) {
+ wx.hideLoading()
+ this.finishSetUserType(type)
+ return
+ }
+
+ // 优化:首次登录时自动创建临时用户信息并完成登录,不再需要用户填写表单
+ // 获取已存储的userId或生成新的
+ let userId = wx.getStorageSync('userId')
+ if (!userId) {
+ userId = 'user_' + Date.now()
+ wx.setStorageSync('userId', userId)
+ }
+
+ // 创建临时用户信息
+ const tempUserInfo = {
+ nickName: '微信用户',
+ avatarUrl: this.data.avatarUrl,
+ gender: 0,
+ country: '',
+ province: '',
+ city: '',
+ language: 'zh_CN'
+ }
+
+ try {
+ // 保存临时用户信息并完成登录,等待数据上传完成
+ await this.saveUserInfo(tempUserInfo, type)
+
+ // 隐藏加载提示
+ wx.hideLoading()
+
+ // 数据上传完成后再跳转
+ this.finishSetUserType(type)
+ } catch (error) {
+ console.error('处理用户信息授权失败:', error)
+ wx.hideLoading()
+ wx.showToast({
+ title: '登录失败,请重试',
+ icon: 'none',
+ duration: 2000
+ })
+ }
+ },
+
+ // 保存用户信息
+ async saveUserInfo(userInfo, type) {
+ // 确保userId存在
+ let userId = wx.getStorageSync('userId')
+ if (!userId) {
+ userId = 'user_' + Date.now()
+ wx.setStorageSync('userId', userId)
+ }
+
+ // 保存用户信息到本地存储 - 修复首次获取问题
+ let users = wx.getStorageSync('users')
+ // 如果users不存在或不是对象,初始化为空对象
+ if (!users || typeof users !== 'object') {
+ users = {}
+ }
+
+ // 初始化用户信息
+ users[userId] = users[userId] || {}
+ users[userId].info = userInfo
+ users[userId].type = type
+
+ // 确保存储操作成功
+ try {
+ wx.setStorageSync('users', users)
+ console.log('用户信息已成功保存到本地存储')
+ } catch (e) {
+ console.error('保存用户信息到本地存储失败:', e)
+ }
+
+ // 保存用户信息到全局变量
+ const app = getApp()
+ app.globalData.userInfo = userInfo
+ app.globalData.userType = type
+ console.log('用户信息已保存到全局变量:', userInfo)
+
+ // 额外保存一份单独的userInfo到本地存储,便于checkPhoneAuthSetting方法检查
+ try {
+ wx.setStorageSync('userInfo', userInfo)
+ console.log('单独的userInfo已保存')
+ } catch (e) {
+ console.error('保存单独的userInfo失败:', e)
+ }
+
+ // 上传用户信息到服务器
+ // 在测试模式下也上传用户信息,用于连通性测试
+ console.log('准备上传用户信息到服务器进行测试...')
+
+ // 确保测试数据包含服务器所需的所有字段
+ const completeUserInfo = {
+ ...userInfo,
+ // 确保包含服务器需要的必要字段
+ nickName: userInfo.nickName || '测试用户',
+ phoneNumber: userInfo.phoneNumber || '13800138000'
+ }
+
+ try {
+ const uploadResult = await this.uploadUserInfoToServer(completeUserInfo, userId, type)
+ console.log('用户信息上传到服务器成功')
+ return uploadResult // 返回上传结果
+ } catch (error) {
+ console.error('用户信息上传到服务器失败:', error)
+ // 显示友好的提示,但不中断流程
+ wx.showToast({
+ title: '测试数据上传失败,不影响使用',
+ icon: 'none',
+ duration: 2000
+ })
+ // 不再抛出错误,而是返回默认成功结果,确保登录流程继续
+ return {
+ success: true,
+ message: '本地登录成功,服务器连接失败'
+ }
+ }
+ },
+
+ // 处理头像选择
+ onChooseAvatar(e) {
+ const { avatarUrl } = e.detail
+ this.setData({
+ avatarUrl
+ })
+ },
+
+ // 处理昵称提交
+ getUserName(e) {
+ const { nickname } = e.detail.value
+ const type = this.data.currentUserType
+
+ if (!nickname) {
+ wx.showToast({
+ title: '请输入昵称',
+ icon: 'none',
+ duration: 2000
+ })
+ return
+ }
+
+ // 创建用户信息对象
+ const userInfo = {
+ nickName: nickname,
+ avatarUrl: this.data.avatarUrl,
+ // 其他可能需要的字段
+ gender: 0,
+ country: '',
+ province: '',
+ city: '',
+ language: 'zh_CN'
+ }
+
+ // 保存用户信息
+ this.saveUserInfo(userInfo, type)
+
+ // 隐藏表单
+ this.setData({
+ showUserInfoForm: false
+ })
+
+ // 完成设置并跳转
+ this.finishSetUserType(type)
+ },
+
+ // 取消用户信息表单
+ cancelUserInfoForm() {
+ this.setData({
+ showUserInfoForm: false
+ })
+ wx.hideLoading()
+ },
+
+ // 上传用户信息到服务器
+ async uploadUserInfoToServer(userInfo, userId, type) {
+ // 引入API服务
+ const API = require('../../utils/api.js')
+
+ // 获取openid
+ const openid = wx.getStorageSync('openid')
+
+ // 构造上传数据(包含openid和session_key)
+ const uploadData = {
+ userId: userId,
+ openid: openid,
+ ...userInfo,
+ type: type,
+ timestamp: Date.now()
+ }
+
+ // 调用API上传用户信息并返回Promise
+ try {
+ const res = await API.uploadUserInfo(uploadData)
+ console.log('用户信息上传成功:', res)
+ return res
+ } catch (err) {
+ console.error('用户信息上传失败:', err)
+ // 不再抛出错误,而是返回默认成功结果,确保登录流程继续
+ // 这样即使服务器连接失败,本地登录也能完成
+ return {
+ success: true,
+ message: '本地登录成功,服务器连接失败'
+ }
+ }
+ },
+
+ // 处理手机号授权结果(已重命名为onPhoneNumberResult,此方法已废弃)
+ processPhoneAuthResult: function () {
+ console.warn('processPhoneAuthResult方法已废弃,请使用onPhoneNumberResult方法')
+ },
+
+ // 手机号授权处理
+ async onPhoneNumberResult(e) {
+ console.log('手机号授权结果:', e)
+ if (e.detail.errMsg === 'getPhoneNumber:ok') {
+ // 用户同意授权,获取加密数据
+ const phoneData = e.detail
+
+ wx.showLoading({ title: '获取手机号中...' })
+
+ try {
+ // 引入API服务
+ const API = require('../../utils/api.js')
+
+ // 上传到服务器解密
+ const res = await API.uploadPhoneNumberData(phoneData)
+
+ wx.hideLoading()
+
+ if (res.success && res.phoneNumber) {
+ console.log('获取手机号成功:', res.phoneNumber)
+
+ // 保存手机号到用户信息
+ const app = getApp()
+ const userInfo = app.globalData.userInfo || wx.getStorageSync('userInfo') || {}
+ userInfo.phoneNumber = res.phoneNumber
+
+ // 更新本地和全局用户信息
+ app.globalData.userInfo = userInfo
+ wx.setStorageSync('userInfo', userInfo)
+
+ // 获取userId
+ const userId = wx.getStorageSync('userId')
+ const users = wx.getStorageSync('users') || {}
+ const currentUserType = users[userId] && users[userId].type ? users[userId].type : ''
+
+ // 同时更新服务器用户信息,确保上传完成
+ console.log('开始更新服务器用户信息...')
+ if (!this.data.testMode) {
+ await this.uploadUserInfoToServer(userInfo, userId, currentUserType)
+ console.log('服务器用户信息更新完成')
+ } else {
+ console.log('测试模式下跳过服务器用户信息更新')
+ }
+
+ wx.showToast({ title: '手机号绑定成功', icon: 'success' })
+ } else {
+ console.error('获取手机号失败:', res)
+ wx.showToast({ title: '获取手机号失败', icon: 'none' })
+ }
+ } catch (err) {
+ wx.hideLoading()
+ console.error('获取手机号失败:', err)
+ wx.showToast({ title: '获取手机号失败', icon: 'none' })
+ }
+ } else {
+ console.log('用户拒绝授权手机号')
+ }
+ },
+
+ // 完成用户类型设置并跳转
+ finishSetUserType(type) {
+ const userId = wx.getStorageSync('userId')
+
+ // 更新用户类型
+ let users = wx.getStorageSync('users')
+ // 检查users是否为对象,如果不是则重新初始化为空对象
+ if (typeof users !== 'object' || users === null) {
+ users = {}
+ }
+ // 确保userId对应的用户对象存在
+ if (!users[userId]) {
+ users[userId] = {}
+ }
+ users[userId].type = type
+ wx.setStorageSync('users', users)
+
+ // 打标签
+ let tags = wx.getStorageSync('tags')
+ // 检查tags是否为对象,如果不是则重新初始化为空对象
+ if (typeof tags !== 'object' || tags === null) {
+ tags = {}
+ }
+ // 确保userId对应的标签数组存在
+ tags[userId] = tags[userId] || []
+ // 移除已有的身份标签
+ tags[userId] = tags[userId].filter(tag => !tag.startsWith('身份:'))
+ // 添加新的身份标签
+ tags[userId].push(`身份:${type}`)
+ wx.setStorageSync('tags', tags)
+
+ console.log('用户类型设置完成,准备跳转到', type === 'buyer' ? '买家页面' : '卖家页面')
+
+ // 添加小延迟确保所有异步操作都完成后再跳转
+ setTimeout(() => {
+ // 跳转到对应页面
+ if (type === 'buyer') {
+ wx.switchTab({ url: '/pages/buyer/index' })
+ } else {
+ // 卖家身份需要处理partnerstatus逻辑,调用专门的方法
+ this.handleSellerRoute()
+ }
+ }, 500)
+ },
+
+
+
+ // 前往个人中心
+ toProfile() {
+ wx.switchTab({ url: '/pages/profile/index' })
+ }
+})
diff --git a/pages/index/index.json b/pages/index/index.json
new file mode 100644
index 0000000..aa3f1b0
--- /dev/null
+++ b/pages/index/index.json
@@ -0,0 +1,5 @@
+{
+ "usingComponents": {
+ "navigation-bar": "/components/navigation-bar/navigation-bar"
+ }
+}
\ No newline at end of file
diff --git a/pages/index/index.wxml b/pages/index/index.wxml
new file mode 100644
index 0000000..2243bf2
--- /dev/null
+++ b/pages/index/index.wxml
@@ -0,0 +1,94 @@
+
+
+ 中国最专业的鸡蛋现货交易平台
+
+ 请选择您的需求,我们将为您提供专属服务
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 提示
+
+
+ 您还没有授权登录
+
+
+
+
+
+
+
+
+
+
+
+
+ 授权登录
+
+
+ 请授权获取您的手机号用于登录
+
+
+
+
+
+
+
+
+
+
+
+
+ 完善个人信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 已有账号?进入我的页面
+
+
diff --git a/pages/index/index.wxss b/pages/index/index.wxss
new file mode 100644
index 0000000..e792b37
--- /dev/null
+++ b/pages/index/index.wxss
@@ -0,0 +1,243 @@
+/**index.wxss**/
+page {
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
+ margin: 0;
+ padding: 0;
+}
+
+.container {
+ padding: 0;
+ margin: 0;
+ width: 100%;
+}
+.scrollarea {
+ flex: 1;
+ overflow-y: hidden;
+}
+
+/* 玻璃质感按钮样式 */
+.btn {
+ /* 基础样式重置 */
+ border: none;
+ border-radius: 24rpx;
+ font-size: 32rpx;
+ font-weight: 600;
+ padding: 28rpx 0;
+ margin: 0 auto 24rpx;
+ width: 80%;
+ display: block;
+ text-align: center;
+ white-space: nowrap;
+ line-height: 1.5;
+
+ /* 玻璃质感效果 */
+ background: rgba(255, 255, 255, 0.15);
+ backdrop-filter: blur(12rpx);
+ -webkit-backdrop-filter: blur(12rpx);
+ border: 1rpx solid rgba(255, 255, 255, 0.3);
+ box-shadow:
+ 0 8rpx 32rpx rgba(31, 38, 135, 0.2),
+ 0 4rpx 16rpx rgba(0, 0, 0, 0.1),
+ inset 0 2rpx 4rpx rgba(255, 255, 255, 0.7),
+ inset 0 -2rpx 4rpx rgba(0, 0, 0, 0.1);
+
+ /* 过渡效果 */
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+/* 买家按钮样式 */
+.buyer-btn {
+ color: #07c160;
+ background: rgba(7, 193, 96, 0.15);
+}
+
+/* 卖家按钮样式 */
+.seller-btn {
+ color: #1677ff;
+ background: rgba(22, 119, 255, 0.15);
+}
+
+/* 估价按钮样式 */
+.evaluate-btn {
+ color: #4CAF50;
+ background: rgba(76, 175, 80, 0.15);
+}
+
+/* 立即入驻按钮样式 */
+.settlement-btn {
+ color: #2196F3;
+ background: rgba(33, 150, 243, 0.15);
+}
+
+/* 按钮点击效果 */
+.btn:active {
+ transform: scale(0.98);
+ box-shadow:
+ 0 4rpx 16rpx rgba(31, 38, 135, 0.1),
+ 0 2rpx 8rpx rgba(0, 0, 0, 0.05),
+ inset 0 1rpx 2rpx rgba(255, 255, 255, 0.5),
+ inset 0 -1rpx 2rpx rgba(0, 0, 0, 0.05);
+}
+
+/* 按钮悬浮光晕效果 */
+.btn::after {
+ content: '';
+ position: absolute;
+ top: -50%;
+ left: -50%;
+ width: 200%;
+ height: 200%;
+ background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.3), transparent);
+ transform: rotate(45deg);
+ animation: shine 3s infinite;
+ opacity: 0;
+}
+
+@keyframes shine {
+ 0% { transform: translateX(-100%) rotate(45deg); opacity: 0; }
+ 50% { opacity: 0.2; }
+ 100% { transform: translateX(100%) rotate(45deg); opacity: 0; }
+}
+
+.btn:active::after {
+ animation: none;
+}
+
+/* 弹窗样式 */
+.modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.5);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 999;
+}
+
+.modal-container {
+ background-color: white;
+ border-radius: 16rpx;
+ width: 80%;
+ padding: 40rpx;
+}
+
+.modal-title {
+ text-align: center;
+ margin-bottom: 30rpx;
+}
+
+.modal-title text {
+ font-size: 36rpx;
+ font-weight: bold;
+}
+
+.modal-content {
+ text-align: center;
+ margin-bottom: 40rpx;
+ color: #666;
+}
+
+.modal-content text {
+ font-size: 32rpx;
+}
+
+.modal-buttons {
+ text-align: center;
+}
+
+.primary-button {
+ background-color: #1677ff;
+ color: white;
+ width: 100%;
+ border-radius: 8rpx;
+ margin-bottom: 20rpx;
+ border: none;
+}
+
+.cancel-button {
+ background: none;
+ color: #666;
+ border: none;
+}
+
+/* 头像选择样式 */
+.avatar-section {
+ text-align: center;
+ margin-bottom: 40rpx;
+}
+
+.avatar-wrapper {
+ padding: 0;
+ background: none;
+ border: none;
+}
+
+.avatar {
+ width: 160rpx;
+ height: 160rpx;
+ border-radius: 50%;
+}
+
+/* 表单样式 */
+.form-group {
+ margin-bottom: 30rpx;
+}
+
+.form-label {
+ font-size: 28rpx;
+ margin-bottom: 10rpx;
+ display: block;
+}
+
+.form-input {
+ border: 1rpx solid #eee;
+ border-radius: 8rpx;
+ padding: 20rpx;
+ width: 100%;
+ max-width: 100%;
+ box-sizing: border-box;
+ font-size: 28rpx;
+}
+
+.form-actions {
+ text-align: center;
+ margin-top: 40rpx;
+}
+
+.confirm-button {
+ background-color: #07c160;
+ color: white;
+ width: 100%;
+ border-radius: 8rpx;
+ border: none;
+}
+
+/* 登录提示样式 */
+.login-hint {
+ margin-top: 50rpx;
+ font-size: 28rpx;
+ color: #666;
+ text-align: center;
+}
+
+.link-text {
+ color: #1677ff;
+}
+
+/* 标题样式 */
+.title {
+ font-size: 40rpx;
+ font-weight: bold;
+ text-align: center;
+ color: #333;
+ margin-top: 20rpx;
+ margin-bottom: 10rpx;
+}
diff --git a/pages/notopen/index.js b/pages/notopen/index.js
new file mode 100644
index 0000000..f3043a5
--- /dev/null
+++ b/pages/notopen/index.js
@@ -0,0 +1,64 @@
+Page({
+ /**
+ * 页面的初始数据
+ */
+ data: {
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad: function (options) {
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady: function () {
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow: function () {
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide: function () {
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload: function () {
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh: function () {
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom: function () {
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage: function () {
+ },
+
+ /**
+ * 返回首页
+ */
+ onBackTap: function () {
+ wx.switchTab({
+ url: '/pages/index/index'
+ })
+ }
+})
\ No newline at end of file
diff --git a/pages/notopen/index.json b/pages/notopen/index.json
new file mode 100644
index 0000000..464cc72
--- /dev/null
+++ b/pages/notopen/index.json
@@ -0,0 +1,4 @@
+{
+ "navigationBarTitleText": "又鸟蛋平台",
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/pages/notopen/index.wxml b/pages/notopen/index.wxml
new file mode 100644
index 0000000..369b90a
--- /dev/null
+++ b/pages/notopen/index.wxml
@@ -0,0 +1,8 @@
+
+
+
+
+ 功能暂未开放
+ 该功能正在紧张开发中,敬请期待
+
+
\ No newline at end of file
diff --git a/pages/notopen/index.wxss b/pages/notopen/index.wxss
new file mode 100644
index 0000000..c1e7ef7
--- /dev/null
+++ b/pages/notopen/index.wxss
@@ -0,0 +1,69 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100vh;
+ width: 100vw;
+ background-color: #ffffff;
+ padding: 40rpx;
+ box-sizing: border-box;
+ margin: 0;
+}
+
+/* 重置页面默认样式 */
+page {
+ height: 100vh;
+ width: 100vw;
+ margin: 0;
+ padding: 0;
+ background-color: #ffffff;
+}
+
+.icon {
+ margin-bottom: 60rpx;
+}
+
+.lock-icon {
+ width: 120rpx;
+ height: 120rpx;
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-image: url('data:image/svg+xml;utf8,');
+}
+
+.title {
+ font-size: 36rpx;
+ font-weight: bold;
+ color: #333333;
+ margin-bottom: 24rpx;
+}
+
+.subtitle {
+ font-size: 28rpx;
+ color: #999999;
+ margin-bottom: 80rpx;
+ text-align: center;
+}
+
+.back-btn {
+ width: 320rpx;
+ height: 88rpx;
+ background-color: #1989fa;
+ color: white;
+ font-size: 32rpx;
+ border-radius: 44rpx;
+ box-shadow: 0 4rpx 16rpx rgba(25, 137, 250, 0.3);
+ border: none;
+ outline: none;
+}
+
+.back-btn::after {
+ border: none;
+}
+
+.back-btn:active {
+ background-color: #0c7ad9;
+ transform: scale(0.98);
+}
\ No newline at end of file
diff --git a/pages/profile/index.js b/pages/profile/index.js
new file mode 100644
index 0000000..fa0ee99
--- /dev/null
+++ b/pages/profile/index.js
@@ -0,0 +1,652 @@
+// pages/profile/index.js
+Page({
+ data: {
+ userInfo: {},
+ userType: '',
+ userTags: [],
+ needPhoneAuth: false // 是否需要重新授权手机号
+ },
+
+ onLoad() {
+ this.loadUserInfo()
+ },
+
+ onShow() {
+ this.loadUserInfo()
+ // 更新自定义tabBar状态
+ if (typeof this.getTabBar === 'function' && this.getTabBar()) {
+ this.getTabBar().setData({
+ selected: 3
+ });
+ }
+ // 更新全局tab状态
+ const app = getApp();
+ app.updateCurrentTab('profile');
+ },
+
+ // 加载用户信息
+ loadUserInfo() {
+ console.log('开始加载用户信息')
+ const app = getApp()
+
+ // 从本地存储获取用户信息
+ const localUserInfo = wx.getStorageSync('userInfo') || {}
+ if (app.globalData.userInfo) {
+ this.setData({ userInfo: app.globalData.userInfo })
+ } else {
+ app.globalData.userInfo = localUserInfo
+ this.setData({
+ userInfo: localUserInfo,
+ needPhoneAuth: !localUserInfo.phoneNumber || localUserInfo.phoneNumber === '13800138000'
+ })
+ }
+
+ // 加载用户类型和标签
+ const userId = wx.getStorageSync('userId')
+ const openid = wx.getStorageSync('openid')
+ console.log('加载用户信息 - userId:', userId, 'openid:', openid ? '已获取' : '未获取')
+
+ if (userId && openid) {
+ // 从服务器获取最新的用户信息,确保手机号是最新的
+ this.refreshUserInfoFromServer(openid, userId)
+
+ // 确保users存储结构存在
+ let users = wx.getStorageSync('users')
+ if (!users) {
+ users = {}
+ wx.setStorageSync('users', users)
+ }
+
+ if (!users[userId]) {
+ users[userId] = { type: '' }
+ wx.setStorageSync('users', users)
+ }
+
+ const user = users[userId]
+ const currentType = this.formatUserType(user.type)
+ this.setData({ userType: currentType })
+ console.log('加载用户信息 - 当前用户类型:', currentType)
+
+ // 确保tags存储结构存在
+ let tags = wx.getStorageSync('tags')
+ if (!tags) {
+ tags = {}
+ wx.setStorageSync('tags', tags)
+ }
+
+ if (!tags[userId]) {
+ tags[userId] = []
+ wx.setStorageSync('tags', tags)
+ }
+
+ const userTags = tags[userId] || []
+ console.log('加载用户信息 - 原始标签:', userTags)
+
+ // 使用indexOf替代includes以解决Babel兼容性问题
+ let firstCategoryTag = []
+ let identityTags = []
+
+ // 查找第一个偏好品类标签
+ for (let i = 0; i < userTags.length; i++) {
+ if (userTags[i].indexOf('偏好品类') !== -1) {
+ firstCategoryTag = [userTags[i]]
+ break
+ }
+ }
+
+ // 合并保留的标签
+ let filteredTags = [...firstCategoryTag]
+
+ // 始终根据当前用户类型显示对应的身份标签,而不是使用存储的标签
+ if (user.type && user.type !== '') {
+ let identityLabel = '身份:not_set'
+ switch (user.type) {
+ case 'buyer': identityLabel = '身份:buyer'; break
+ case 'seller': identityLabel = '身份:seller'; break
+ case 'both': identityLabel = '身份:buyer+seller'; break
+ }
+ filteredTags.push(identityLabel)
+ console.log('加载用户信息 - 根据当前用户类型显示身份标签:', identityLabel)
+ } else {
+ // 如果没有用户类型,但有存储的身份标签,显示第一个
+ for (let i = 0; i < userTags.length; i++) {
+ if (userTags[i].indexOf('身份') !== -1) {
+ filteredTags.push(userTags[i])
+ console.log('加载用户信息 - 显示存储的身份标签:', userTags[i])
+ break
+ }
+ }
+ }
+
+ console.log('加载用户信息 - 过滤后的标签:', filteredTags)
+ this.setData({ userTags: filteredTags })
+ }
+ },
+
+ // 从服务器刷新用户信息
+ refreshUserInfoFromServer(openid, userId) {
+ const API = require('../../utils/api.js')
+
+ API.getUserInfo(openid).then(res => {
+ console.log('从服务器获取用户信息成功:', res)
+
+ if (res.success && res.data) {
+ const serverUserInfo = res.data
+
+ // 检查手机号是否是临时手机号
+ if (serverUserInfo.phoneNumber === '13800138000') {
+ console.warn('服务器返回的仍是临时手机号,用户可能需要重新授权手机号')
+ // 可以在这里显示提示,让用户重新授权手机号
+ this.setData({
+ needPhoneAuth: true
+ })
+ }
+
+ // 更新本地用户信息
+ const app = getApp()
+ const updatedUserInfo = {
+ ...app.globalData.userInfo,
+ ...serverUserInfo
+ }
+
+ app.globalData.userInfo = updatedUserInfo
+ wx.setStorageSync('userInfo', updatedUserInfo)
+ this.setData({ userInfo: updatedUserInfo })
+
+ console.log('用户信息已更新,昵称:', updatedUserInfo.nickName, '手机号:', updatedUserInfo.phoneNumber)
+ }
+ }).catch(err => {
+ console.error('从服务器获取用户信息失败:', err)
+ // 如果getUserInfo失败,尝试使用validateUserLogin作为备选
+ API.validateUserLogin().then(res => {
+ console.log('使用validateUserLogin获取用户信息成功:', res)
+
+ if (res.success && res.data) {
+ const serverUserInfo = res.data
+
+ // 检查手机号是否是临时手机号
+ if (serverUserInfo.phoneNumber === '13800138000') {
+ console.warn('服务器返回的仍是临时手机号,用户可能需要重新授权手机号')
+ this.setData({
+ needPhoneAuth: true
+ })
+ }
+
+ // 更新本地用户信息
+ const app = getApp()
+ const updatedUserInfo = {
+ ...app.globalData.userInfo,
+ ...serverUserInfo
+ }
+
+ app.globalData.userInfo = updatedUserInfo
+ wx.setStorageSync('userInfo', updatedUserInfo)
+ this.setData({ userInfo: updatedUserInfo })
+
+ console.log('用户信息已更新(备选方案):', updatedUserInfo)
+ }
+ }).catch(validateErr => {
+ console.error('从服务器获取用户信息失败(包括备选方案):', validateErr)
+ // 如果服务器请求失败,继续使用本地缓存的信息
+ })
+ })
+ },
+
+ // 格式化用户类型显示
+ formatUserType(type) {
+ switch (type) {
+ case 'buyer': return '买家'
+ case 'seller': return '卖家'
+ case 'both': return '买家+卖家'
+ default: return '未设置'
+ }
+ },
+
+ // 设置为买家
+ setAsBuyer() {
+ this.switchUserType('buyer', '买家')
+ },
+
+ // 设置为卖家
+ setAsSeller() {
+ this.switchUserType('seller', '卖家')
+ },
+
+ // 切换用户类型的通用方法
+ switchUserType(newType, typeName) {
+ const userId = wx.getStorageSync('userId')
+ const openid = wx.getStorageSync('openid')
+ const userInfo = wx.getStorageSync('userInfo')
+
+ if (!userId || !openid) {
+ wx.navigateTo({ url: '/pages/index/index' })
+ return
+ }
+
+ // 更新本地存储中的用户类型
+ let users = wx.getStorageSync('users') || {}
+ if (!users[userId]) {
+ users[userId] = {}
+ }
+ users[userId].type = newType
+ wx.setStorageSync('users', users)
+
+ // 更新全局数据
+ const app = getApp()
+ app.globalData.userType = newType
+
+ // 上传更新后的用户信息到服务器
+ this.uploadUserTypeToServer(openid, userId, userInfo, newType)
+
+ // 更新页面显示
+ this.setData({
+ userType: this.formatUserType(newType)
+ })
+
+ wx.showToast({
+ title: `已切换为${typeName}`,
+ icon: 'success',
+ duration: 2000
+ })
+ },
+
+ // 上传用户类型到服务器
+ uploadUserTypeToServer(openid, userId, userInfo, type) {
+ // 引入API服务
+ const API = require('../../utils/api.js')
+
+ // 构造上传数据
+ const uploadData = {
+ userId: userId,
+ openid: openid,
+ ...userInfo,
+ type: type,
+ timestamp: Date.now()
+ }
+
+ // 调用API上传用户信息
+ API.uploadUserInfo(uploadData).then(res => {
+ console.log('用户类型更新成功:', res)
+ }).catch(err => {
+ console.error('用户类型更新失败:', err)
+ wx.showToast({
+ title: '身份更新失败,请重试',
+ icon: 'none',
+ duration: 2000
+ })
+ })
+ },
+ // 处理手机号授权结果
+ onPhoneNumberResult(e) {
+ console.log('手机号授权结果:', e)
+
+ // 首先检查用户是否拒绝授权
+ if (e.detail.errMsg !== 'getPhoneNumber:ok') {
+ console.log('用户拒绝授权手机号')
+ wx.showToast({
+ title: '您已拒绝授权,操作已取消',
+ icon: 'none'
+ })
+ // 直接返回,取消所有后续操作
+ return
+ }
+
+ // 用户同意授权,继续执行后续操作
+ // 检查是否有openid,如果没有则先登录
+ const openid = wx.getStorageSync('openid')
+ if (!openid) {
+ console.log('未登录,执行登录流程')
+ // 显示登录loading提示
+ wx.showLoading({ title: '登录中...' })
+ // 调用微信登录接口
+ wx.login({
+ success: loginRes => {
+ if (loginRes.code) {
+ // 引入API服务
+ const API = require('../../utils/api.js')
+ // 获取openid
+ API.getOpenid(loginRes.code)
+ .then(openidRes => {
+ wx.hideLoading()
+ console.log('获取openid响应:', openidRes)
+
+ // 增强版响应处理逻辑,支持多种返回格式
+ let openid = null;
+ let userId = null;
+ let sessionKey = null;
+
+ // 优先从data字段获取数据
+ if (openidRes && openidRes.data && typeof openidRes.data === 'object') {
+ openid = openidRes.data.openid || openidRes.data.OpenID || null;
+ userId = openidRes.data.userId || openidRes.data.userid || null;
+ sessionKey = openidRes.data.session_key || openidRes.data.sessionKey || null;
+ }
+
+ // 如果data为空或不存在,尝试从响应对象直接获取
+ if (!openid && openidRes && typeof openidRes === 'object') {
+ console.warn('服务器返回格式可能不符合预期,data字段为空或不存在,但尝试从根对象提取信息:', openidRes);
+ openid = openidRes.openid || openidRes.OpenID || null;
+ userId = openidRes.userId || openidRes.userid || null;
+ sessionKey = openidRes.session_key || openidRes.sessionKey || null;
+ }
+
+ // 检查服务器状态信息
+ const isSuccess = openidRes && (openidRes.success === true || openidRes.code === 200);
+
+ if (openid) {
+ // 存储openid和session_key
+ wx.setStorageSync('openid', openid)
+ if (sessionKey) {
+ wx.setStorageSync('sessionKey', sessionKey)
+ }
+
+ // 如果有userId,也存储起来
+ if (userId) {
+ wx.setStorageSync('userId', userId)
+ }
+
+ console.log('获取openid成功并存储:', openid)
+
+ // 登录成功,显示提示并重新加载页面
+ wx.showToast({
+ title: '登录成功',
+ icon: 'none'
+ })
+
+ // 在登录成功后重新加载页面
+ wx.reLaunch({
+ url: '/pages/profile/index'
+ })
+ } else {
+ console.error('获取openid失败,响应数据:', openidRes)
+ wx.showToast({
+ title: '登录失败,请重试',
+ icon: 'none'
+ })
+ }
+ })
+ .catch(err => {
+ wx.hideLoading()
+ console.error('获取openid失败:', err)
+ wx.showToast({
+ title: '登录失败,请重试',
+ icon: 'none'
+ })
+ })
+ } else {
+ wx.hideLoading()
+ console.error('微信登录失败:', loginRes)
+ wx.showToast({
+ title: '登录失败,请重试',
+ icon: 'none'
+ })
+ }
+ },
+ fail: err => {
+ wx.hideLoading()
+ console.error('wx.login失败:', err)
+ wx.showToast({
+ title: '获取登录状态失败,操作已取消',
+ icon: 'none'
+ })
+ }
+ })
+ return
+ }
+
+ // 已登录且用户同意授权,获取加密数据
+ const phoneData = e.detail
+
+ wx.showLoading({ title: '获取手机号中...' })
+
+ // 引入API服务
+ const API = require('../../utils/api.js')
+
+ // 上传到服务器解密
+ API.uploadPhoneNumberData(phoneData)
+ .then(res => {
+ wx.hideLoading()
+ if (res.success) {
+ console.log('获取手机号结果:', res)
+
+ // 检查是否有手机号冲突
+ const hasPhoneConflict = res.phoneNumberConflict || false
+ const isNewPhone = res.isNewPhone || true
+ const phoneNumber = res.phoneNumber || null
+
+ // 如果有手机号冲突且没有返回手机号,使用临时手机号
+ const finalPhoneNumber = hasPhoneConflict && !phoneNumber ? '13800138000' : phoneNumber
+
+ if (finalPhoneNumber) {
+ // 保存手机号到用户信息
+ const app = getApp()
+ const userInfo = app.globalData.userInfo || wx.getStorageSync('userInfo') || {}
+ userInfo.phoneNumber = finalPhoneNumber
+
+ // 更新本地和全局用户信息
+ app.globalData.userInfo = userInfo
+ wx.setStorageSync('userInfo', userInfo)
+
+ // 获取userId
+ const userId = wx.getStorageSync('userId')
+ const users = wx.getStorageSync('users') || {}
+ const currentUserType = users[userId] && users[userId].type ? users[userId].type : ''
+
+ // 同时更新服务器用户信息
+ this.uploadUserInfoToServer(userInfo, userId, currentUserType)
+
+ // 更新页面状态
+ this.setData({
+ needPhoneAuth: finalPhoneNumber === '13800138000'
+ })
+
+ // 重新加载用户信息以更新UI
+ this.loadUserInfo()
+ }
+
+ // 根据服务器返回的结果显示不同的提示
+ if (hasPhoneConflict) {
+ wx.showToast({
+ title: '获取成功,但手机号已被其他账号绑定',
+ icon: 'none',
+ duration: 3000
+ })
+ } else {
+ wx.showToast({
+ title: '手机号绑定成功',
+ icon: 'success'
+ })
+ }
+ } else {
+ console.error('获取手机号失败:', res)
+ wx.showToast({
+ title: '获取手机号失败',
+ icon: 'none'
+ })
+ }
+ })
+ .catch(err => {
+ wx.hideLoading()
+ console.error('获取手机号失败:', err)
+ wx.showToast({
+ title: '获取手机号失败',
+ icon: 'none'
+ })
+ })
+ },
+
+ // 上传用户信息到服务器
+ uploadUserInfoToServer(userInfo, userId, type) {
+ // 返回Promise以便调用者可以进行错误处理
+ return new Promise((resolve, reject) => {
+ try {
+ // 引入API服务
+ const API = require('../../utils/api.js')
+
+ // 获取openid
+ const openid = wx.getStorageSync('openid')
+
+ // 验证必要参数
+ if (!userId || !openid) {
+ const error = new Error('缺少必要的用户信息');
+ console.error('用户信息上传失败:', error);
+ reject(error);
+ return;
+ }
+
+ // 构造上传数据(包含所有必要字段,包括phoneNumber)
+ const uploadData = {
+ userId: userId,
+ openid: openid,
+ nickName: userInfo.nickName,
+ phoneNumber: userInfo.phoneNumber, // 添加phoneNumber字段,满足服务器要求
+ type: type,
+ timestamp: Date.now()
+ }
+
+ // 调用API上传用户信息
+ API.uploadUserInfo(uploadData).then(res => {
+ console.log('用户信息上传成功:', res)
+ resolve(res);
+ }).catch(err => {
+ console.error('用户信息上传失败:', err)
+ reject(err);
+ })
+ } catch (error) {
+ console.error('上传用户信息时发生异常:', error);
+ reject(error);
+ }
+ });
+ },
+
+ // 修改用户名称
+ onEditNickName() {
+ const currentName = this.data.userInfo.nickName || '未登录';
+
+ wx.showModal({
+ title: '修改用户名称',
+ editable: true,
+ placeholderText: '请输入新的名称最多10个字符',
+ confirmText: '确认',
+ cancelText: '取消',
+ success: (res) => {
+ if (res.confirm) {
+ // 移除首尾空格并过滤多余空格
+ let newName = res.content.trim();
+ newName = newName.replace(/\s+/g, ' ');
+
+ // 验证昵称不能为空
+ if (!newName) {
+ wx.showToast({
+ title: '名称不能为空',
+ icon: 'none',
+ duration: 2000
+ });
+ return;
+ }
+
+ // 验证昵称长度
+ if (newName.length > 10) {
+ wx.showToast({
+ title: '名称长度不能超过10个字符',
+ icon: 'none',
+ duration: 2000
+ });
+ return;
+ }
+
+ // 检查名称是否变化
+ if (newName === currentName) {
+ wx.showToast({
+ title: '名称未变化',
+ icon: 'none',
+ duration: 2000
+ });
+ return;
+ }
+
+ // 显示加载提示
+ wx.showLoading({
+ title: '正在更新...',
+ mask: true
+ });
+
+ // 更新用户信息
+ this.updateNickName(newName).finally(() => {
+ // 无论成功失败,都隐藏加载提示
+ wx.hideLoading();
+ });
+ }
+ }
+ });
+ },
+
+ // 更新用户名称
+ updateNickName(newName) {
+ return new Promise((resolve, reject) => {
+ try {
+ // 更新本地和全局用户信息
+ const app = getApp();
+ const updatedUserInfo = {
+ ...this.data.userInfo,
+ nickName: newName
+ };
+
+ // 保存到本地存储和全局状态
+ app.globalData.userInfo = updatedUserInfo;
+ wx.setStorageSync('userInfo', updatedUserInfo);
+
+ // 更新页面显示
+ this.setData({
+ userInfo: updatedUserInfo
+ });
+
+ // 更新服务器信息
+ const userId = wx.getStorageSync('userId');
+ const currentUserType = this.data.userType;
+
+ // 如果有用户ID,则上传到服务器
+ if (userId) {
+ // 使用Promise链处理上传
+ this.uploadUserInfoToServer(updatedUserInfo, userId, currentUserType)
+ .then(() => {
+ wx.showToast({
+ title: '名称修改成功',
+ icon: 'success',
+ duration: 2000
+ });
+ resolve();
+ })
+ .catch((err) => {
+ console.error('服务器同步失败,但本地已更新:', err);
+ // 即使服务器同步失败,本地也已成功更新
+ wx.showToast({
+ title: '本地更新成功,服务器同步稍后进行',
+ icon: 'none',
+ duration: 3000
+ });
+ resolve(); // 即使服务器失败,也视为成功,因为本地已经更新
+ });
+ } else {
+ // 没有用户ID,只更新本地
+ console.warn('没有用户ID,仅更新本地用户名称');
+ wx.showToast({
+ title: '名称修改成功',
+ icon: 'success',
+ duration: 2000
+ });
+ resolve();
+ }
+ } catch (error) {
+ console.error('更新用户名称失败:', error);
+ wx.showToast({
+ title: '更新失败,请稍后重试',
+ icon: 'none',
+ duration: 2000
+ });
+ reject(error);
+ }
+ });
+ },
+
+})
diff --git a/pages/profile/index.json b/pages/profile/index.json
new file mode 100644
index 0000000..3928faa
--- /dev/null
+++ b/pages/profile/index.json
@@ -0,0 +1,3 @@
+{
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/pages/profile/index.wxml b/pages/profile/index.wxml
new file mode 100644
index 0000000..93f8a36
--- /dev/null
+++ b/pages/profile/index.wxml
@@ -0,0 +1,63 @@
+
+
+
+
+
+ {{userInfo.nickName || '未登录'}}
+ 当前身份: {{userType || '未设置'}}
+
+ 手机号: {{userInfo.phoneNumber === '13800138000' ? '临时手机号,请重新授权' : (userInfo.phoneNumber || '未绑定')}}
+
+
+
+
+
+
+
+
+
+
+
+
+ 我的标签
+
+
+ {{item}}
+
+
+
+
+
+ 身份管理
+
+
+
+
diff --git a/pages/profile/index.wxss b/pages/profile/index.wxss
new file mode 100644
index 0000000..8aba164
--- /dev/null
+++ b/pages/profile/index.wxss
@@ -0,0 +1 @@
+/* pages/profile/index.wxss */
\ No newline at end of file
diff --git a/pages/publish/index.js b/pages/publish/index.js
new file mode 100644
index 0000000..a731fec
--- /dev/null
+++ b/pages/publish/index.js
@@ -0,0 +1,588 @@
+// pages/publish/index.js
+// 引入API工具
+const API = require('../../utils/api.js');
+
+// 【终极修复】创建全局上传管理器,完全独立于页面生命周期
+if (!global.ImageUploadManager) {
+ global.ImageUploadManager = {
+ // 存储所有活动的上传任务
+ activeTasks: {},
+ // 深度克隆工具函数
+ deepClone: function(obj) {
+ return JSON.parse(JSON.stringify(obj));
+ },
+ // 核心上传方法
+ upload: function(formData, images, successCallback, failCallback) {
+ console.log('【全局上传管理器】开始上传,图片数量:', images.length);
+
+ // 创建唯一的上传任务ID
+ const taskId = `upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
+
+ // 创建深度克隆,完全隔离数据
+ const clonedFormData = this.deepClone(formData);
+ const clonedImages = this.deepClone(images);
+
+ // 将任务保存到全局状态中,防止页面重新编译时丢失
+ this.activeTasks[taskId] = {
+ id: taskId,
+ formData: clonedFormData,
+ images: clonedImages,
+ status: 'started',
+ startTime: Date.now(),
+ uploadedCount: 0,
+ totalCount: clonedImages.length
+ };
+
+ console.log(`【全局上传管理器】创建任务 ${taskId},已保存到全局状态`);
+
+ // 使用setTimeout完全隔离执行上下文,避免与页面生命周期耦合
+ const self = this;
+ setTimeout(() => {
+ try {
+ console.log('【全局上传管理器】准备调用API.publishProduct');
+ console.log('准备的商品数据:', clonedFormData);
+ console.log('准备的图片数量:', clonedImages.length);
+
+ // 关键修改:使用API.publishProduct方法,这是正确的调用链
+ // 包含所有必要字段
+ const productData = {
+ ...clonedFormData,
+ images: clonedImages, // 直接传递图片数组
+ imageUrls: clonedImages, // 同时设置imageUrls字段
+ // 生成会话ID,确保所有图片关联同一商品
+ sessionId: taskId,
+ uploadSessionId: taskId
+ };
+
+ console.log('最终传递给publishProduct的数据:', Object.keys(productData));
+
+ API.publishProduct(productData)
+ .then(res => {
+ console.log(`【全局上传管理器】任务 ${taskId} 上传完成,响应:`, res);
+
+ // 更新任务状态
+ if (self.activeTasks[taskId]) {
+ self.activeTasks[taskId].status = 'completed';
+ self.activeTasks[taskId].endTime = Date.now();
+ self.activeTasks[taskId].result = res;
+ }
+
+ // 使用setTimeout隔离成功回调的执行
+ setTimeout(() => {
+ if (successCallback) {
+ successCallback(res);
+ }
+ }, 0);
+ })
+ .catch(err => {
+ console.error(`【全局上传管理器】任务 ${taskId} 上传失败:`, err);
+
+ // 更新任务状态
+ if (self.activeTasks[taskId]) {
+ self.activeTasks[taskId].status = 'failed';
+ self.activeTasks[taskId].error = err;
+ self.activeTasks[taskId].endTime = Date.now();
+ }
+
+ // 使用setTimeout隔离失败回调的执行
+ setTimeout(() => {
+ if (failCallback) {
+ failCallback(err);
+ }
+ }, 0);
+ })
+ .finally(() => {
+ // 延迟清理任务,确保所有操作完成
+ setTimeout(() => {
+ if (self.activeTasks[taskId]) {
+ delete self.activeTasks[taskId];
+ console.log(`【全局上传管理器】任务 ${taskId} 已清理`);
+ }
+ }, 10000);
+ });
+ } catch (e) {
+ console.error(`【全局上传管理器】任务 ${taskId} 发生异常:`, e);
+ setTimeout(() => {
+ if (failCallback) {
+ failCallback(e);
+ }
+ }, 0);
+ }
+ }, 0);
+
+ return taskId;
+ },
+
+ // 获取任务状态的方法
+ getTaskStatus: function(taskId) {
+ return this.activeTasks[taskId] || null;
+ },
+
+ // 获取所有活动任务
+ getActiveTasks: function() {
+ return Object.values(this.activeTasks);
+ }
+ };
+}
+
+Page({
+ /**
+ * 页面的初始数据
+ */
+ data: {
+ variety: '', // 品种
+ price: '',
+ quantity: '',
+ grossWeight: '',
+ yolk: '', // 蛋黄
+ specification: '',
+ images: [] // 新增图片数组
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+ // 检查用户是否已登录
+ this.checkLoginStatus();
+ },
+
+ /**
+ * 检查用户登录状态
+ */
+ checkLoginStatus() {
+ const openid = wx.getStorageSync('openid');
+ if (!openid) {
+ wx.showModal({
+ title: '提示',
+ content: '请先登录后再发布商品',
+ showCancel: false,
+ success: (res) => {
+ if (res.confirm) {
+ wx.navigateTo({ url: '/pages/index/index' });
+ }
+ }
+ });
+ }
+ },
+
+ /**
+ * 品种输入处理
+ */
+ onVarietyInput(e) {
+ this.setData({
+ variety: e.detail.value
+ });
+ },
+
+ /**
+ * 蛋黄输入处理
+ */
+ onYolkInput(e) {
+ this.setData({
+ yolk: e.detail.value
+ });
+ },
+
+ /**
+ * 价格输入处理
+ */
+ onPriceInput(e) {
+ // 保存原始字符串值,不进行数字转换
+ this.setData({
+ price: e.detail.value
+ });
+ },
+
+ /**
+ * 数量输入处理
+ */
+ onQuantityInput(e) {
+ const value = parseFloat(e.detail.value);
+ this.setData({
+ quantity: isNaN(value) ? '' : value
+ });
+ },
+
+ /**
+ * 毛重输入处理
+ */
+ onGrossWeightInput(e) {
+ // 直接保存原始字符串值,不进行数字转换
+ this.setData({
+ grossWeight: e.detail.value
+ });
+ },
+
+ /**
+ * 规格输入处理
+ */
+ onSpecificationInput(e) {
+ this.setData({
+ specification: e.detail.value
+ });
+ },
+
+ /**
+ * 表单验证
+ */
+ validateForm() {
+ const { variety, price, quantity } = this.data;
+
+ console.log('表单验证数据 - variety:', variety, 'price:', price, 'quantity:', quantity);
+ console.log('数据类型 - variety:', typeof variety, 'price:', typeof price, 'quantity:', typeof quantity);
+
+ if (!variety || !variety.trim()) {
+ wx.showToast({ title: '请输入品种', icon: 'none' });
+ return false;
+ }
+
+ if (!price || price.trim() === '') {
+ wx.showToast({ title: '请输入有效价格', icon: 'none' });
+ return false;
+ }
+
+ if (quantity === '' || quantity === undefined || quantity === null || quantity <= 0) {
+ wx.showToast({ title: '请输入有效数量', icon: 'none' });
+ return false;
+ }
+
+ console.log('表单验证通过');
+ return true;
+ },
+
+ /**
+ * 发布商品按钮点击事件
+ */
+ onPublishTap() {
+ console.log('发布按钮点击');
+
+ // 检查用户登录状态
+ const openid = wx.getStorageSync('openid');
+ const userInfo = wx.getStorageSync('userInfo');
+ const userId = wx.getStorageSync('userId');
+
+ console.log('检查用户授权状态 - openid:', !!openid, 'userInfo:', !!userInfo, 'userId:', !!userId);
+
+ if (!openid || !userId || !userInfo) {
+ console.log('用户未登录或未授权,引导重新登录');
+ wx.showModal({
+ title: '登录过期',
+ content: '请先授权登录后再发布商品',
+ showCancel: false,
+ confirmText: '去登录',
+ success: (res) => {
+ if (res.confirm) {
+ wx.navigateTo({ url: '/pages/index/index' });
+ }
+ }
+ });
+ return;
+ }
+
+ if (!this.validateForm()) {
+ console.log('表单验证失败');
+ return;
+ }
+
+ const { variety, price, quantity, grossWeight, yolk, specification } = this.data;
+ const images = this.data.images;
+
+ // 构建商品数据,确保价格和数量为字符串类型
+ const productData = {
+ productName: variety.trim(), // 使用品种作为商品名称
+ price: price.toString(),
+ quantity: quantity.toString(),
+ grossWeight: grossWeight !== '' && grossWeight !== null && grossWeight !== undefined ? grossWeight : "",
+ yolk: yolk || '',
+ specification: specification || '',
+ images: images,
+ imageUrls: images,
+ allImageUrls: images,
+ hasMultipleImages: images.length > 1,
+ totalImages: images.length
+ };
+
+ console.log('【关键日志】商品数据:', productData);
+ console.log('【关键日志】图片数量:', images.length);
+
+ // 【终极修复】在上传开始前立即清空表单
+ // 先深度克隆所有数据
+ console.log('【上传前检查】准备克隆数据');
+ const formDataCopy = JSON.parse(JSON.stringify(productData));
+ const imagesCopy = JSON.parse(JSON.stringify(images));
+
+ console.log('【上传前检查】克隆后图片数量:', imagesCopy.length);
+ console.log('【上传前检查】克隆后图片数据:', imagesCopy);
+
+ // 立即清空表单,避免任何状态变化触发重新编译
+ console.log('【上传前检查】清空表单');
+ this.setData({
+ variety: '',
+ price: '',
+ quantity: '',
+ grossWeight: '',
+ yolk: '',
+ specification: '',
+ images: []
+ });
+
+ // 显示加载提示
+ wx.showLoading({ title: '正在上传图片...' });
+
+ // 【终极修复】使用全局上传管理器处理上传,完全脱离页面生命周期
+ // 将所有数据存储到全局对象中,防止被回收
+ console.log('【上传前检查】存储数据到全局对象');
+ global.tempUploadData = {
+ formData: formDataCopy,
+ images: imagesCopy,
+ userId: userId,
+ timestamp: Date.now()
+ };
+
+ // 预先生成会话ID,确保所有图片关联同一个商品
+ const uploadSessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
+ formDataCopy.sessionId = uploadSessionId;
+ formDataCopy.uploadSessionId = uploadSessionId;
+
+ console.log(`【关键修复】预先生成会话ID:`, uploadSessionId);
+ console.log(`【上传前检查】准备调用全局上传管理器,图片数量:`, imagesCopy.length);
+ console.log(`【上传前检查】传递的formData结构:`, Object.keys(formDataCopy));
+
+ // 【核心修复】直接使用wx.uploadFile API,确保与服务器端测试脚本格式一致
+ console.log(`【核心修复】使用wx.uploadFile API直接上传`);
+
+ // 预先生成会话ID
+ const sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
+ formDataCopy.sessionId = sessionId;
+ formDataCopy.uploadSessionId = sessionId;
+
+ console.log(`【核心修复】使用会话ID:`, sessionId);
+ console.log(`【核心修复】上传图片数量:`, imagesCopy.length);
+
+ // 使用Promise处理上传
+ const uploadPromise = new Promise((resolve, reject) => {
+ // 构建formData,与服务器测试脚本一致
+ const formData = {
+ productData: JSON.stringify(formDataCopy),
+ sessionId: sessionId,
+ uploadSessionId: sessionId,
+ totalImages: imagesCopy.length.toString(),
+ isSingleUpload: 'false' // 关键参数:标记为多图片上传
+ };
+
+ console.log(`【核心修复】准备上传,formData结构:`, Object.keys(formData));
+ console.log(`【核心修复】上传URL:`, API.BASE_URL + '/api/products/upload');
+
+ // 直接使用wx.uploadFile上传第一张图片
+ wx.uploadFile({
+ url: API.BASE_URL + '/api/products/upload',
+ filePath: imagesCopy[0], // 先上传第一张
+ name: 'images',
+ formData: formData,
+ timeout: 180000,
+ success: (res) => {
+ console.log('【核心修复】上传成功,状态码:', res.statusCode);
+ console.log('【核心修复】原始响应:', res.data);
+ try {
+ const data = JSON.parse(res.data);
+ resolve(data);
+ } catch (e) {
+ resolve({data: res.data});
+ }
+ },
+ fail: (err) => {
+ console.error('【核心修复】上传失败:', err);
+ reject(err);
+ }
+ });
+ });
+
+ uploadPromise.then((res) => {
+ // 上传成功回调
+ console.log('【核心修复】上传成功,响应:', res);
+
+ // 使用setTimeout完全隔离回调执行上下文
+ setTimeout(() => {
+ wx.hideLoading();
+
+ // 从全局临时存储获取数据
+ const tempData = global.tempUploadData || {};
+ const localFormData = tempData.formData;
+ const userId = tempData.userId;
+
+ // 【关键修复】从多个来源提取图片URL,确保不丢失
+ let allUploadedImageUrls = [];
+
+ // 尝试从多个位置提取图片URLs
+ if (res.imageUrls && Array.isArray(res.imageUrls) && res.imageUrls.length > 0) {
+ allUploadedImageUrls = [...res.imageUrls];
+ console.log('【全局上传】从res.imageUrls提取到图片:', allUploadedImageUrls.length);
+ }
+
+ if (res.product && res.product.imageUrls && Array.isArray(res.product.imageUrls) && res.product.imageUrls.length > 0) {
+ allUploadedImageUrls = [...res.product.imageUrls];
+ console.log('【全局上传】从res.product.imageUrls提取到图片:', allUploadedImageUrls.length);
+ }
+
+ if (res.data && res.data.imageUrls && Array.isArray(res.data.imageUrls) && res.data.imageUrls.length > 0) {
+ allUploadedImageUrls = [...res.data.imageUrls];
+ console.log('【全局上传】从res.data.imageUrls提取到图片:', allUploadedImageUrls.length);
+ }
+
+ // 去重处理,确保URL不重复
+ allUploadedImageUrls = [...new Set(allUploadedImageUrls)];
+
+ console.log('【全局上传】最终去重后的图片URL列表:', allUploadedImageUrls);
+ console.log('【全局上传】最终图片数量:', allUploadedImageUrls.length);
+
+ // 获取卖家信息
+ const users = wx.getStorageSync('users') || {};
+ const sellerName = users[userId] && users[userId].info && users[userId].info.nickName ? users[userId].info.nickName : '未知卖家';
+
+ // 保存到本地存储
+ setTimeout(() => {
+ // 获取当前已有的货源列表
+ const supplies = wx.getStorageSync('supplies') || [];
+ const newId = supplies.length > 0 ? Math.max(...supplies.map(s => s.id)) + 1 : 1;
+ const serverProductId = res.product && res.product.productId ? res.product.productId : '';
+
+ // 创建新的货源记录
+ const newSupply = {
+ id: newId,
+ productId: serverProductId,
+ serverProductId: serverProductId,
+ name: localFormData.productName,
+ productName: localFormData.productName,
+ price: localFormData.price,
+ minOrder: localFormData.quantity,
+ yolk: localFormData.yolk,
+ spec: localFormData.specification,
+ grossWeight: localFormData.grossWeight !== null ? localFormData.grossWeight : '',
+ seller: sellerName,
+ status: res.product && res.product.status ? res.product.status : 'pending_review',
+ imageUrls: allUploadedImageUrls,
+ reservedCount: 0,
+ isReserved: false
+ };
+
+ // 保存到supplies和goods本地存储
+ supplies.push(newSupply);
+ wx.setStorageSync('supplies', supplies);
+
+ const goods = wx.getStorageSync('goods') || [];
+ const newGoodForBuyer = {
+ id: String(newId),
+ productId: String(serverProductId),
+ name: localFormData.productName,
+ productName: localFormData.productName,
+ price: localFormData.price,
+ minOrder: localFormData.quantity,
+ yolk: localFormData.yolk,
+ spec: localFormData.specification,
+ grossWeight: localFormData.grossWeight !== null ? localFormData.grossWeight : '',
+ displayGrossWeight: localFormData.grossWeight !== null ? localFormData.grossWeight : '',
+ seller: sellerName,
+ status: res.product && res.product.status ? res.product.status : 'pending_review',
+ imageUrls: allUploadedImageUrls,
+ reservedCount: 0,
+ isReserved: false
+ };
+ goods.push(newGoodForBuyer);
+ wx.setStorageSync('goods', goods);
+
+ // 显示成功提示
+ setTimeout(() => {
+ wx.showModal({
+ title: '发布成功',
+ content: `所有${allUploadedImageUrls.length}张图片已成功上传!\n请手动返回查看您的商品。\n\n重要:请勿关闭小程序,等待3-5秒确保所有数据处理完成。`,
+ showCancel: false,
+ confirmText: '我知道了',
+ success: function() {
+ // 延迟清理全局临时数据,确保所有操作完成
+ setTimeout(() => {
+ if (global.tempUploadData) {
+ delete global.tempUploadData;
+ }
+ }, 5000);
+ }
+ });
+ }, 500);
+ }, 500);
+ }, 100);
+ })
+ .catch((err) => {
+ // 上传失败回调
+ console.error('【核心修复】上传失败:', err);
+
+ // 使用setTimeout隔离错误处理
+ setTimeout(() => {
+ wx.hideLoading();
+
+ if (err.needRelogin) {
+ wx.showModal({
+ title: '登录状态失效',
+ content: '请重新授权登录',
+ showCancel: false,
+ success: (res) => {
+ if (res.confirm) {
+ wx.removeStorageSync('openid');
+ wx.removeStorageSync('userId');
+ wx.navigateTo({ url: '/pages/login/index' });
+ }
+ }
+ });
+ } else {
+ wx.showToast({ title: err.message || '发布失败,请重试', icon: 'none' });
+ }
+
+ // 清理全局临时数据
+ if (global.tempUploadData) {
+ delete global.tempUploadData;
+ }
+ }, 100);
+ });
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+ // 页面显示时可以刷新数据
+ },
+
+ /**
+ * 选择图片 - 修复版本
+ */
+ chooseImage: function () {
+ const that = this;
+ wx.chooseMedia({
+ count: 5 - that.data.images.length,
+ mediaType: ['image'],
+ sourceType: ['album', 'camera'],
+ success: function (res) {
+ console.log('选择图片成功,返回数据:', res);
+ const tempFiles = res.tempFiles.map(file => file.tempFilePath);
+ that.setData({
+ images: [...that.data.images, ...tempFiles]
+ });
+ console.log('更新后的图片数组:', that.data.images);
+ },
+ fail: function (err) {
+ console.error('选择图片失败:', err);
+ }
+ });
+ },
+
+ /**
+ * 删除图片
+ */
+ deleteImage: function (e) {
+ const index = e.currentTarget.dataset.index;
+ const images = this.data.images;
+ images.splice(index, 1);
+ this.setData({
+ images: images
+ });
+ }
+});
\ No newline at end of file
diff --git a/pages/publish/index.json b/pages/publish/index.json
new file mode 100644
index 0000000..3928faa
--- /dev/null
+++ b/pages/publish/index.json
@@ -0,0 +1,3 @@
+{
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/pages/publish/index.wxml b/pages/publish/index.wxml
new file mode 100644
index 0000000..e19d1db
--- /dev/null
+++ b/pages/publish/index.wxml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+ 品种 *
+
+
+
+
+ 价格 (元/斤) *
+
+
+
+
+ 数量 (斤) *
+
+
+
+
+ 毛重 (斤)
+
+
+
+
+ 蛋黄
+
+
+
+
+ 规格
+
+
+
+
+
+ 商品图片(最多5张)
+
+
+
+ ×
+
+
+ +
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/publish/index.wxss b/pages/publish/index.wxss
new file mode 100644
index 0000000..ab7390d
--- /dev/null
+++ b/pages/publish/index.wxss
@@ -0,0 +1,117 @@
+/* pages/publish/index.wxss */
+.publish-container {
+ padding: 20rpx;
+ background-color: #f8f8f8;
+ min-height: 100vh;
+}
+
+.publish-header {
+ background-color: #fff;
+ padding: 30rpx;
+ border-radius: 10rpx;
+ margin-bottom: 20rpx;
+ box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
+}
+
+.header-title {
+ font-size: 36rpx;
+ font-weight: bold;
+ color: #333;
+}
+
+.form-container {
+ background-color: #fff;
+ padding: 30rpx;
+ border-radius: 10rpx;
+ box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
+}
+
+.form-item {
+ margin-bottom: 30rpx;
+}
+
+.label {
+ display: block;
+ font-size: 28rpx;
+ color: #666;
+ margin-bottom: 10rpx;
+}
+
+.input {
+ width: 100%;
+ height: 80rpx;
+ border: 1rpx solid #ddd;
+ border-radius: 8rpx;
+ padding: 0 20rpx;
+ font-size: 28rpx;
+ box-sizing: border-box;
+}
+
+/* 图片上传样式 */
+.image-upload-container {
+ margin-bottom: 30rpx;
+}
+
+.image-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20rpx;
+}
+
+.image-item {
+ width: 160rpx;
+ height: 160rpx;
+ position: relative;
+ border: 1rpx solid #ddd;
+ border-radius: 8rpx;
+ overflow: hidden;
+}
+
+.image-item image {
+ width: 100%;
+ height: 100%;
+}
+
+.image-delete {
+ position: absolute;
+ top: 0;
+ right: 0;
+ width: 40rpx;
+ height: 40rpx;
+ background-color: rgba(0, 0, 0, 0.5);
+ color: #fff;
+ text-align: center;
+ line-height: 40rpx;
+ font-size: 32rpx;
+ border-radius: 0 8rpx 0 20rpx;
+}
+
+.image-upload {
+ width: 160rpx;
+ height: 160rpx;
+ border: 2rpx dashed #ddd;
+ border-radius: 8rpx;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: #f8f8f8;
+}
+
+.image-upload text {
+ font-size: 64rpx;
+ color: #999;
+}
+
+.publish-btn {
+ margin-top: 40rpx;
+ background-color: #07c160;
+ color: #fff;
+ font-size: 32rpx;
+ height: 90rpx;
+ line-height: 90rpx;
+ border-radius: 45rpx;
+}
+
+.publish-btn:active {
+ background-color: #06b356;
+}
\ No newline at end of file
diff --git a/pages/seller/index.js b/pages/seller/index.js
new file mode 100644
index 0000000..f692dd8
--- /dev/null
+++ b/pages/seller/index.js
@@ -0,0 +1,3333 @@
+// pages/seller/index.js
+const API = require('../../utils/api.js')
+
+Page({
+ data: {
+ supplies: [],
+ publishedSupplies: [],
+ pendingSupplies: [], // 审核中的货源
+ rejectedSupplies: [], // 审核失败的货源
+ draftSupplies: [],
+ showModal: false,
+ showEditModal: false,
+ showRejectReasonModal: false, // 控制审核失败原因弹窗显示
+ currentRejectSupply: null, // 当前显示的审核失败货源
+ rejectReason: '', // 审核失败原因
+ showTabBar: true, // 控制底部自定义tab-bar的显示状态
+ showSpecSelectModal: false, // 控制规格选择弹窗显示
+ modalSpecSearchKeyword: '', // 规格弹窗中的搜索关键词
+ filteredModalSpecOptions: [], // 弹窗中过滤后的规格选项
+ selectedModalSpecIndex: -1, // 弹窗中选中的规格索引
+ currentSpecMode: 'create', // 当前规格选择模式:create 或 edit
+ showNameSelectModal: false, // 控制商品名称选择弹窗显示
+ showYolkSelectModal: false, // 控制蛋黄选择弹窗显示
+ selectedNameIndex: -1, // 商品名称弹窗中选中的索引
+ selectedYolkIndex: -1,//蛋黄弹窗中选中的索引,
+ // 商品名称选项列表
+ productNameOptions: ['罗曼粉', '伊莎粉', '罗曼灰', '海蓝灰', '海蓝褐', '绿壳', '粉一', '粉二', '粉八', '京粉1号', '京红', '京粉6号', '京粉3号', '农大系列', '黑鸡土蛋', '双黄蛋', '大午金凤', '黑凤'],
+ // 蛋黄选项
+ yolkOptions: ['红心', '黄心', '双色'],
+ // 规格选项
+ specOptions: ['格子装', '散托', '不限规格','净重47+', '净重46-47', '净重45-46', '净重44-45', '净重43-44', '净重42-43', '净重41-42', '净重40-41', '净重39-40', '净重38-39', '净重37-39','净重37-38' , '净重36-38', '净重36-37', '净重35-36', '净重34-35', '净重33-34', '净重32-33', '净重32-34', '净重31-32', '净重30-35', '净重30-34', '净重30-32', '净重30-31', '净重29-31', '净重29-30', '净重28-29', '净重28以下', '毛重52以上', '毛重50-51', '毛重48-49', '毛重47-48', '毛重46-47', '毛重45-47', '毛重45-46', '毛重44-45', '毛重43-44', '毛重42-43', '毛重41-42', '毛重40-41', '毛重38-39', '毛重36-37', '毛重34-35', '毛重32-33', '毛重30-31', '毛重30以下'],
+ // 规格搜索相关变量
+ specSearchKeyword: '', // 创建货源弹窗中的规格搜索关键词
+ editSpecSearchKeyword: '', // 编辑货源弹窗中的规格搜索关键词
+ filteredSpecOptions: [], // 过滤后的规格选项数组
+ filteredEditSpecOptions: [], // 编辑货源过滤后的规格选项数组
+ newSupply: {
+ name: '', // 品种
+ price: '',
+ minOrder: '',
+ yolk: '', // 蛋黄字段
+ yolkIndex: 0, // 蛋黄选项索引
+ spec: '', // 规格字段
+ specIndex: 0, // 规格选项索引
+ region: '', // 【新增】地区字段
+ grossWeight: '', // 【新增】毛重字段,支持中文
+ imageUrls: [] // 图片URL数组,支持多张图片
+ },
+ editSupply: {
+ yolkIndex: 0,
+ specIndex: 0
+ },
+ currentImageIndex: 0, // 用于滑动时记录当前图片索引
+ searchKeyword: '', // 搜索关键词
+ // 图片缩放相关数据
+ scale: 1, // 缩放比例
+ offsetX: 0, // X轴偏移
+ offsetY: 0, // Y轴偏移
+ lastDistance: 0, // 上一次两指距离
+ lastTouchPoint: null, // 上一次触摸点
+ imageWidth: 375, // 图片原始宽度
+ imageHeight: 375, // 图片原始高度
+ minScale: 1, // 最小缩放比例
+ maxScale: 4, // 最大缩放比例
+ doubleTapTimeout: null, // 双击超时计时器
+ doubleTapCount: 0, // 双击计数
+
+
+ // 分页相关数据
+ pagination: {
+ published: {
+ page: 1,
+ pageSize: 20,
+ hasMore: true,
+ loading: false
+ },
+ pending: {
+ page: 1,
+ pageSize: 20,
+ hasMore: true,
+ loading: false
+ },
+ rejected: {
+ page: 1,
+ pageSize: 20,
+ hasMore: true,
+ loading: false
+ },
+ draft: {
+ page: 1,
+ pageSize: 20,
+ hasMore: true,
+ loading: false
+ }
+ },
+
+ // 当前正在加载的状态类型
+ currentLoadingType: null,
+
+ // 图片预览相关状态
+ showImagePreview: false, // 控制图片预览弹窗显示
+ previewImageUrls: [], // 预览的图片URL列表
+ previewImageIndex: 0, // 当前预览图片的索引
+
+ // 折叠状态控制
+ isPublishedExpanded: true, // 已上架货源是否展开
+ isPendingExpanded: true, // 审核中货源是否展开
+ isRejectedExpanded: true, // 审核失败货源是否展开
+ isDraftExpanded: true, // 下架状态货源是否展开
+
+ // 自动发布控制
+ autoPublishAfterEdit: false, // 编辑后是否自动发布(上架)
+
+ // 页面加载状态控制
+ _hasLoadedOnShow: false, // 标记onShow是否已经加载过数据
+
+ // 页面滚动锁定状态
+ pageScrollLock: false, // 控制页面是否锁定滚动
+ touchMoveBlocked: false, // iOS设备触摸事件阻止
+
+ // 授权登录相关状态
+ showAuthModal: false, // 控制未授权提示弹窗显示
+ showOneKeyLoginModal: false, // 控制一键登录弹窗显示
+ pendingUserType: 'seller', // 记录用户即将选择的身份类型
+ avatarUrl: '/images/default-avatar.png' // 默认头像
+ },
+
+ onLoad() {
+ console.log('卖家页面onLoad开始执行');
+ // 移除强制登录检查,允许用户浏览货源页面
+ // 只有在创建新货源时才检查登录状态
+ this.loadSupplies();
+
+ // 初始化规格搜索相关数据
+ this.setData({
+ specSearchKeyword: '',
+ editSpecSearchKeyword: '',
+ filteredSpecOptions: this.data.specOptions,
+ filteredEditSpecOptions: this.data.specOptions
+ });
+
+ console.log('卖家页面onLoad执行完毕');
+ },
+
+ // 重新登录方法 - 跳转到登录页面
+ reLogin() {
+ console.log('执行reLogin方法,跳转到登录页面');
+ wx.showToast({
+ title: '请先登录',
+ icon: 'none',
+ duration: 2000,
+ complete: () => {
+ setTimeout(() => {
+ wx.switchTab({
+ url: '/pages/index/index'
+ });
+ }, 2000);
+ }
+ });
+ },
+
+ // 轮播图切换事件
+ swiperChange: function (e) {
+ const current = e.detail.current;
+ const id = e.currentTarget.dataset.id;
+
+ if (!id) {
+ console.error('swiperChange: 缺少商品ID');
+ return;
+ }
+
+ console.log(`商品 ${id} 的轮播图切换到第 ${current} 张`);
+
+ // 更新特定商品的当前图片索引
+ this.updateProductCurrentIndex(id, current);
+ },
+
+ // 更新商品当前图片索引
+ updateProductCurrentIndex: function (productId, index) {
+ // 更新所有货源列表中的对应商品
+ const updateSupplies = (supplies) => {
+ return supplies.map(supply => {
+ if (supply.id === productId) {
+ return {
+ ...supply,
+ currentImageIndex: index
+ };
+ }
+ return supply;
+ });
+ };
+
+ this.setData({
+ supplies: updateSupplies(this.data.supplies),
+ publishedSupplies: updateSupplies(this.data.publishedSupplies),
+ pendingSupplies: updateSupplies(this.data.pendingSupplies),
+ rejectedSupplies: updateSupplies(this.data.rejectedSupplies),
+ draftSupplies: updateSupplies(this.data.draftSupplies)
+ });
+ },
+
+ // 切换已上架货源的折叠状态
+ togglePublishedExpand() {
+ this.setData({
+ isPublishedExpanded: !this.data.isPublishedExpanded
+ });
+ },
+
+ // 切换审核中货源的折叠状态
+ togglePendingExpand() {
+ this.setData({
+ isPendingExpanded: !this.data.isPendingExpanded
+ });
+ },
+
+ // 切换审核失败货源的折叠状态
+ toggleRejectedExpand() {
+ this.setData({
+ isRejectedExpanded: !this.data.isRejectedExpanded
+ });
+ },
+
+ // 切换下架状态货源的折叠状态
+ toggleDraftExpand() {
+ this.setData({
+ isDraftExpanded: !this.data.isDraftExpanded
+ });
+ },
+
+ // 处理搜索输入
+ onSearchInput(e) {
+ this.setData({
+ searchKeyword: e.detail.value
+ });
+ },
+
+ // 搜索货源
+ searchSupplies() {
+ console.log('搜索货源,关键词:', this.data.searchKeyword);
+
+ // 根据搜索关键词过滤所有状态的货源
+ const keyword = this.data.searchKeyword.toLowerCase().trim();
+ if (!keyword) {
+ // 如果关键词为空,重新加载所有数据
+ this.loadSupplies();
+ return;
+ }
+
+ // 获取所有货源
+ const allSupplies = this.data.supplies;
+
+ // 过滤符合条件的货源
+ const filteredSupplies = allSupplies.filter(supply => {
+ // 搜索名称、品种等字段
+ const name = (supply.name || '').toLowerCase();
+ const productName = (supply.productName || '').toLowerCase();
+ const yolk = (supply.yolk || '').toLowerCase();
+ const spec = (supply.spec || '').toLowerCase();
+
+ return name.includes(keyword) ||
+ productName.includes(keyword) ||
+ yolk.includes(keyword) ||
+ spec.includes(keyword);
+ });
+
+ // 将过滤后的货源按照状态分类
+ const publishedSupplies = filteredSupplies.filter(s => s.status === 'published');
+ const pendingSupplies = filteredSupplies.filter(s => s.status === 'pending_review');
+ const rejectedSupplies = filteredSupplies.filter(s => s.status === 'rejected');
+ const draftSupplies = filteredSupplies.filter(s => s.status === 'draft');
+
+ // 更新UI显示
+ this.setData({
+ publishedSupplies,
+ pendingSupplies,
+ rejectedSupplies,
+ draftSupplies
+ });
+
+ // 显示搜索结果提示
+ wx.showToast({
+ title: `找到${filteredSupplies.length}个货源`,
+ icon: 'none',
+ duration: 1500
+ });
+ },
+
+ // 下拉刷新处理函数
+ onPullDownRefresh() {
+ console.log('====== 触发下拉刷新 ======');
+
+ // 重新加载所有货源数据
+ this.loadSupplies()
+ .then(() => {
+ console.log('下拉刷新数据加载成功');
+ wx.showToast({
+ title: '刷新成功',
+ icon: 'success',
+ duration: 1500
+ });
+ })
+ .catch(err => {
+ console.error('下拉刷新数据加载失败:', err);
+ wx.showToast({
+ title: '刷新失败,请重试',
+ icon: 'none',
+ duration: 2000
+ });
+ })
+ .finally(() => {
+ console.log('====== 下拉刷新动画停止 ======');
+ wx.stopPullDownRefresh();
+ });
+ },
+
+ onShow() {
+ console.log('seller页面onShow开始加载')
+ // 检查页面是否是初次加载(onLoad已调用loadSupplies)
+ // 避免在页面初次加载时重复加载数据
+ if (!this.data._hasLoadedOnShow) {
+ this.setData({
+ _hasLoadedOnShow: true
+ });
+ // 为了避免onLoad和onShow的重复加载,这里不立即调用
+ // 而是在短暂延迟后调用,确保不会与onLoad的加载冲突
+ setTimeout(() => {
+ this.loadSupplies();
+ }, 500);
+ } else {
+ // 页面不是初次显示,正常加载数据
+ this.loadSupplies();
+ }
+
+ // 更新自定义tabBar状态
+ if (typeof this.getTabBar === 'function' && this.getTabBar()) {
+ this.getTabBar().setData({
+ selected: 2
+ });
+ }
+ // 更新全局tab状态
+ const app = getApp();
+ app.updateCurrentTab('seller');
+ },
+
+ // 加载货源列表并分类 - 修改为分页加载
+ loadSupplies() {
+ console.log('开始加载货源数据 - 分页模式');
+
+ // 重置所有分页状态
+ this.resetAllPagination();
+
+ // 并行加载所有类型的货源
+ return Promise.all([
+ this.loadSuppliesFromServer('published', 1),
+ this.loadSuppliesFromServer('pending', 1),
+ this.loadSuppliesFromServer('rejected', 1),
+ this.loadSuppliesFromServer('draft', 1)
+ ]).then(results => {
+ console.log('所有类型货源加载完成');
+ return results;
+ }).catch(err => {
+ console.error('加载货源失败:', err);
+ throw err;
+ });
+ },
+
+ // 重置所有分页状态
+ resetAllPagination() {
+ this.setData({
+ 'pagination.published.page': 1,
+ 'pagination.published.hasMore': true,
+ 'pagination.published.loading': false,
+
+ 'pagination.pending.page': 1,
+ 'pagination.pending.hasMore': true,
+ 'pagination.pending.loading': false,
+
+ 'pagination.rejected.page': 1,
+ 'pagination.rejected.hasMore': true,
+ 'pagination.rejected.loading': false,
+
+ 'pagination.draft.page': 1,
+ 'pagination.draft.hasMore': true,
+ 'pagination.draft.loading': false,
+
+ currentLoadingType: null
+ });
+ },
+
+ // 搜索货源 - 修改为使用本地数据
+ searchSupplies() {
+ console.log('搜索货源,关键词:', this.data.searchKeyword);
+
+ const keyword = this.data.searchKeyword.toLowerCase().trim();
+ if (!keyword) {
+ // 如果关键词为空,重新加载所有数据
+ this.loadSupplies();
+ return;
+ }
+
+ // 从所有货源中搜索
+ const allSupplies = this.data.supplies;
+
+ // 过滤符合条件的货源
+ const filteredSupplies = allSupplies.filter(supply => {
+ const name = (supply.name || '').toLowerCase();
+ const productName = (supply.productName || '').toLowerCase();
+ const yolk = (supply.yolk || '').toLowerCase();
+ const spec = (supply.spec || '').toLowerCase();
+
+ return name.includes(keyword) ||
+ productName.includes(keyword) ||
+ yolk.includes(keyword) ||
+ spec.includes(keyword);
+ });
+
+ // 将过滤后的货源按照状态分类
+ const publishedSupplies = filteredSupplies.filter(s => s.status === 'published');
+ const pendingSupplies = filteredSupplies.filter(s => s.status === 'pending_review' || s.status === 'reviewed');
+ const rejectedSupplies = filteredSupplies.filter(s => s.status === 'rejected');
+ const draftSupplies = filteredSupplies.filter(s => s.status === 'draft' || s.status === 'sold_out');
+
+ // 更新UI显示
+ this.setData({
+ publishedSupplies,
+ pendingSupplies,
+ rejectedSupplies,
+ draftSupplies
+ });
+
+ // 显示搜索结果提示
+ wx.showToast({
+ title: `找到${filteredSupplies.length}个货源`,
+ icon: 'none',
+ duration: 1500
+ });
+ },
+
+ // 修改图片URL处理函数
+ processImageUrls: function (imageUrls) {
+ if (!imageUrls || !Array.isArray(imageUrls)) {
+ return [];
+ }
+
+ return imageUrls.map(url => {
+ if (!url || typeof url !== 'string') return '';
+
+ let processedUrl = url.trim();
+
+ // 处理占位符URL - 替换为本地默认图片
+ if (processedUrl.startsWith('placeholder://')) {
+ console.log('检测到占位符URL,替换为默认图片:', processedUrl);
+ return '/images/default-product.png'; // 使用本地默认图片
+ }
+
+ // 处理临时文件路径
+ if (processedUrl.startsWith('http://tmp/') || processedUrl.startsWith('wxfile://')) {
+ console.log('检测到临时文件路径,保持原样:', processedUrl);
+ return processedUrl;
+ }
+
+ // 确保HTTP URL格式正确
+ if (processedUrl.startsWith('//')) {
+ processedUrl = 'https:' + processedUrl;
+ } else if (!processedUrl.startsWith('http') && !processedUrl.startsWith('/')) {
+ // 如果是相对路径但没有斜杠,添加斜杠
+ processedUrl = '/' + processedUrl;
+ }
+
+ return processedUrl;
+ }).filter(url => url && url !== '');
+ },
+
+
+
+ // 直接从服务器获取货源数据并显示 - 支持分页
+ loadSuppliesFromServer(type = 'all', page = 1) {
+ return new Promise((resolve, reject) => {
+ const openid = wx.getStorageSync('openid');
+ console.log(`loadSuppliesFromServer - type: ${type}, page: ${page}, openid:`, openid);
+
+ if (!openid) {
+ console.warn('openid不存在,显示空数据状态,允许用户浏览页面');
+ // 未登录状态下显示空数据,不跳转,允许用户浏览页面
+ this.setData({
+ supplies: [],
+ publishedSupplies: [],
+ pendingSupplies: [],
+ rejectedSupplies: [],
+ draftSupplies: []
+ });
+
+ resolve([]);
+ return;
+ }
+
+ console.log(`开始从服务器获取${type}类型商品数据,第${page}页`);
+
+ // 根据类型设置请求参数
+ let status = [];
+ let pageSize = 20;
+
+ switch (type) {
+ case 'published':
+ status = ['published'];
+ pageSize = this.data.pagination.published.pageSize;
+ this.setData({
+ 'pagination.published.loading': true,
+ currentLoadingType: 'published'
+ });
+ break;
+ case 'pending':
+ status = ['pending_review', 'reviewed'];
+ pageSize = this.data.pagination.pending.pageSize;
+ this.setData({
+ 'pagination.pending.loading': true,
+ currentLoadingType: 'pending'
+ });
+ break;
+ case 'rejected':
+ status = ['rejected'];
+ pageSize = this.data.pagination.rejected.pageSize;
+ this.setData({
+ 'pagination.rejected.loading': true,
+ currentLoadingType: 'rejected'
+ });
+ break;
+ case 'draft':
+ status = ['draft', 'sold_out'];
+ pageSize = this.data.pagination.draft.pageSize;
+ this.setData({
+ 'pagination.draft.loading': true,
+ currentLoadingType: 'draft'
+ });
+ break;
+ default:
+ // 全部加载,不分类型
+ status = ['all'];
+ pageSize = 100; // 初始加载时使用较大值
+ }
+
+ const requestData = {
+ openid: openid,
+ viewMode: 'seller',
+ status: status,
+ page: page,
+ pageSize: pageSize
+ };
+
+ console.log('请求参数:', requestData);
+
+ API.getAllSupplies(requestData)
+ .then(res => {
+ console.log(`从服务器获取${type}类型数据响应:`, res);
+
+ if (res && res.success && res.products) {
+ console.log(`从服务器获取到${type}类型商品数据,共`, res.products.length, '条');
+
+ // 处理服务器返回的商品数据
+ const serverSupplies = res.products
+ .filter(product => product.status !== 'hidden')
+ .map(serverProduct => {
+ // 状态映射
+ const mappedStatus = serverProduct.status;
+
+ // 处理图片URL
+ let imageUrls = this.processImageUrls(serverProduct.imageUrls);
+
+ // 处理创建时间
+ const createdAt = serverProduct.created_at || null;
+ const formattedCreatedAt = this.formatCreateTime(createdAt);
+
+ return {
+ id: serverProduct.productId,
+ name: serverProduct.productName,
+ price: serverProduct.price,
+ minOrder: serverProduct.quantity,
+ grossWeight: serverProduct.grossWeight,
+ yolk: serverProduct.yolk,
+ spec: serverProduct.specification,
+ region: serverProduct.region || '未知地区', // 【修复】添加默认地区
+ serverProductId: serverProduct.productId,
+ status: mappedStatus,
+ rejectReason: serverProduct.rejectReason || '',
+ imageUrls: imageUrls,
+ created_at: createdAt,
+ formattedCreatedAt: formattedCreatedAt,
+ currentImageIndex: 0
+ };
+ });
+
+ // 根据类型更新数据
+ this.updateSuppliesByType(type, serverSupplies, res, page);
+
+ resolve(serverSupplies);
+ } else {
+ console.log(`服务器没有返回${type}类型商品数据或返回格式不正确`);
+ this.handleNoData(type);
+ resolve([]);
+ }
+ })
+ .catch(err => {
+ console.error(`从服务器获取${type}类型数据失败:`, err);
+ this.handleLoadError(type, err);
+ reject(err);
+ })
+ .finally(() => {
+ // 重置加载状态
+ this.resetLoadingState(type);
+ });
+ });
+ },
+
+ // 根据类型更新货源数据
+ updateSuppliesByType(type, newSupplies, response, currentPage) {
+ const paginationKey = `pagination.${type}`;
+
+ // 更新分页信息
+ const hasMore = currentPage < (response.totalPages || 1);
+ this.setData({
+ [`${paginationKey}.hasMore`]: hasMore,
+ [`${paginationKey}.page`]: currentPage
+ });
+
+ // 更新货源列表
+ if (currentPage === 1) {
+ // 第一页,直接替换
+ this.setData({
+ [`${type}Supplies`]: newSupplies
+ });
+ } else {
+ // 后续页面,追加数据
+ const existingSupplies = this.data[`${type}Supplies`] || [];
+ const updatedSupplies = [...existingSupplies, ...newSupplies];
+ this.setData({
+ [`${type}Supplies`]: updatedSupplies
+ });
+ }
+
+ // 更新总列表(用于搜索等功能)
+ this.updateAllSupplies();
+
+ console.log(`更新${type}类型货源完成,当前数量:`, this.data[`${type}Supplies`].length, '是否有更多:', hasMore);
+ },
+
+ // 更新所有货源列表(用于搜索)
+ updateAllSupplies() {
+ const allSupplies = [
+ ...this.data.publishedSupplies,
+ ...this.data.pendingSupplies,
+ ...this.data.rejectedSupplies,
+ ...this.data.draftSupplies
+ ];
+
+ this.setData({
+ supplies: allSupplies
+ });
+ },
+
+ // 处理无数据情况
+ handleNoData(type) {
+ const paginationKey = `pagination.${type}`;
+ this.setData({
+ [`${paginationKey}.hasMore`]: false,
+ [`${type}Supplies`]: []
+ });
+ },
+
+ // 处理加载错误
+ handleLoadError(type, err) {
+ const paginationKey = `pagination.${type}`;
+ this.setData({
+ [`${paginationKey}.loading`]: false
+ });
+
+ // 检查是否是用户不存在的错误
+ if (err.message && (err.message.includes('404') || err.message.includes('用户不存在'))) {
+ console.log('用户不存在,跳转到登录页面');
+ wx.showToast({
+ title: '用户不存在,请重新登录',
+ icon: 'none',
+ duration: 2000,
+ success: () => {
+ wx.removeStorageSync('openid');
+ wx.removeStorageSync('userInfo');
+ setTimeout(() => {
+ wx.switchTab({
+ url: '/pages/index/index'
+ });
+ }, 2000);
+ }
+ });
+ }
+ },
+
+ // 重置加载状态
+ resetLoadingState(type) {
+ if (type !== 'all') {
+ this.setData({
+ [`pagination.${type}.loading`]: false,
+ currentLoadingType: null
+ });
+ }
+ },
+
+ // 加载更多货源
+ loadMoreSupplies(type) {
+ const pagination = this.data.pagination[type];
+
+ if (!pagination.hasMore || pagination.loading) {
+ console.log(`没有更多${type}类型数据或正在加载中`);
+ return;
+ }
+
+ console.log(`开始加载更多${type}类型数据,当前页码:`, pagination.page);
+
+ const nextPage = pagination.page + 1;
+ this.loadSuppliesFromServer(type, nextPage)
+ .then(() => {
+ console.log(`加载更多${type}类型数据成功`);
+ })
+ .catch(err => {
+ console.error(`加载更多${type}类型数据失败:`, err);
+ wx.showToast({
+ title: '加载失败,请重试',
+ icon: 'none',
+ duration: 2000
+ });
+ });
+ },
+
+ // 已上架货源加载更多
+ onReachPublishedBottom() {
+ console.log('已上架货源滚动到底部,加载更多');
+ this.loadMoreSupplies('published');
+ },
+
+ // 审核中货源加载更多
+ onReachPendingBottom() {
+ console.log('审核中货源滚动到底部,加载更多');
+ this.loadMoreSupplies('pending');
+ },
+
+ // 审核失败货源加载更多
+ onReachRejectedBottom() {
+ console.log('审核失败货源滚动到底部,加载更多');
+ this.loadMoreSupplies('rejected');
+ },
+
+ // 下架状态货源加载更多
+ onReachDraftBottom() {
+ console.log('下架状态货源滚动到底部,加载更多');
+ this.loadMoreSupplies('draft');
+ },
+
+ // 从服务器同步最新的商品数据 (现在直接使用服务器数据,不再保存到本地存储)
+ syncSuppliesFromServer() {
+ // 调用新的直接从服务器获取数据的方法
+ console.log('syncSuppliesFromServer: 直接从服务器获取最新数据');
+ this.loadSuppliesFromServer();
+ },
+
+ // 从本地存储加载货源数据(已废弃,现在直接从服务器获取)
+ loadSuppliesFromLocal() {
+ console.log('loadSuppliesFromLocal: 已废弃,现在直接从服务器获取数据');
+ this.loadSuppliesFromServer();
+ },
+
+ // 同步货源数据到商品列表 - 移除本地存储操作
+ syncSuppliesToGoods(supplies) {
+ try {
+ console.log('开始同步货源数据到商品列表 - 通过服务器同步')
+
+ // 直接通知服务器同步已上架商品,不操作本地存储
+ // 修复:移除supply.status === 'reviewed',reviewed状态不应被视为已上架
+ const publishedSupplies = supplies.filter(supply =>
+ supply.status === 'published'
+ );
+
+ if (publishedSupplies.length > 0) {
+ // 延迟一小段时间,避免与服务器交互过于频繁
+ setTimeout(() => {
+ // 这里应该有一个API调用,通知服务器同步商品
+ // API.syncPublishedSuppliesToGoods(publishedSupplies)
+ // .then(res => {
+ // console.log('服务器同步商品成功:', res)
+ // })
+ // .catch(err => {
+ // console.error('服务器同步商品失败:', err)
+ // })
+ console.log('已上架商品:', publishedSupplies)
+ }, 500);
+ }
+ } catch (error) {
+ console.error('同步货源到商品列表过程中发生错误:', error)
+ }
+ },
+
+ // 显示一键登录弹窗
+ showOneKeyLogin() {
+ this.setData({
+ showAuthModal: false,
+ showOneKeyLoginModal: true
+ })
+ },
+
+ // 关闭未授权提示弹窗
+ closeAuthModal() {
+ this.setData({ showAuthModal: false })
+ },
+
+ // 关闭一键登录弹窗
+ closeOneKeyLoginModal() {
+ this.setData({ showOneKeyLoginModal: false })
+ },
+
+ // 选择头像
+ onChooseAvatar(e) {
+ const { avatarUrl } = e.detail
+ this.setData({
+ avatarUrl
+ })
+ },
+
+ // 处理昵称提交
+ getUserName(e) {
+ const { nickname } = e.detail.value
+ const type = 'seller' // 卖家页面固定为卖家类型
+
+ if (!nickname) {
+ wx.showToast({
+ title: '请输入昵称',
+ icon: 'none',
+ duration: 2000
+ })
+ return
+ }
+
+ // 创建用户信息对象
+ const userInfo = {
+ nickName: nickname,
+ avatarUrl: this.data.avatarUrl,
+ gender: 0,
+ country: '',
+ province: '',
+ city: '',
+ language: 'zh_CN'
+ }
+
+ // 保存用户信息
+ this.saveUserInfo(userInfo, type)
+
+ // 隐藏表单
+ this.setData({
+ showUserInfoForm: false
+ })
+
+ // 完成设置
+ this.finishSetUserType(type)
+ },
+
+ // 取消用户信息表单
+ cancelUserInfoForm() {
+ this.setData({
+ showUserInfoForm: false
+ })
+ wx.hideLoading()
+ },
+
+ // 处理手机号授权
+ async onGetPhoneNumber(e) {
+ // 打印详细错误信息,方便调试
+ console.log('getPhoneNumber响应:', e.detail)
+
+ // 关闭手机号授权弹窗
+ this.setData({ showOneKeyLoginModal: false })
+
+ // 用户点击拒绝授权
+ if (e.detail.errMsg === 'getPhoneNumber:fail user deny') {
+ wx.showToast({
+ title: '需要授权手机号才能使用',
+ icon: 'none',
+ duration: 2000
+ })
+ return
+ }
+
+ // 处理没有权限的情况
+ if (e.detail.errMsg === 'getPhoneNumber:fail no permission') {
+ wx.showToast({
+ title: '当前环境无法获取手机号权限',
+ icon: 'none',
+ duration: 3000
+ })
+ console.warn('获取手机号权限失败: 请注意,微信小程序获取手机号功能需要满足以下条件:1. 小程序必须完成微信企业认证;2. 需要在小程序后台配置相应权限;3. 必须使用button组件的open-type="getPhoneNumber"触发。')
+ return
+ }
+
+ // 检查是否已经登录,避免重复授权
+ const existingOpenid = wx.getStorageSync('openid')
+ const existingUserId = wx.getStorageSync('userId')
+ const existingUserInfo = wx.getStorageSync('userInfo')
+
+ if (existingOpenid && existingUserId && existingUserInfo && existingUserInfo.phoneNumber !== '13800138000') {
+ console.log('用户已登录且手机号有效,直接完成身份设置')
+ // 直接完成身份设置,跳过重复授权
+ const currentUserType = this.data.pendingUserType || 'seller'
+ this.finishSetUserType(currentUserType)
+ return
+ }
+
+ wx.showLoading({
+ title: '登录中...',
+ mask: true
+ })
+
+ try {
+ if (e.detail.errMsg === 'getPhoneNumber:ok') {
+ // 用户同意授权,实际处理授权流程
+ console.log('用户同意授权获取手机号')
+
+ // 1. 先执行微信登录获取code
+ const loginRes = await new Promise((resolve, reject) => {
+ wx.login({
+ success: resolve,
+ fail: reject
+ })
+ })
+
+ if (!loginRes.code) {
+ throw new Error('获取登录code失败')
+ }
+
+ console.log('获取登录code成功:', loginRes.code)
+
+ // 2. 使用code换取openid
+ const openidRes = await API.getOpenid(loginRes.code)
+
+ let openid = null;
+ let userId = null;
+ console.log('openidRes完整响应:', JSON.stringify(openidRes));
+
+ if (openidRes && typeof openidRes === 'object') {
+ if (openidRes.data && typeof openidRes.data === 'object') {
+ console.log('识别到标准服务器返回格式,从data字段提取信息');
+ openid = openidRes.data.openid || openidRes.data.OpenID || null;
+ userId = openidRes.data.userId || null;
+ } else {
+ console.log('尝试从根对象直接提取openid');
+ openid = openidRes.openid || openidRes.OpenID || null;
+ userId = openidRes.userId || null;
+ }
+ }
+
+ if (!openid) {
+ console.error('无法从服务器响应中提取openid,完整响应:', JSON.stringify(openidRes));
+ throw new Error(`获取openid失败: 服务器返回数据格式可能不符合预期,请检查服务器配置。响应数据为: ${JSON.stringify(openidRes)}`);
+ }
+
+ console.log('获取openid成功:', openid)
+
+ // 3. 存储openid和session_key
+ wx.setStorageSync('openid', openid)
+
+ if (openidRes && openidRes.session_key) {
+ wx.setStorageSync('sessionKey', openidRes.session_key)
+ } else if (openidRes && openidRes.data && openidRes.data.session_key) {
+ wx.setStorageSync('sessionKey', openidRes.data.session_key)
+ }
+
+ if (userId) {
+ wx.setStorageSync('userId', userId)
+ console.log('使用从服务器data字段提取的userId:', userId)
+ } else if (openidRes && openidRes.userId) {
+ wx.setStorageSync('userId', openidRes.userId)
+ console.log('使用服务器根对象中的userId:', openidRes.userId)
+ } else {
+ const tempUserId = 'user_' + Date.now()
+ wx.setStorageSync('userId', tempUserId)
+ console.log('生成临时userId:', tempUserId)
+ }
+
+ // 4. 上传手机号加密数据到服务器解密
+ const phoneData = {
+ ...e.detail,
+ openid: openid
+ }
+
+ console.log('准备上传手机号加密数据到服务器')
+ const phoneRes = await API.uploadPhoneNumberData(phoneData)
+
+ if (!phoneRes || (!phoneRes.success && !phoneRes.phoneNumber)) {
+ if (phoneRes && phoneRes.phoneNumber) {
+ console.warn('服务器返回格式可能不符合预期,但成功获取手机号');
+ } else {
+ throw new Error('获取手机号失败: ' + (phoneRes && phoneRes.message ? phoneRes.message : '未知错误'))
+ }
+ }
+
+ const hasPhoneConflict = phoneRes.phoneNumberConflict || false
+ const isNewPhone = phoneRes.isNewPhone || true
+ const phoneNumber = phoneRes.phoneNumber || null
+ const finalPhoneNumber = hasPhoneConflict && !phoneNumber ? '13800138000' : phoneNumber
+
+ console.log('手机号解密结果:', {
+ phoneNumber: finalPhoneNumber,
+ hasPhoneConflict: hasPhoneConflict,
+ isNewPhone: isNewPhone
+ })
+
+ // 5. 创建临时用户信息并保存
+ const tempUserInfo = {
+ nickName: '微信用户',
+ avatarUrl: this.data.avatarUrl,
+ gender: 0,
+ country: '',
+ province: '',
+ city: '',
+ language: 'zh_CN',
+ phoneNumber: finalPhoneNumber
+ }
+
+ const storedUserId = wx.getStorageSync('userId')
+ const currentUserType = this.data.pendingUserType || 'seller'
+
+ console.log('用户身份类型:', currentUserType)
+
+ if (this.data.pendingUserType) {
+ this.setData({ pendingUserType: null })
+ }
+
+ // 保存用户信息并等待上传完成
+ console.log('开始保存用户信息并上传到服务器...')
+ const uploadResult = await this.saveUserInfo(tempUserInfo, currentUserType)
+ console.log('用户信息保存并上传完成')
+
+ wx.hideLoading()
+
+ if (uploadResult && uploadResult.phoneNumberConflict) {
+ wx.showToast({
+ title: '登录成功,但手机号已被其他账号绑定',
+ icon: 'none',
+ duration: 3000
+ })
+ } else {
+ wx.showToast({
+ title: '登录成功,手机号已绑定',
+ icon: 'success',
+ duration: 2000
+ })
+ }
+
+ // 完成设置并跳转
+ this.finishSetUserType(currentUserType)
+ } else {
+ console.log('手机号授权失败:', e.detail.errMsg)
+ wx.hideLoading()
+ wx.showToast({
+ title: '需要授权手机号才能使用',
+ icon: 'none',
+ duration: 2000
+ })
+ return
+ }
+ } catch (error) {
+ wx.hideLoading()
+ console.error('登录过程中发生错误:', error)
+
+ let errorMsg = '登录失败,请重试'
+ if (error.message.includes('网络')) {
+ errorMsg = '网络连接失败,请检查网络后重试'
+ } else if (error.message.includes('服务器')) {
+ errorMsg = '服务器连接失败,请稍后重试'
+ }
+
+ wx.showToast({
+ title: errorMsg,
+ icon: 'none',
+ duration: 3000
+ })
+
+ try {
+ wx.removeStorageSync('openid')
+ wx.removeStorageSync('sessionKey')
+ wx.removeStorageSync('userId')
+ } catch (e) {
+ console.error('清除临时登录信息失败:', e)
+ }
+ }
+ },
+
+ // 保存用户信息
+ async saveUserInfo(userInfo, type) {
+ try {
+ // 获取userId
+ const userId = wx.getStorageSync('userId')
+
+ // 保存用户信息到本地存储
+ wx.setStorageSync('userInfo', userInfo)
+
+ // 更新用户类型信息
+ let users = wx.getStorageSync('users') || {}
+ users[userId] = {
+ ...users[userId],
+ type: type,
+ userInfo: userInfo,
+ lastLoginTime: Date.now()
+ }
+ wx.setStorageSync('users', users)
+
+ console.log('用户信息保存成功:', userInfo)
+
+ // 上传用户信息到服务器
+ return await this.uploadUserInfoToServer(userInfo, userId, type)
+ } catch (error) {
+ console.error('保存用户信息失败:', error)
+ throw error
+ }
+ },
+
+ // 上传用户信息到服务器
+ async uploadUserInfoToServer(userInfo, userId, type) {
+ const openid = wx.getStorageSync('openid')
+
+ const uploadData = {
+ userId: userId,
+ openid: openid,
+ ...userInfo,
+ type: type,
+ timestamp: Date.now()
+ }
+
+ try {
+ const res = await API.uploadUserInfo(uploadData)
+ console.log('用户信息上传成功:', res)
+ return res
+ } catch (err) {
+ console.error('用户信息上传失败:', err)
+ return {
+ success: true,
+ message: '本地登录成功,服务器连接失败'
+ }
+ }
+ },
+
+ // 完成用户类型设置并跳转
+ finishSetUserType(type) {
+ const userId = wx.getStorageSync('userId')
+
+ // 更新用户类型
+ let users = wx.getStorageSync('users')
+ if (typeof users !== 'object' || users === null) {
+ users = {}
+ }
+ if (!users[userId]) {
+ users[userId] = {}
+ }
+ users[userId].type = type
+ wx.setStorageSync('users', users)
+
+ // 打标签
+ let tags = wx.getStorageSync('tags')
+ if (typeof tags !== 'object' || tags === null) {
+ tags = {}
+ }
+ tags[userId] = tags[userId] || []
+ tags[userId] = tags[userId].filter(tag => !tag.startsWith('身份:'))
+ tags[userId].push(`身份:${type}`)
+ wx.setStorageSync('tags', tags)
+
+ console.log('用户类型设置完成,准备跳转到', type === 'buyer' ? '买家页面' : '卖家页面')
+
+ setTimeout(() => {
+ if (type === 'buyer') {
+ wx.switchTab({ url: '/pages/buyer/index' })
+ } else {
+ // 卖家登录成功后,重新显示创建货源弹窗
+ this.setData({
+ showImagePreview: false,
+ showModal: true,
+ newSupply: { name: '', price: '', minOrder: '', yolk: '', spec: '', imageUrls: [] }
+ });
+ this.disablePageScroll();
+ }
+ }, 500)
+ },
+
+ // 显示添加货源弹窗
+ showAddSupply(e) {
+ console.log('点击创建新货源按钮');
+
+ // 检查登录状态
+ const openid = wx.getStorageSync('openid');
+ const userId = wx.getStorageSync('userId');
+
+ if (!openid || !userId) {
+ console.log('用户未登录,触发授权登录流程');
+ // 显示授权弹窗
+ this.setData({
+ showAuthModal: true,
+ pendingUserType: 'seller'
+ });
+ return;
+ }
+
+ // 阻止事件冒泡,防止触发父元素的点击事件
+ if (e && e.stopPropagation) {
+ e.stopPropagation();
+ }
+
+ // 已登录,继续原有逻辑
+ this.setData({
+ showImagePreview: false,
+ showModal: true,
+ newSupply: { name: '', price: '', minOrder: '', yolk: '', spec: '', imageUrls: [] }
+ });
+
+ // 锁定页面滚动
+ this.disablePageScroll();
+ },
+
+ // 隐藏弹窗
+ hideModal() {
+ this.setData({
+ showModal: false,
+ newSupply: { name: '', price: '', minOrder: '', yolk: '', spec: '', imageUrls: [] },
+ showImagePreview: false // 确保图片预览弹窗关闭
+ })
+ // 恢复页面滚动
+ this.enablePageScroll()
+ },
+
+ // 隐藏编辑弹窗
+ hideEditModal() {
+ this.setData({
+ showEditModal: false
+ })
+ // 恢复页面滚动
+ this.enablePageScroll()
+ },
+
+ // 禁用页面滚动
+ disablePageScroll() {
+ // 获取页面实例并设置样式来禁用滚动
+ const pages = getCurrentPages()
+ const currentPage = pages[pages.length - 1]
+ if (currentPage) {
+ currentPage.setData({
+ pageScrollLock: true
+ })
+ }
+
+ // iOS设备特殊处理:阻止触摸事件
+ if (this.isIOS()) {
+ this.blockTouchMove()
+ }
+ },
+
+ // 启用页面滚动
+ enablePageScroll() {
+ // 获取页面实例并恢复滚动
+ const pages = getCurrentPages()
+ const currentPage = pages[pages.length - 1]
+ if (currentPage) {
+ currentPage.setData({
+ pageScrollLock: false
+ })
+ }
+
+ // iOS设备特殊处理:恢复触摸事件
+ if (this.isIOS()) {
+ this.unblockTouchMove()
+ }
+ },
+
+ // 输入内容处理
+ onInput(e) {
+ const field = e.currentTarget.dataset.field
+ const value = e.detail.value
+ const newSupply = this.data.newSupply
+ newSupply[field] = value
+ this.setData({ newSupply })
+ },
+
+ // 编辑输入处理
+ onEditInput(e) {
+ const field = e.currentTarget.dataset.field
+ const value = e.detail.value
+ // 创建一个新的对象,而不是直接修改data中的对象
+ this.setData({
+ editSupply: {
+ ...this.data.editSupply,
+ [field]: value
+ }
+ })
+ },
+
+ // 处理蛋黄选择变更
+ onYolkChange(e) {
+ const index = e.detail.value
+ const yolk = this.data.yolkOptions[index]
+ this.setData({
+ 'newSupply.yolkIndex': index,
+ 'newSupply.yolk': yolk
+ })
+ },
+
+ // 处理规格选择变更 - 现在直接打开自定义弹窗
+ onSpecChange(e) {
+ // 由于我们使用自定义弹窗,这个函数现在只需要打开弹窗即可
+ this.openSpecSelectModal({ currentTarget: { dataset: { mode: 'create' } } });
+ },
+
+ // 处理编辑模式下的蛋黄选择变更
+ onEditYolkChange(e) {
+ console.warn('此方法已弃用,请使用openYolkSelectModal替代');
+ },
+
+ // 处理编辑模式下的规格选择变更 - 现在直接打开自定义弹窗
+ onEditSpecChange(e) {
+ // 由于我们使用自定义弹窗,这个函数现在只需要打开弹窗即可
+ this.openSpecSelectModal({ currentTarget: { dataset: { mode: 'edit' } } });
+ },
+ // 商品名称选择变化处理
+ onNameChange(e) {
+ const index = e.detail.value
+ const productName = this.data.productNameOptions[index]
+ const newSupply = this.data.newSupply
+ newSupply.name = productName
+ this.setData({ newSupply })
+ },
+
+ // 编辑商品名称选择变化处理
+ onEditNameChange(e) {
+ console.warn('此方法已弃用,请使用openNameSelectModal替代');
+ },
+ // 添加新货源 - 先创建商品再上传图片(修复版)
+ addSupply() {
+ const { name, price, minOrder, yolk, spec, region, imageUrls } = this.data.newSupply
+ if (!name || !price || !minOrder || !yolk) {
+ wx.showToast({ title: '请填写完整信息', icon: 'none', duration: 2000 })
+ return
+ }
+
+ // 显示加载中提示
+ wx.showLoading({ title: '正在创建商品...', mask: true })
+
+ const openid = wx.getStorageSync('openid')
+ console.log('当前用户openid:', openid)
+ // 检查openid是否存在
+ if (!openid) {
+ console.error('openid不存在,无法上传商品到服务器')
+ wx.hideLoading()
+ wx.showModal({
+ title: '登录状态异常',
+ content: '您的登录状态已失效,请重新登录后再尝试发布商品',
+ showCancel: false,
+ success: () => {
+ wx.showToast({
+ title: '创建失败,请先登录',
+ icon: 'none',
+ duration: 3000
+ })
+ }
+ })
+
+ this.setData({
+ showModal: false,
+ newSupply: { name: '', price: '', minOrder: '', yolk: '', spec: '', region: '', grossWeight: '', imageUrls: [] }
+ })
+ this.enablePageScroll()
+ return
+ }
+
+ // 第一步:先创建商品(不带图片)
+ const productData = {
+ productName: name,
+ price: price, // 保留原始字符串,不进行数字转换
+ quantity: Number(minOrder),
+ grossWeight: this.data.newSupply.grossWeight && this.data.newSupply.grossWeight !== '' ? this.data.newSupply.grossWeight : "",
+
+ yolk: yolk,
+ specification: spec || '',
+ region: region || '', // 【新增】添加地区字段
+ rejectReason: '',
+ imageUrls: [] // 明确设置为空数组
+ }
+
+ console.log('第一步:准备创建商品,数据:', productData)
+
+ // 调用API创建商品(不带图片)
+ API.publishProduct(productData)
+ .then(res => {
+ console.log('商品创建成功:', res)
+
+ // 第二步:如果有图片,上传图片到已创建的商品
+ if (imageUrls && imageUrls.length > 0) {
+ wx.showLoading({ title: '正在上传图片...', mask: true })
+ console.log('开始上传图片到已创建商品,数量:', imageUrls.length)
+
+ // 获取创建的商品ID - 从多个可能的位置获取
+ const productId = res.productId || res.data?.productId || res.product?.productId
+
+ if (productId) {
+ console.log('找到商品ID:', productId)
+ // 【关键修复】使用专门的方法上传图片到已存在商品
+ return this.uploadImagesToExistingProduct(productId, imageUrls, openid)
+ .then(uploadRes => {
+ console.log('图片上传成功:', uploadRes)
+ return { ...res, imageUpload: uploadRes }
+ })
+ } else {
+ console.error('无法获取商品ID,响应数据:', res)
+ throw new Error('无法获取商品ID,无法上传图片')
+ }
+ } else {
+ // 没有图片,直接返回
+ return res
+ }
+ })
+ .then(finalRes => {
+ wx.hideLoading()
+ wx.showToast({
+ title: imageUrls && imageUrls.length > 0 ? '创建成功,图片已上传' : '创建成功',
+ duration: 3000
+ })
+
+ // 重置表单
+ this.setData({
+ showModal: false,
+ newSupply: { name: '', price: '', minOrder: '', yolk: '', spec: '', imageUrls: [] }
+ })
+ this.enablePageScroll()
+
+ // 重新加载数据
+ this.loadSupplies()
+ })
+ .catch(err => {
+ console.error('商品创建或图片上传失败:', err)
+ wx.hideLoading()
+
+ // 错误处理
+ if (err.needRelogin) {
+ console.warn('检测到需要重新登录')
+ wx.showModal({
+ title: '登录状态失效',
+ content: '您的登录已过期,请重新授权登录',
+ showCancel: false,
+ success: (res) => {
+ if (res.confirm) {
+ wx.removeStorageSync('openid')
+ wx.removeStorageSync('userId')
+ wx.navigateTo({ url: '/pages/login/index' })
+ }
+ }
+ })
+ } else {
+ let errorMsg = '上传服务器失败'
+ if (err.message && err.message.includes('用户不存在')) {
+ errorMsg = '用户未登录,请先登录'
+ } else if (err.message && err.message.includes('卖家才能发布商品')) {
+ errorMsg = '请先在个人资料中修改用户类型为卖家'
+ } else if (err.message && err.message.includes('商品不存在')) {
+ errorMsg = '商品创建失败,无法上传图片'
+ }
+ wx.showModal({
+ title: '发布失败',
+ content: errorMsg + '\n\n错误详情: ' + (err.message || JSON.stringify(err)),
+ showCancel: false,
+ success: () => {
+ this.loadSupplies()
+ }
+ })
+ }
+ })
+ },
+
+ // 上传商品图片 - 修复版,专门用于为已存在商品上传图片
+ uploadProductImages(productId, imageUrls) {
+ return new Promise((resolve, reject) => {
+ if (!productId) {
+ reject(new Error('商品ID不能为空'))
+ return
+ }
+
+ if (!imageUrls || imageUrls.length === 0) {
+ resolve({ success: true, message: '没有图片需要上传' })
+ return
+ }
+
+ console.log('开始为已存在商品上传图片,商品ID:', productId, '图片数量:', imageUrls.length)
+
+ // 获取openid
+ const openid = wx.getStorageSync('openid')
+ if (!openid) {
+ reject(new Error('用户未登录'))
+ return
+ }
+
+ // 【关键修复】使用专门的图片上传方法,而不是创建新商品
+ this.uploadImagesToExistingProduct(productId, imageUrls, openid)
+ .then(resolve)
+ .catch(reject)
+ })
+ },
+
+ // 【修复】上传商品图片 - 确保顺序执行
+ uploadImagesToExistingProduct(productId, imageUrls, openid) {
+ return new Promise((resolve, reject) => {
+ console.log('【图片上传】开始为已存在商品上传图片,商品ID:', productId);
+
+ // 【关键修复】顺序上传图片,避免并发问题
+ const uploadSequentially = async () => {
+ const results = [];
+
+ for (let i = 0; i < imageUrls.length; i++) {
+ try {
+ console.log(`顺序上传第${i + 1}/${imageUrls.length}张图片`);
+
+ const result = await new Promise((resolveUpload, rejectUpload) => {
+ const formData = {
+ productId: productId,
+ openid: openid,
+ action: 'add_images_only',
+ imageIndex: i,
+ totalImages: imageUrls.length,
+ isUpdate: 'true',
+ timestamp: Date.now()
+ };
+
+ wx.uploadFile({
+ url: API.BASE_URL + '/api/products/upload',
+ filePath: imageUrls[i],
+ name: 'images',
+ formData: formData,
+ success: (res) => {
+ if (res.statusCode === 200) {
+ try {
+ const data = JSON.parse(res.data);
+ if (data.success) {
+ console.log(`第${i + 1}张图片上传成功,当前总数:`, data.totalCount);
+ resolveUpload(data);
+ } else {
+ rejectUpload(new Error(data.message || '图片上传失败'));
+ }
+ } catch (parseError) {
+ rejectUpload(new Error('服务器响应格式错误'));
+ }
+ } else {
+ rejectUpload(new Error(`HTTP ${res.statusCode}`));
+ }
+ },
+ fail: (err) => {
+ rejectUpload(new Error('网络错误: ' + err.errMsg));
+ }
+ });
+ });
+
+ results.push(result);
+
+ // 添加延迟,避免服务器处理压力过大
+ if (i < imageUrls.length - 1) {
+ await new Promise(resolve => setTimeout(resolve, 500));
+ }
+
+ } catch (error) {
+ console.error(`第${i + 1}张图片上传失败:`, error);
+ // 继续上传其他图片,不中断流程
+ results.push({ success: false, error: error.message });
+ }
+ }
+
+ return results;
+ };
+
+ uploadSequentially()
+ .then(results => {
+ // 取最后一个成功的结果作为最终状态
+ const successfulResults = results.filter(r => r && r.success);
+ if (successfulResults.length > 0) {
+ const lastResult = successfulResults[successfulResults.length - 1];
+ resolve({
+ success: true,
+ message: `成功上传${successfulResults.length}张图片`,
+ imageUrls: lastResult.imageUrls || [],
+ allImageUrls: lastResult.allImageUrls || [],
+ uploadedCount: successfulResults.length,
+ totalCount: lastResult.totalCount || successfulResults.length,
+ results: results
+ });
+ } else {
+ reject(new Error('所有图片上传失败'));
+ }
+ })
+ .catch(error => {
+ console.error('图片上传失败:', error);
+ reject(error);
+ });
+ });
+ },
+
+ // 准备上架操作:只显示编辑页面,用户点击提交后才执行上架
+ preparePublishSupply(e) {
+ // 阻止事件冒泡,防止触发父元素的点击事件
+ if (e && e.stopPropagation) {
+ e.stopPropagation();
+ }
+
+ // 设置自动上架标志为true
+ this.setData({
+ autoPublishAfterEdit: true
+ });
+ console.log('设置编辑后自动上架标志为true');
+
+ // 调用showEditSupply方法显示编辑页面,但不自动执行上架
+ this.showEditSupply(e, true); // 传递第二个参数表示这是上架操作
+ },
+
+ // 保存编辑后的货源信息
+ saveEdit() {
+ const { editSupply, autoPublishAfterEdit } = this.data;
+
+ // 验证必填信息
+ if (!editSupply.name || !editSupply.price || !editSupply.minOrder || !editSupply.yolk) {
+ wx.showToast({ title: '请填写完整信息', icon: 'none', duration: 2000 });
+ return;
+ }
+
+ // 显示加载中提示
+ wx.showLoading({ title: '正在同步...', mask: true });
+
+ // 获取openid
+ const openid = wx.getStorageSync('openid');
+
+ if (!openid) {
+ wx.hideLoading();
+ wx.showModal({
+ title: '登录状态异常',
+ content: '您的登录状态已失效,请重新登录后再尝试保存',
+ showCancel: false,
+ success: () => {
+ wx.showToast({
+ title: '保存失败,请先登录',
+ icon: 'none',
+ duration: 3000
+ });
+ this.setData({ showEditModal: false });
+ this.enablePageScroll();
+ }
+ });
+ return;
+ }
+
+ // 【关键修复】准备商品数据 - 确保包含地区字段
+ const productData = {
+ productName: editSupply.name,
+ price: editSupply.price, // 保留原始字符串,不进行数字转换
+ quantity: Number(editSupply.minOrder),
+ grossWeight: editSupply.grossWeight !== undefined && editSupply.grossWeight !== null && editSupply.grossWeight !== '' ? editSupply.grossWeight : "",
+ yolk: editSupply.yolk,
+ specification: editSupply.spec || '',
+ region: editSupply.region || '', // 【重要】确保地区字段传递
+ imageUrls: editSupply.imageUrls || [],
+ created_at: new Date().toISOString(),
+ status: autoPublishAfterEdit ? 'pending_review' : ''
+ };
+
+ console.log('【调试】准备提交的商品数据:', {
+ productData: productData,
+ hasRegion: !!productData.region,
+ regionValue: productData.region
+ });
+
+ // 判断是编辑现有商品还是创建新商品
+ if (editSupply.serverProductId) {
+ // 编辑现有商品
+ productData.productId = editSupply.serverProductId;
+
+ console.log('【调试】调用API.editProduct,商品ID:', editSupply.serverProductId);
+
+ // 【关键修复】使用正确的API调用格式
+ const requestData = {
+ openid: openid,
+ productId: editSupply.serverProductId,
+ product: {
+ productName: productData.productName,
+ price: productData.price,
+ quantity: productData.quantity,
+ grossWeight: productData.grossWeight,
+ yolk: productData.yolk,
+ specification: productData.specification,
+ region: productData.region, // 【重要】确保在product对象中传递地区字段
+ imageUrls: productData.imageUrls
+ },
+ status: productData.status || ''
+ };
+
+ console.log('【调试】最终发送的请求数据:', requestData);
+
+ // 直接使用wx.request调用,避免API封装层的问题
+ wx.request({
+ url: API.BASE_URL + '/api/product/edit',
+ method: 'POST',
+ data: requestData,
+ success: (res) => {
+ console.log('【调试】编辑商品成功响应:', res);
+ wx.hideLoading();
+ this.setData({ showEditModal: false });
+ this.enablePageScroll();
+ wx.showToast({ title: '更新成功', duration: 2000 });
+
+ // 重新加载数据
+ setTimeout(() => {
+ this.loadSupplies();
+ }, 100);
+ },
+ fail: (err) => {
+ console.error('【调试】编辑商品失败:', err);
+ wx.hideLoading();
+ wx.showToast({ title: '保存失败,请重试', icon: 'none', duration: 2000 });
+ }
+ });
+ } else {
+ // 创建新商品并提交审核
+ // 调用添加商品接口
+ wx.request({
+ url: API.BASE_URL + '/api/product/add',
+ method: 'POST',
+ data: productData,
+ success: (res) => {
+ console.log('商品创建成功:', res);
+ wx.hideLoading();
+
+ // 关闭编辑弹窗
+ this.setData({ showEditModal: false });
+ // 恢复页面滚动
+ this.enablePageScroll();
+
+ wx.showToast({ title: '更新成功,等待审核', duration: 2000 });
+
+ // 重新加载商品列表
+ setTimeout(() => {
+ this.loadSupplies();
+ }, 100);
+ },
+ fail: (err) => {
+ console.error('商品创建失败:', err);
+ wx.hideLoading();
+ wx.showToast({ title: '创建失败,请重试', icon: 'none', duration: 2000 });
+ }
+ });
+ }
+ },
+
+ // 预览图片
+ previewImage(e) {
+ const { urls, index } = e.currentTarget.dataset
+
+ console.log('准备预览图片,原始URLs:', urls);
+ console.log('当前预览图片索引:', index);
+ console.log('当前预览图片原始URL:', urls[index]);
+
+ // 修复图片URL格式化问题
+ const formattedUrls = urls.map(url => {
+ if (!url) return '';
+ // 移除URL中的引号
+ let formattedUrl = url.toString().replace(/['"`]/g, '');
+ // 确保URL以http://或https://开头,特殊处理wxfile://格式
+ // 特殊处理占位符URL(以placeholder://协议开头)
+ const isHttpProtocol = formattedUrl.startsWith('http');
+ const isWxfileProtocol = formattedUrl.startsWith('wxfile://');
+ const isPlaceholderUrl = formattedUrl.startsWith('placeholder://');
+
+ console.log('previewImage - 原始URL:', url);
+ console.log('previewImage - 移除引号后的URL:', formattedUrl);
+ console.log('previewImage - isHttpProtocol:', isHttpProtocol, 'isWxfileProtocol:', isWxfileProtocol, 'isPlaceholderUrl:', isPlaceholderUrl);
+
+ // 对于占位符URL,返回空字符串,这样就不会在预览中显示它们
+ if (isPlaceholderUrl) {
+ console.log('previewImage - 占位符URL,不参与预览:', formattedUrl);
+ return '';
+ }
+
+ if (formattedUrl && !isHttpProtocol && !isWxfileProtocol) {
+ console.warn('previewImage - 图片URL缺少协议,添加https://前缀:', formattedUrl);
+ formattedUrl = 'https://' + formattedUrl;
+ } else {
+ console.log('previewImage - URL已包含有效协议或为wxfile格式,无需添加前缀:', formattedUrl);
+ }
+
+ // 尝试解码可能被编码的URL路径段
+ try {
+ // 先检查是否包含%2F等已编码的斜杠
+ if (formattedUrl.includes('%2F')) {
+ // 只解码路径部分,保留查询参数
+ const parts = formattedUrl.split('?');
+ if (parts.length > 1) {
+ formattedUrl = decodeURIComponent(parts[0]) + '?' + parts[1];
+ } else {
+ formattedUrl = decodeURIComponent(formattedUrl);
+ }
+ }
+ } catch (e) {
+ console.error('解码URL失败:', e);
+ }
+ // 简单验证URL格式
+ if (formattedUrl && /^https?:\/\/.+\..+/.test(formattedUrl)) {
+ return formattedUrl;
+ }
+ return '';
+ });
+
+ console.log('格式化后的URLs:', formattedUrls);
+ console.log('当前预览图片格式化后URL:', formattedUrls[index]);
+
+ // 锁定页面滚动
+ this.disablePageScroll();
+
+ this.setData({
+ showImagePreview: true,
+ previewImageUrls: formattedUrls.filter(url => url), // 过滤掉无效URL
+ previewImageIndex: parseInt(index)
+ })
+ },
+
+ // 关闭图片预览
+ closeImagePreview() {
+ this.setData({
+ showImagePreview: false
+ })
+
+ // 恢复页面滚动
+ this.enablePageScroll();
+ },
+
+ // 切换预览图片
+ onPreviewImageChange(e) {
+ this.setData({
+ previewImageIndex: e.detail.current,
+ // 切换图片时重置缩放状态
+ scale: 1,
+ offsetX: 0,
+ offsetY: 0
+ })
+ },
+
+ // 处理图片点击事件
+ handleImageTap() {
+ // 清除之前的双击计时器
+ if (this.data.doubleTapTimeout) {
+ clearTimeout(this.data.doubleTapTimeout)
+ this.setData({ doubleTapTimeout: null })
+ }
+
+ // 增加双击计数
+ const newDoubleTapCount = this.data.doubleTapCount + 1
+ this.setData({ doubleTapCount: newDoubleTapCount })
+
+ // 如果是第一次点击,设置计时器
+ if (newDoubleTapCount === 1) {
+ const timer = setTimeout(() => {
+ // 单击操作:重置缩放
+ this.resetZoom()
+ this.setData({ doubleTapCount: 0, doubleTapTimeout: null })
+ }, 300)
+ this.setData({ doubleTapTimeout: timer })
+ } else if (newDoubleTapCount === 2) {
+ // 双击操作:切换缩放状态
+ if (this.data.scale > 1) {
+ this.resetZoom()
+ } else {
+ this.zoomToFit(this.data.imageWidth, this.data.imageHeight)
+ }
+ this.setData({ doubleTapCount: 0, doubleTapTimeout: null })
+ }
+ },
+
+ // 处理触摸开始事件
+ handleTouchStart(e) {
+ // 清除双击计时器
+ if (this.data.doubleTapTimeout) {
+ clearTimeout(this.data.doubleTapTimeout)
+ this.setData({ doubleTapTimeout: null, doubleTapCount: 0 })
+ }
+
+ // 双指触摸时计算距离
+ if (e.touches.length === 2) {
+ const distance = this.calculateDistance(e.touches[0], e.touches[1])
+ this.setData({ lastDistance: distance })
+ } else if (e.touches.length === 1) {
+ // 单指触摸时记录触摸点 - 使用pageX和pageY而非clientX和clientY
+ const touch = e.touches[0]
+ this.setData({
+ lastTouchPoint: {
+ pageX: touch.pageX,
+ pageY: touch.pageY
+ }
+ })
+ }
+ },
+
+ // 处理触摸移动事件
+ handleTouchMove(e) {
+ // 小程序中阻止冒泡通过catchtap等方式实现
+
+ if (e.touches.length === 2) {
+ // 双指缩放
+ const currentDistance = this.calculateDistance(e.touches[0], e.touches[1])
+ const scaleRatio = currentDistance / this.data.lastDistance
+ let newScale = this.data.scale * scaleRatio
+
+ // 限制缩放范围
+ newScale = Math.max(this.data.minScale, Math.min(this.data.maxScale, newScale))
+
+ this.setData({
+ scale: newScale,
+ lastDistance: currentDistance
+ })
+ } else if (e.touches.length === 1 && this.data.scale > 1 && this.data.lastTouchPoint) {
+ // 单指移动(仅在缩放后可移动)
+ const currentTouch = e.touches[0]
+ // 使用pageX和pageY而非clientX和clientY
+ const deltaX = currentTouch.pageX - this.data.lastTouchPoint.pageX
+ const deltaY = currentTouch.pageY - this.data.lastTouchPoint.pageY
+
+ let newOffsetX = this.data.offsetX + deltaX
+ let newOffsetY = this.data.offsetY + deltaY
+
+ // 限制拖动范围
+ const maxOffsetX = (this.data.imageWidth * this.data.scale - this.data.imageWidth) / 2
+ const maxOffsetY = (this.data.imageHeight * this.data.scale - this.data.imageHeight) / 2
+
+ newOffsetX = Math.max(-maxOffsetX, Math.min(maxOffsetX, newOffsetX))
+ newOffsetY = Math.max(-maxOffsetY, Math.min(maxOffsetY, newOffsetY))
+
+ this.setData({
+ offsetX: newOffsetX,
+ offsetY: newOffsetY,
+ lastTouchPoint: {
+ pageX: currentTouch.pageX,
+ pageY: currentTouch.pageY
+ }
+ })
+ }
+ },
+
+ // 处理触摸结束事件
+ handleTouchEnd() {
+ // 重置触摸点和距离
+ this.setData({
+ lastTouchPoint: null,
+ lastDistance: 0
+ })
+ },
+
+ // 重置缩放
+ resetZoom() {
+ this.setData({
+ scale: 1,
+ offsetX: 0,
+ offsetY: 0
+ })
+ },
+
+ // 计算两点之间的距离
+ calculateDistance(touch1, touch2) {
+ // 在小程序中使用pageX和pageY而非clientX和clientY
+ const dx = touch1.pageX - touch2.pageX
+ const dy = touch1.pageY - touch2.pageY
+ return Math.sqrt(dx * dx + dy * dy)
+ },
+
+ // 缩放图片以适应屏幕
+ zoomToFit(imageWidth, imageHeight) {
+ // 假设屏幕宽度为375px
+ const screenWidth = 375
+ let newScale = 2
+
+ this.setData({ scale: newScale })
+ },
+
+ // 图片加载完成事件
+ onPreviewImageLoad(e) {
+ this.setData({
+ imageWidth: e.detail.width,
+ imageHeight: e.detail.height
+ })
+ },
+
+ // 图片加载失败处理 - 增强版
+ imageError(e) {
+ const url = e.currentTarget.dataset.src || '未知URL';
+ const errMsg = e.detail.errMsg || '未知错误';
+
+ console.error(`图片加载失败 [${errMsg}]: ${url}`);
+
+ // 尝试使用占位图替代
+ const target = e.currentTarget;
+ try {
+ // 在实际运行中,小程序会自动使用fallback-src
+ // 这里添加日志记录以便追踪
+ console.log(`为失败图片设置占位图: ${url}`);
+ } catch (err) {
+ console.error('设置占位图时出错:', err);
+ }
+
+ // 记录失败的URL到本地,便于调试
+ try {
+ const failedUrls = wx.getStorageSync('imageLoadFailures') || [];
+ if (!failedUrls.includes(url)) {
+ failedUrls.push({ url, time: new Date().toISOString(), error: errMsg });
+ // 只保留最近20条记录
+ if (failedUrls.length > 20) {
+ failedUrls.shift();
+ }
+ wx.setStorageSync('imageLoadFailures', failedUrls);
+ }
+ } catch (storageErr) {
+ console.error('存储失败URL时出错:', storageErr);
+ }
+ },
+
+ // 图片加载成功处理 - 增强版
+ imageLoad(e) {
+ const url = e.currentTarget.dataset.src;
+ const width = e.detail.width;
+ const height = e.detail.height;
+
+ console.log(`图片加载成功: ${url} (${width}x${height})`);
+
+ // 可以在这里添加图片统计逻辑
+ try {
+ const successCount = wx.getStorageSync('imageLoadSuccessCount') || 0;
+ wx.setStorageSync('imageLoadSuccessCount', successCount + 1);
+ } catch (storageErr) {
+ console.error('存储成功计数时出错:', storageErr);
+ }
+ },
+
+ // 显示编辑弹窗 - 修复版
+ showEditSupply(e, isPublishOperation = false) {
+ // 阻止事件冒泡,防止触发父元素的点击事件
+ if (e && e.stopPropagation) {
+ e.stopPropagation();
+ }
+
+ // 确保图片预览弹窗关闭
+ this.setData({
+ showImagePreview: false
+ });
+
+ const id = e.currentTarget.dataset.id;
+ console.log('显示编辑弹窗,货源ID:', id, '是否上架操作:', isPublishOperation);
+
+ if (!id) {
+ console.error('显示编辑弹窗失败:缺少货源ID');
+ wx.showToast({ title: '操作失败,缺少货源信息', icon: 'none', duration: 2000 });
+ return;
+ }
+
+ // 在所有货源列表中查找
+ let supply = null;
+ const allSupplies = [
+ ...this.data.publishedSupplies,
+ ...this.data.pendingSupplies,
+ ...this.data.rejectedSupplies,
+ ...this.data.draftSupplies
+ ];
+
+ supply = allSupplies.find(s => s.id === id);
+
+ // 如果没找到,尝试在主列表中查找
+ if (!supply) {
+ supply = this.data.supplies.find(s => s.id === id);
+ }
+
+ // 安全检查:确保supply存在
+ if (!supply) {
+ console.error('未找到ID为', id, '的货源');
+ wx.showToast({ title: '未找到该货源', icon: 'none', duration: 2000 });
+ this.setData({ showEditModal: false });
+ // 确保页面滚动状态正常
+ this.enablePageScroll();
+ this.loadSupplies();
+ return;
+ }
+
+ // 计算蛋黄和规格的索引值
+ const yolkIndex = this.data.yolkOptions.indexOf(supply.yolk) >= 0 ? this.data.yolkOptions.indexOf(supply.yolk) : 0;
+ const specIndex = this.data.specOptions.indexOf(supply.spec) >= 0 ? this.data.specOptions.indexOf(supply.spec) : 0;
+
+ // 设置编辑货源数据,显示编辑弹窗
+ const supplyWithFormattedTime = {
+ ...supply,
+ formattedCreatedAt: this.formatCreateTime(supply.created_at),
+ region: supply.region || '', // 【新增】确保地区字段存在
+ yolkIndex: yolkIndex,
+ specIndex: specIndex
+ };
+
+ console.log('【调试】编辑弹窗数据设置:', {
+ supplyRegion: supply.region,
+ editSupplyRegion: supplyWithFormattedTime.region
+ });
+
+ // 如果是上架操作,设置自动上架标志
+ if (isPublishOperation) {
+ this.setData({
+ autoPublishAfterEdit: true
+ });
+ console.log('设置编辑后自动上架标志为true');
+ } else {
+ this.setData({
+ autoPublishAfterEdit: false
+ });
+ console.log('设置编辑后自动上架标志为false');
+ }
+
+ this.setData({
+ editSupply: supplyWithFormattedTime,
+ showEditModal: true
+ });
+
+ // 锁定页面滚动
+ this.disablePageScroll();
+
+ // 显示提示信息
+ wx.showToast({
+ title: '请编辑信息后点击提交',
+ icon: 'none',
+ duration: 2000
+ });
+ },
+
+ // 上架货源 - 移除本地存储操作
+ publishSupply(e) {
+ // 阻止事件冒泡,防止触发父元素的点击事件
+ if (e && e.stopPropagation) {
+ e.stopPropagation();
+ }
+
+ // 确保图片预览弹窗关闭
+ this.setData({
+ showImagePreview: false
+ });
+
+ const id = e.currentTarget.dataset.id
+ // 优先使用编辑中的商品数据
+ let supply = null
+
+ // 检查是否存在编辑中的数据
+ if (this.data.editSupply && this.data.editSupply.id === id) {
+ supply = { ...this.data.editSupply };
+ } else {
+ // 否则从supplies中查找
+ supply = this.data.supplies.find(s => s.id === id)
+ }
+
+ if (!supply) {
+ wx.hideLoading();
+ // 恢复页面滚动
+ this.enablePageScroll();
+ wx.showToast({
+ title: '操作失败,货源不存在',
+ icon: 'none',
+ duration: 2000
+ });
+ return;
+ }
+
+ wx.showLoading({ title: '处理中...', mask: true });
+
+ // 判断当前货源状态,决定设置什么状态
+ // 重新提交的商品应该先进入审核中
+ let newStatus = 'pending_review'; // 默认审核中
+ if (supply.status === 'reviewed') {
+ newStatus = 'published'; // 已审核通过的货源可以直接上架
+ }
+
+ // 同步数据到服务器数据库
+ // 仅当有serverProductId时才同步到服务器
+ if (supply.serverProductId) {
+ const openid = wx.getStorageSync('openid');
+ if (openid) {
+ // 审核失败、隐藏、审核中或下架的货源重新提交时,调用编辑接口同步商品内容和状态
+ if (supply.status === 'rejected' || supply.status === 'hidden' || supply.status === 'pending_review' || supply.status === 'sold_out') {
+ console.log('审核失败、隐藏、审核中或下架货源重新提交,同步商品内容和状态到服务器');
+ // 准备商品数据,转换为服务器需要的格式
+ const productData = {
+ openid: openid,
+ productId: supply.serverProductId,
+ product: {
+ productName: supply.name,
+ price: supply.price,
+ quantity: supply.minOrder,
+ grossWeight: supply.grossWeight || "",
+ yolk: supply.yolk,
+ specification: supply.spec,
+ resubmit: true // 关键参数:告诉服务器这是重新提交审核
+ },
+ status: newStatus // 明确传递状态参数,确保变为审核中状态
+ };
+
+ console.log('准备发送商品编辑请求 - URL:', API.BASE_URL + '/api/product/edit');
+ console.log('准备发送的商品数据:', productData);
+ // 调用编辑商品接口,该接口会自动设置状态为pending_review
+ wx.request({
+ url: API.BASE_URL + '/api/product/edit',
+ method: 'POST',
+ data: productData,
+ success: (res) => {
+ console.log('商品内容和状态同步成功:', res);
+ // 重新加载数据以更新UI
+ this.loadSupplies();
+ },
+ fail: (err) => {
+ console.error('商品内容和状态同步失败:', err);
+ // 重新加载数据以更新UI
+ this.loadSupplies();
+ },
+ complete: () => {
+ // 确保在请求完成后隐藏loading并显示提示
+ try {
+ wx.hideLoading();
+ // 恢复页面滚动
+ this.enablePageScroll();
+ wx.showToast({
+ title: newStatus === 'published' ? '上架成功' : '重新提交成功,等待审核',
+ duration: 2000
+ });
+ } catch (e) {
+ console.error('显示提示时出错:', e);
+ // 确保即使在错误情况下也隐藏loading并恢复滚动
+ try {
+ wx.hideLoading();
+ this.enablePageScroll();
+ } catch (innerErr) {
+ console.error('隐藏loading时出错:', innerErr);
+ }
+ }
+ }
+ });
+ return; // 异步操作,稍后再继续执行
+ } else {
+ // 其他情况只更新状态
+ wx.request({
+ url: API.BASE_URL + '/api/product/review',
+ method: 'POST',
+ data: {
+ openid: openid,
+ productId: supply.serverProductId,
+ status: newStatus
+ },
+ success: () => {
+ this.loadSupplies();
+ },
+ fail: (err) => {
+ console.error('更新状态失败:', err);
+ this.loadSupplies();
+ },
+ complete: () => {
+ try {
+ wx.hideLoading();
+ // 恢复页面滚动
+ this.enablePageScroll();
+ wx.showToast({
+ title: newStatus === 'published' ? '上架成功' : '重新提交成功,等待审核',
+ duration: 2000
+ });
+ } catch (e) {
+ console.error('显示提示时出错:', e);
+ // 确保即使在错误情况下也隐藏loading并恢复滚动
+ try {
+ wx.hideLoading();
+ this.enablePageScroll();
+ } catch (innerErr) {
+ console.error('隐藏loading时出错:', innerErr);
+ }
+ }
+ }
+ });
+ return; // 异步操作,稍后再继续执行
+ }
+ } else {
+ // 没有openid时的处理
+ wx.hideLoading();
+ // 恢复页面滚动
+ this.enablePageScroll();
+ wx.showToast({
+ title: '登录状态异常,请重新登录',
+ icon: 'none',
+ duration: 2000
+ });
+ }
+ } else {
+ // 如果没有serverProductId,提示用户
+ wx.hideLoading();
+ // 恢复页面滚动
+ this.enablePageScroll();
+ wx.showToast({
+ title: '无法上架,商品未上传到服务器',
+ icon: 'none',
+ duration: 2000
+ });
+ }
+ },
+
+ // 下架货源 - 移除本地存储操作
+ unpublishSupply(e) {
+ // 阻止事件冒泡,防止触发父元素的点击事件
+ if (e && e.stopPropagation) {
+ e.stopPropagation();
+ }
+
+ const supplyId = e.currentTarget.dataset.id;
+ console.log('下架商品 - ID:', supplyId);
+ console.log('当前商品列表长度:', this.data.supplies.length);
+ console.log('当前已上架商品列表长度:', this.data.publishedSupplies.length);
+
+ // 查找对应商品
+ let supply = this.data.supplies.find(s => s.id === supplyId);
+
+ // 如果在主列表中找不到,尝试在已上架商品列表中查找
+ if (!supply) {
+ supply = this.data.publishedSupplies.find(s => s.id === supplyId);
+ console.log('在已上架列表中查找结果:', supply ? '找到' : '未找到');
+ }
+
+ // 如果仍然找不到商品,尝试直接使用传入的ID下架(容错处理)
+ if (!supply) {
+ console.warn('未在本地列表中找到商品,但尝试直接下架:', supplyId);
+
+ // 禁用页面滚动
+ this.disablePageScroll();
+ wx.showLoading({ title: '下架中...', mask: true });
+
+ // 直接使用传入的ID尝试下架
+ API.hideProduct(supplyId)
+ .then(res => {
+ console.log('直接下架成功:', res);
+ wx.hideLoading();
+ this.enablePageScroll();
+ wx.showToast({ title: '已下架', icon: 'success', duration: 2000 });
+
+ // 清理购物车并重新加载列表
+ this.cleanUnpublishedFromAllCarts(supplyId);
+ setTimeout(() => {
+ this.loadSupplies();
+ }, 100);
+ })
+ .catch(err => {
+ console.error('直接下架失败:', err);
+ wx.hideLoading();
+ this.enablePageScroll();
+ wx.showToast({ title: '下架失败,请重试', icon: 'none', duration: 2000 });
+ });
+ return;
+ }
+
+ // 检查是否有serverProductId,只有上传到服务器的商品才能下架
+ if (!supply.serverProductId) {
+ // 没有serverProductId,提示用户
+ wx.showToast({ title: '无法下架,商品未上传到服务器', icon: 'none', duration: 2000 });
+ return;
+ }
+
+ // 禁用页面滚动
+ this.disablePageScroll();
+ wx.showLoading({ title: '下架中...', mask: true });
+
+ // 调用API下架商品
+ API.hideProduct(supply.serverProductId)
+ .then(res => {
+ console.log('服务器下架成功:', res);
+ wx.hideLoading();
+ // 恢复页面滚动
+ this.enablePageScroll();
+ wx.showToast({ title: '已下架', icon: 'success', duration: 2000 });
+
+ // 清理所有用户购物车中已下架的商品
+ this.cleanUnpublishedFromAllCarts(supply.serverProductId);
+
+ // 只需要调用一次loadSupplies
+ setTimeout(() => {
+ this.loadSupplies();
+ }, 100);
+ })
+ .catch(err => {
+ console.error('服务器下架失败:', err);
+ wx.hideLoading();
+ // 恢复页面滚动
+ this.enablePageScroll();
+ wx.showToast({ title: '服务器同步失败,请重试', icon: 'none', duration: 3000 });
+
+ // 只需要调用一次loadSupplies
+ setTimeout(() => {
+ this.loadSupplies();
+ }, 100);
+ });
+ },
+
+ // 清理所有用户购物车中已下架的商品 - 移除本地存储操作
+ cleanUnpublishedFromAllCarts(supplyId) {
+ try {
+ console.log('开始清理购物车中的已下架商品:', supplyId)
+ // 直接通知服务器清理购物车
+ setTimeout(() => {
+ API.removeFromAllCarts(supplyId)
+ .then(res => {
+ console.log('清理所有购物车中的已下架商品完成:', res)
+ })
+ .catch(err => {
+ console.error('清理服务器购物车失败:', err)
+ })
+ }, 0);
+ } catch (error) {
+ console.error('清理购物车过程中发生错误:', error)
+ }
+ },
+
+ // 删除货源(软删除:只在服务器标记为隐藏)
+ deleteSupply(e) {
+ // 阻止事件冒泡,防止触发父元素的点击事件
+ if (e && e.stopPropagation) {
+ e.stopPropagation();
+ }
+
+ // 确保图片预览弹窗关闭
+ this.setData({
+ showImagePreview: false
+ });
+
+ const id = e.currentTarget.dataset.id
+ const supply = this.data.supplies.find(s => s.id === id)
+
+ if (!supply) {
+ wx.showToast({ title: '货源不存在', icon: 'none', duration: 2000 })
+ return
+ }
+
+ // 显示确认弹窗
+ wx.showModal({
+ title: '确认删除',
+ content: '确定要删除该货源吗?删除后将不再显示,但数据会保留。',
+ success: (res) => {
+ if (res.confirm) {
+ wx.showLoading({ title: '删除中...' })
+
+ // 确保使用正确的productId格式
+ let productIdToHide;
+ // 将id转换为字符串,避免startsWith调用错误
+ const idStr = String(id);
+
+ if (supply.serverProductId) {
+ productIdToHide = supply.serverProductId;
+ console.log('使用服务器返回的productId:', productIdToHide);
+ } else if (idStr.startsWith('product_')) {
+ productIdToHide = id;
+ console.log('使用已有的product_前缀ID:', productIdToHide);
+ } else {
+ // 如果本地ID不是以product_开头,尝试直接使用
+ productIdToHide = id;
+ console.log('使用本地ID作为productId:', productIdToHide);
+ }
+
+ API.deleteProduct(productIdToHide).then(() => {
+ console.log('服务器标记商品为隐藏成功:', productIdToHide)
+ wx.hideLoading()
+ wx.showToast({
+ title: '删除成功',
+ icon: 'success',
+ duration: 2000
+ })
+ // 手动加载数据更新UI
+ this.loadSupplies()
+ }).catch(error => {
+ console.error('服务器标记商品为隐藏失败:', error);
+ console.error('错误详情:', JSON.stringify(error));
+
+ wx.hideLoading()
+ // 手动加载数据更新UI
+ this.loadSupplies()
+
+ // 提供更详细的错误信息
+ let errorMsg = '服务器操作失败';
+ if (error.message && error.message.includes('连接失败')) {
+ errorMsg = '无法连接服务器,请检查网络连接后重试';
+ } else if (error.message && error.message.includes('商品不存在')) {
+ errorMsg = '该商品在服务器上可能已不存在';
+ }
+
+ wx.showToast({
+ title: errorMsg,
+ icon: 'none',
+ duration: 3000
+ })
+ })
+ }
+ }
+ })
+ },
+
+ // 格式化创建时间为 年/月/日 时:分 格式
+ formatCreateTime: function (timeValue) {
+ // 添加详细日志记录传入的参数
+ console.log('formatCreateTime - 输入值:', timeValue, '类型:', typeof timeValue);
+
+ if (!timeValue) {
+ console.log('formatCreateTime - 输入为空,返回"无"');
+ return '无';
+ }
+
+ try {
+ // 首先尝试直接创建Date对象
+ let date = new Date(timeValue);
+
+ // 如果日期无效,且输入是字符串,尝试将其转换为数字,再创建Date对象
+ if (isNaN(date.getTime()) && typeof timeValue === 'string') {
+ console.log('formatCreateTime - 尝试将字符串转换为数字');
+ const numericTime = Number(timeValue);
+ // 只有当转换后的数字不是NaN时才使用新的Date对象
+ if (!isNaN(numericTime)) {
+ date = new Date(numericTime);
+ }
+ }
+
+ console.log('formatCreateTime - Date对象:', date, '时间戳:', date.getTime());
+
+ // 检查日期是否有效
+ if (isNaN(date.getTime())) {
+ console.log('formatCreateTime - 日期无效,返回"无"');
+ return '无';
+ }
+
+ const year = date.getFullYear();
+ const month = (date.getMonth() + 1).toString().padStart(2, '0');
+ const day = date.getDate().toString().padStart(2, '0');
+ const hours = date.getHours().toString().padStart(2, '0');
+ const minutes = date.getMinutes().toString().padStart(2, '0');
+
+ const formattedTime = `${year}/${month}/${day} ${hours}:${minutes}`;
+ console.log('formatCreateTime - 格式化结果:', formattedTime);
+
+ return formattedTime;
+ } catch (error) {
+ console.error('时间格式化错误:', error);
+ return '无';
+ }
+ },
+
+ // 格式化时间为北京时间(UTC+8)并转换为 年-月-日-时:分 格式
+ formatTimeToBeijing: function (timeValue) {
+ if (!timeValue) {
+ return '无';
+ }
+
+ try {
+ // 创建Date对象
+ const date = new Date(timeValue);
+
+ // 检查日期是否有效
+ if (isNaN(date.getTime())) {
+ return '无';
+ }
+
+ // 使用Date对象的方法直接获取UTC时间,然后加8小时计算北京时间
+ const utcYear = date.getUTCFullYear();
+ const utcMonth = date.getUTCMonth();
+ const utcDate = date.getUTCDate();
+ const utcHours = date.getUTCHours() + 8; // 直接加8小时
+
+ // 创建北京时间Date对象
+ const beijingTime = new Date(Date.UTC(utcYear, utcMonth, utcDate, utcHours, date.getUTCMinutes()));
+
+ // 格式化时间,使用连字符分隔
+ const year = beijingTime.getFullYear();
+ const month = (beijingTime.getMonth() + 1).toString().padStart(2, '0');
+ const day = beijingTime.getDate().toString().padStart(2, '0');
+ const hours = beijingTime.getHours().toString().padStart(2, '0');
+ const minutes = beijingTime.getMinutes().toString().padStart(2, '0');
+
+ // 返回格式:年-月-日-时:分
+ return `${year}-${month}-${day}-${hours}:${minutes}`;
+ } catch (error) {
+ console.error('北京时间格式化错误:', error);
+ return '无';
+ }
+ },
+
+ // 显示审核失败原因弹窗
+ showRejectReason: function (e) {
+ // 阻止事件冒泡
+ if (e && e.stopPropagation) {
+ e.stopPropagation();
+ }
+
+ const id = e.currentTarget.dataset.id;
+ console.log('显示审核失败原因,货源ID:', id);
+
+ // 在所有货源列表中查找
+ let supply = null;
+ const allSupplies = [
+ ...this.data.publishedSupplies,
+ ...this.data.pendingSupplies,
+ ...this.data.rejectedSupplies,
+ ...this.data.draftSupplies
+ ];
+
+ supply = allSupplies.find(s => s.id === id);
+
+ // 如果没找到,尝试在主列表中查找
+ if (!supply) {
+ supply = this.data.supplies.find(s => s.id === id);
+ }
+
+ if (!supply) {
+ console.error('未找到ID为', id, '的货源');
+ wx.showToast({ title: '未找到该货源', icon: 'none', duration: 2000 });
+ return;
+ }
+
+ console.log('找到货源信息:', supply);
+
+ // 锁定页面滚动
+ this.disablePageScroll();
+
+ // 设置当前显示的货源和失败原因
+ this.setData({
+ currentRejectSupply: supply,
+ rejectReason: supply.rejectReason || '暂无详细的审核失败原因,请联系客服了解详情。',
+ showRejectReasonModal: true
+ });
+ },
+
+
+ // 关闭审核失败原因弹窗
+ closeRejectReasonModal: function () {
+ console.log('关闭审核失败原因弹窗');
+ this.setData({
+ showRejectReasonModal: false
+ // 注意:这里不立即清空 currentRejectSupply,确保后续操作能使用
+ });
+ },
+
+ // 打开规格选择弹窗
+ openSpecSelectModal: function (e) {
+ const mode = e.currentTarget.dataset.mode || 'create';
+ const currentSpec = mode === 'create' ? this.data.newSupply.spec : this.data.editSupply.spec;
+ const specOptions = this.data.specOptions;
+ let selectedIndex = -1;
+
+ // 查找当前选中规格的索引
+ if (currentSpec) {
+ selectedIndex = specOptions.indexOf(currentSpec);
+ }
+
+ // 通过全局数据控制自定义tab-bar的显示状态
+ const app = getApp();
+ if (app && app.globalData) {
+ app.globalData.showTabBar = false;
+ }
+
+ this.setData({
+ showSpecSelectModal: true,
+ currentSpecMode: mode,
+ modalSpecSearchKeyword: '',
+ filteredModalSpecOptions: specOptions,
+ selectedModalSpecIndex: selectedIndex,
+ showTabBar: false // 隐藏底部tab-bar
+ });
+ },
+
+ // 关闭规格选择弹窗
+ closeSpecSelectModal: function () {
+ // 通过全局数据控制自定义tab-bar的显示状态
+ const app = getApp();
+ if (app && app.globalData) {
+ app.globalData.showTabBar = true;
+ }
+
+ this.setData({
+ showSpecSelectModal: false,
+ modalSpecSearchKeyword: '',
+ selectedModalSpecIndex: -1,
+ showTabBar: true // 显示底部tab-bar
+ });
+ },
+
+ // 弹窗中规格搜索输入
+ onModalSpecSearchInput: function (e) {
+ const keyword = e.detail.value;
+ const specOptions = this.data.specOptions;
+ let filteredOptions = specOptions;
+
+ if (keyword) {
+ filteredOptions = specOptions.filter(option => {
+ return option.toLowerCase().includes(keyword.toLowerCase());
+ });
+ }
+
+ this.setData({
+ modalSpecSearchKeyword: keyword,
+ filteredModalSpecOptions: filteredOptions,
+ selectedModalSpecIndex: -1 // 搜索时重置选择
+ });
+ },
+
+ // 清除弹窗中的规格搜索关键词
+ clearModalSpecSearch: function () {
+ this.setData({
+ modalSpecSearchKeyword: '',
+ filteredModalSpecOptions: this.data.specOptions,
+ selectedModalSpecIndex: -1
+ });
+ },
+
+ // 弹窗中选择规格
+ onModalSpecSelect: function (e) {
+ const index = e.currentTarget.dataset.index;
+ const selectedSpec = this.data.filteredModalSpecOptions[index];
+ this.setData({
+ selectedModalSpecIndex: index,
+ modalSpecSearchKeyword: selectedSpec // 自动填充搜索框为当前选择的规格
+ });
+ },
+
+ // 确认规格选择
+ confirmSpecSelection: function () {
+ if (this.data.selectedModalSpecIndex === -1) {
+ wx.showToast({
+ title: '请选择规格',
+ icon: 'none'
+ });
+ return;
+ }
+
+ const selectedSpec = this.data.filteredModalSpecOptions[this.data.selectedModalSpecIndex];
+ const specOptions = this.data.specOptions;
+ const originalIndex = specOptions.indexOf(selectedSpec);
+
+ // 根据当前模式更新对应的规格信息
+ if (this.data.currentSpecMode === 'create') {
+ this.setData({
+ 'newSupply.spec': selectedSpec,
+ 'newSupply.specIndex': originalIndex
+ });
+ } else if (this.data.currentSpecMode === 'edit') {
+ this.setData({
+ 'editSupply.spec': selectedSpec,
+ 'editSupply.specIndex': originalIndex
+ });
+ }
+
+ // 关闭弹窗
+ this.closeSpecSelectModal();
+
+ // 恢复页面滚动
+ this.enablePageScroll();
+
+ // 延迟清空数据,确保操作完成
+ setTimeout(() => {
+ this.setData({
+ currentRejectSupply: null,
+ rejectReason: ''
+ });
+ }, 500);
+ },
+
+ // 编辑审核失败的货源
+ editRejectedSupply: function () {
+ // 先保存当前货源数据,再关闭弹窗
+ const currentRejectSupply = this.data.currentRejectSupply;
+
+ if (!currentRejectSupply || !currentRejectSupply.id) {
+ wx.showToast({ title: '货源信息不存在', icon: 'none', duration: 2000 });
+ return;
+ }
+
+ // 关闭失败原因弹窗
+ this.closeRejectReasonModal();
+
+ // 延迟一小段时间确保弹窗完全关闭
+ setTimeout(() => {
+ // 模拟点击编辑按钮的事件对象
+ const mockEvent = {
+ stopPropagation: function () { },
+ currentTarget: {
+ dataset: {
+ id: currentRejectSupply.id
+ }
+ }
+ };
+
+ // 调用显示编辑弹窗的方法
+ this.showEditSupply(mockEvent);
+ }, 100);
+ },
+
+ // 重新提交审核失败的货源
+ resubmitRejectedSupply: function () {
+ // 先保存当前货源数据,再关闭弹窗
+ const currentRejectSupply = this.data.currentRejectSupply;
+
+ if (!currentRejectSupply || !currentRejectSupply.id) {
+ wx.showToast({ title: '货源信息不存在', icon: 'none', duration: 2000 });
+ return;
+ }
+
+ // 关闭失败原因弹窗
+ this.closeRejectReasonModal();
+
+ // 延迟一小段时间确保弹窗完全关闭
+ setTimeout(() => {
+ // 模拟点击上架按钮的事件对象
+ const mockEvent = {
+ stopPropagation: function () { },
+ currentTarget: {
+ dataset: {
+ id: currentRejectSupply.id
+ }
+ }
+ };
+
+ // 设置自动上架标志
+ this.setData({ autoPublishAfterEdit: true });
+
+ // 调用上架方法
+ this.preparePublishSupply(mockEvent);
+ }, 100);
+ },
+
+
+ // 选择图片方法 - 修复添加照片功能
+ chooseImage: function (e) {
+ const type = e.currentTarget.dataset.type; // 获取操作类型:new或edit
+ let currentImages = [];
+
+ // 根据类型获取当前已选择的图片列表
+ if (type === 'new') {
+ currentImages = this.data.newSupply.imageUrls || [];
+ } else {
+ currentImages = this.data.editSupply.imageUrls || [];
+ }
+
+ // 计算还能选择的图片数量
+ const maxCount = 5 - currentImages.length;
+ if (maxCount <= 0) {
+ wx.showToast({
+ title: '最多只能上传5张图片',
+ icon: 'none',
+ duration: 2000
+ });
+ return;
+ }
+
+ // 调用微信小程序的图片选择API
+ wx.chooseImage({
+ count: maxCount,
+ sizeType: ['compressed'], // 压缩图片以减小尺寸
+ sourceType: ['album', 'camera'], // 可以从相册选择或拍照
+ success: (res) => {
+ // 获取选择的图片临时文件路径
+ const tempFilePaths = res.tempFilePaths;
+
+ // 合并已选择的图片和新选择的图片
+ const updatedImages = [...currentImages, ...tempFilePaths];
+
+ // 根据类型更新数据
+ if (type === 'new') {
+ this.setData({
+ 'newSupply.imageUrls': updatedImages
+ });
+ } else {
+ this.setData({
+ 'editSupply.imageUrls': updatedImages
+ });
+ }
+
+ console.log(`成功选择了${tempFilePaths.length}张图片,当前共${updatedImages.length}张`);
+ },
+ fail: (err) => {
+ console.error('选择图片失败:', err);
+ if (err.errMsg !== 'chooseImage:fail cancel') { // 排除用户主动取消的情况
+ wx.showToast({
+ title: '选择图片失败,请重试',
+ icon: 'none',
+ duration: 2000
+ });
+ }
+ }
+ });
+ },
+
+ // 格式化创建时间
+ formatCreateTime: function (timeValue) {
+ console.log('formatCreateTime - 输入值:', timeValue, '类型:', typeof timeValue);
+
+ if (!timeValue) {
+ console.log('formatCreateTime - 输入为空,返回"无"');
+ return '无';
+ }
+
+ try {
+ // 处理 ISO 8601 格式的字符串 (如: 2025-10-20T08:21:06.000Z)
+ let date;
+
+ if (typeof timeValue === 'string') {
+ // 直接使用 ISO 字符串创建 Date 对象
+ date = new Date(timeValue);
+
+ // 如果日期无效,尝试其他解析方式
+ if (isNaN(date.getTime())) {
+ // 尝试移除可能的额外字符
+ const cleanTime = timeValue.replace(/[^\d\-T:.]/g, '');
+ date = new Date(cleanTime);
+ }
+ } else if (typeof timeValue === 'number') {
+ // 如果是时间戳
+ date = new Date(timeValue);
+ } else {
+ // 其他情况尝试直接创建
+ date = new Date(timeValue);
+ }
+
+ console.log('formatCreateTime - 解析后的Date对象:', date);
+
+ // 检查日期是否有效
+ if (isNaN(date.getTime())) {
+ console.log('formatCreateTime - 日期无效,返回"无"');
+ return '无';
+ }
+
+ // 获取本地时间(考虑时区)
+ const year = date.getFullYear();
+ const month = (date.getMonth() + 1).toString().padStart(2, '0');
+ const day = date.getDate().toString().padStart(2, '0');
+ const hours = date.getHours().toString().padStart(2, '0');
+ const minutes = date.getMinutes().toString().padStart(2, '0');
+
+ const formattedTime = `${year}/${month}/${day} ${hours}:${minutes}`;
+ console.log('formatCreateTime - 格式化结果:', formattedTime);
+
+ return formattedTime;
+ } catch (error) {
+ console.error('时间格式化错误:', error);
+ return timeValue; // 出错时返回原始值
+ }
+ },
+
+ /**
+ * 删除图片
+ */
+ deleteImage: function (e) {
+ const index = e.currentTarget.dataset.index;
+ const type = e.currentTarget.dataset.type || 'new'; // 默认处理new类型
+
+ if (type === 'new') {
+ const imageUrls = this.data.newSupply.imageUrls;
+ imageUrls.splice(index, 1);
+ this.setData({
+ 'newSupply.imageUrls': imageUrls
+ });
+ } else {
+ const imageUrls = this.data.editSupply.imageUrls;
+ imageUrls.splice(index, 1);
+ this.setData({
+ 'editSupply.imageUrls': imageUrls
+ });
+ }
+
+ console.log(`成功删除${type}类型第${index}张图片`);
+ },
+
+ /**
+ * iOS设备检测
+ */
+ isIOS() {
+ const systemInfo = wx.getSystemInfoSync()
+ return systemInfo.platform === 'ios'
+ },
+
+ /**
+ * 阻止触摸移动事件(iOS专用)
+ */
+ blockTouchMove() {
+ // 添加全局触摸事件监听器
+ this.touchMoveHandler = (e) => {
+ e.preventDefault()
+ e.stopPropagation()
+ }
+
+ // 在页面根元素上阻止触摸移动
+ this.setData({
+ touchMoveBlocked: true
+ })
+ },
+
+ /**
+ * 恢复触摸移动事件(iOS专用)
+ */
+ unblockTouchMove() {
+ this.touchMoveHandler = null
+
+ // 移除触摸事件阻止
+ this.setData({
+ touchMoveBlocked: false
+ })
+ },
+
+ // 处理创建货源弹窗中的规格搜索输入
+ onSpecSearchInput(e) {
+ const keyword = e.detail.value.toLowerCase().trim();
+ this.setData({
+ specSearchKeyword: keyword
+ });
+ // 过滤规格选项
+ this.filterSpecOptions(keyword, 'create');
+ },
+
+ // 处理编辑货源弹窗中的规格搜索输入
+ onEditSpecSearchInput(e) {
+ const keyword = e.detail.value.toLowerCase().trim();
+ this.setData({
+ editSpecSearchKeyword: keyword
+ });
+ // 过滤规格选项
+ this.filterSpecOptions(keyword, 'edit');
+ },
+
+ // 过滤规格选项的通用函数
+ filterSpecOptions(keyword, type) {
+ const specOptions = this.data.specOptions;
+ let filteredOptions = specOptions;
+
+ if (keyword) {
+ filteredOptions = specOptions.filter(option => {
+ return option.toLowerCase().includes(keyword);
+ });
+
+ // 如果有匹配的规格选项,自动填充第一个匹配项
+ if (filteredOptions.length > 0) {
+ if (type === 'create') {
+ const firstMatchIndex = specOptions.indexOf(filteredOptions[0]);
+ this.setData({
+ 'newSupply.spec': filteredOptions[0],
+ 'newSupply.specIndex': firstMatchIndex
+ });
+ } else if (type === 'edit') {
+ const firstMatchIndex = specOptions.indexOf(filteredOptions[0]);
+ this.setData({
+ 'editSupply.spec': filteredOptions[0],
+ 'editSupply.specIndex': firstMatchIndex
+ });
+ }
+ }
+ } else {
+ // 当关键词为空时,重置规格选择
+ if (type === 'create') {
+ this.setData({
+ 'newSupply.spec': '',
+ 'newSupply.specIndex': 0
+ });
+ } else if (type === 'edit') {
+ this.setData({
+ 'editSupply.spec': '',
+ 'editSupply.specIndex': 0
+ });
+ }
+ }
+
+ if (type === 'create') {
+ this.setData({
+ filteredSpecOptions: filteredOptions
+ });
+ } else if (type === 'edit') {
+ this.setData({
+ filteredEditSpecOptions: filteredOptions
+ });
+ }
+ },
+
+ // 清除规格搜索关键词
+ clearSpecSearch() {
+ this.setData({
+ specSearchKeyword: '',
+ filteredSpecOptions: this.data.specOptions,
+ 'newSupply.spec': '', // 重置规格选择
+ 'newSupply.specIndex': 0 // 重置规格索引
+ });
+ },
+
+ // 清除编辑弹窗中的规格搜索关键词
+ clearEditSpecSearch() {
+ this.setData({
+ editSpecSearchKeyword: '',
+ filteredEditSpecOptions: this.data.specOptions,
+ 'editSupply.spec': '', // 重置规格选择
+ 'editSupply.specIndex': 0 // 重置规格索引
+ });
+ },
+
+ /**
+ * 阻止触摸移动事件(用于WXML绑定)
+ */
+ preventTouchMove(e) {
+ // iOS设备上阻止触摸事件冒泡和默认行为
+ if (this.isIOS() && this.data.touchMoveBlocked) {
+ e.preventDefault()
+ e.stopPropagation()
+ return false
+ }
+ },
+
+ /**
+ * 输入框触摸事件处理(防止iOS抖动)
+ */
+ onInputTouchStart(e) {
+ // 阻止输入框触摸事件冒泡到页面
+ if (this.isIOS()) {
+ e.stopPropagation()
+ }
+ },
+
+ /**
+ * 输入框触摸移动事件处理(防止iOS抖动)
+ */
+ onInputTouchMove(e) {
+ // 完全阻止输入框区域的触摸移动事件
+ if (this.isIOS()) {
+ e.preventDefault()
+ e.stopPropagation()
+ return false
+ }
+ },
+
+ /**
+ * 弹窗触摸开始事件处理(增强iOS触摸锁定)
+ */
+ onModalTouchStart(e) {
+ // 在iOS设备上阻止弹窗区域的触摸事件冒泡到页面
+ if (this.isIOS()) {
+ e.stopPropagation()
+ }
+ },
+
+ /**
+ * 弹窗触摸移动事件处理(增强iOS触摸锁定)
+ */
+ onModalTouchMove(e) {
+ // 完全阻止弹窗区域的触摸移动事件传播到页面
+ if (this.isIOS()) {
+ e.preventDefault()
+ e.stopPropagation()
+ return false
+ }
+ },
+
+ // 商品名称选择弹窗相关函数
+ openNameSelectModal() {
+ // 设置当前选中的索引
+ let currentName = '';
+ if (this.data.showEditModal && this.data.editSupply.name) {
+ currentName = this.data.editSupply.name;
+ } else {
+ currentName = this.data.newSupply.name;
+ }
+ const index = currentName ? this.data.productNameOptions.indexOf(currentName) : -1;
+
+ // 通过全局数据控制自定义tab-bar的显示状态
+ const app = getApp();
+ if (app && app.globalData) {
+ app.globalData.showTabBar = false;
+ }
+
+ this.setData({
+ showNameSelectModal: true,
+ selectedNameIndex: index >= 0 ? index : -1,
+ showTabBar: false // 隐藏底部tab-bar
+ });
+ },
+
+ closeNameSelectModal() {
+ // 通过全局数据控制自定义tab-bar的显示状态
+ const app = getApp();
+ if (app && app.globalData) {
+ app.globalData.showTabBar = true;
+ }
+
+ this.setData({
+ showNameSelectModal: false,
+ showTabBar: true // 显示底部tab-bar
+ });
+ },
+
+ onNameSelect(e) {
+ const index = e.currentTarget.dataset.index;
+ this.setData({
+ selectedNameIndex: index
+ });
+ },
+
+ confirmNameSelection() {
+ if (this.data.selectedNameIndex >= 0) {
+ const selectedName = this.data.productNameOptions[this.data.selectedNameIndex];
+
+ // 通过全局数据控制自定义tab-bar的显示状态
+ const app = getApp();
+ if (app && app.globalData) {
+ app.globalData.showTabBar = true;
+ }
+
+ // 根据当前是编辑还是创建模式,更新对应的对象
+ if (this.data.showEditModal) {
+ this.setData({
+ 'editSupply.name': selectedName,
+ showNameSelectModal: false,
+ showTabBar: true // 显示底部tab-bar
+ });
+ } else {
+ const newSupply = this.data.newSupply;
+ newSupply.name = selectedName;
+ this.setData({
+ newSupply: newSupply,
+ showNameSelectModal: false,
+ showTabBar: true // 显示底部tab-bar
+ });
+ }
+ }
+ },
+
+ // 蛋黄选择弹窗相关函数
+ openYolkSelectModal() {
+ // 设置当前选中的索引
+ let currentYolk = '';
+ if (this.data.showEditModal && this.data.editSupply.yolk) {
+ currentYolk = this.data.editSupply.yolk;
+ } else {
+ currentYolk = this.data.newSupply.yolk;
+ }
+ const index = currentYolk ? this.data.yolkOptions.indexOf(currentYolk) : -1;
+
+ // 通过全局数据控制自定义tab-bar的显示状态
+ const app = getApp();
+ if (app && app.globalData) {
+ app.globalData.showTabBar = false;
+ }
+
+ this.setData({
+ showYolkSelectModal: true,
+ selectedYolkIndex: index >= 0 ? index : -1,
+ showTabBar: false // 隐藏底部tab-bar
+ });
+ },
+
+ closeYolkSelectModal() {
+ // 通过全局数据控制自定义tab-bar的显示状态
+ const app = getApp();
+ if (app && app.globalData) {
+ app.globalData.showTabBar = true;
+ }
+
+ this.setData({
+ showYolkSelectModal: false,
+ showTabBar: true // 显示底部tab-bar
+ });
+ },
+
+ onYolkSelect(e) {
+ const index = e.currentTarget.dataset.index;
+ this.setData({
+ selectedYolkIndex: index
+ });
+ },
+
+ confirmYolkSelection() {
+ if (this.data.selectedYolkIndex >= 0) {
+ const selectedYolk = this.data.yolkOptions[this.data.selectedYolkIndex];
+
+ // 通过全局数据控制自定义tab-bar的显示状态
+ const app = getApp();
+ if (app && app.globalData) {
+ app.globalData.showTabBar = true;
+ }
+
+ // 根据当前是编辑还是创建模式,更新对应的对象
+ if (this.data.showEditModal) {
+ this.setData({
+ 'editSupply.yolk': selectedYolk,
+ 'editSupply.yolkIndex': this.data.selectedYolkIndex,
+ showYolkSelectModal: false,
+ showTabBar: true // 显示底部tab-bar
+ });
+ } else {
+ const newSupply = this.data.newSupply;
+ newSupply.yolk = selectedYolk;
+ newSupply.yolkIndex = this.data.selectedYolkIndex;
+ this.setData({
+ newSupply: newSupply,
+ showYolkSelectModal: false,
+ showTabBar: true // 显示底部tab-bar
+ });
+ }
+ }
+ },
+
+ // 联系客服
+ contactCustomerService() {
+ wx.showModal({
+ title: '客服电话',
+ content: '123456',
+ showCancel: true,
+ cancelText: '取消',
+ confirmText: '拨打',
+ success: (res) => {
+ if (res.confirm) {
+ wx.makePhoneCall({
+ phoneNumber: '123456',
+ success: () => {
+ console.log('拨打电话成功');
+ },
+ fail: (err) => {
+ console.error('拨打电话失败', err);
+ wx.showToast({
+ title: '拨打电话失败',
+ icon: 'none'
+ });
+ }
+ });
+ }
+ }
+ });
+ }
+})
diff --git a/pages/seller/index.json b/pages/seller/index.json
new file mode 100644
index 0000000..7ef5329
--- /dev/null
+++ b/pages/seller/index.json
@@ -0,0 +1,5 @@
+{
+ "usingComponents": {},
+ "enablePullDownRefresh": true,
+ "backgroundTextStyle": "dark"
+}
\ No newline at end of file
diff --git a/pages/seller/index.wxml b/pages/seller/index.wxml
new file mode 100644
index 0000000..8d86685
--- /dev/null
+++ b/pages/seller/index.wxml
@@ -0,0 +1,833 @@
+
+
+ 我的鸡蛋货源
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 已上架货源 ({{publishedSupplies.length}})
+
+ ▼
+ ▲
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 暂无图片
+
+
+
+
+
+
+
+
+
+
+
+
+ {{(item.currentImageIndex || 0) + 1}}/{{item.imageUrls.length}}
+
+
+
+
+
+
+
+ {{item.name}}
+ 已上架
+
+ 蛋黄: {{item.yolk || '无'}}
+ 规格: {{item.spec || '无'}}
+ 件数: {{item.minOrder}}件
+ 斤重: {{item.grossWeight || ''}}斤
+ 地区: {{item.region || '未设置'}}
+ 创建时间: {{item.formattedCreatedAt}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+ 点击加载更多已上架货源
+
+
+
+ 没有更多已上架货源了
+
+
+
+
+ 暂无已上架的货源
+
+
+
+
+
+
+
+ 审核中的货源 ({{pendingSupplies.length}})
+
+ ▼
+ ▲
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 暂无图片
+
+
+
+
+
+
+
+
+
+
+
+
+ {{(item.currentImageIndex || 0) + 1}}/{{item.imageUrls.length}}
+
+
+
+
+
+
+
+ {{item.name}}
+ 审核中
+
+ 蛋黄: {{item.yolk || '无'}}
+ 规格: {{item.spec || '无'}}
+ 件数: {{item.minOrder}}件
+ 斤重: {{item.grossWeight || ''}}斤
+ 地区: {{item.region || '未设置'}}
+ 创建时间: {{item.formattedCreatedAt}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+ 点击加载更多审核中货源
+
+
+
+ 没有更多审核中货源了
+
+
+
+
+ 暂无审核中的货源
+
+
+
+
+
+
+
+ 审核失败的货源 ({{rejectedSupplies.length}})
+
+ ▼
+ ▲
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 暂无图片
+
+
+
+
+
+
+
+
+
+
+
+
+ {{(item.currentImageIndex || 0) + 1}}/{{item.imageUrls.length}}
+
+
+
+
+
+
+
+ {{item.name}}
+ 审核失败
+
+ 蛋黄: {{item.yolk || '无'}}
+ 规格: {{item.spec || '无'}}
+ 件数: {{item.minOrder}}件
+ 斤重: {{item.grossWeight || ''}}斤
+ 地区: {{item.region || '未设置'}}
+ 创建时间: {{item.formattedCreatedAt}}
+
+
+ 审核失败原因:点击查看
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+ 点击加载更多审核失败货源
+
+
+
+ 没有更多审核失败货源了
+
+
+
+
+ 暂无审核失败的货源
+
+
+
+
+
+
+
+ 下架状态货源 ({{draftSupplies.length}})
+
+ ▼
+ ▲
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 暂无图片
+
+
+
+
+
+
+
+
+
+
+
+
+ {{(item.currentImageIndex || 0) + 1}}/{{item.imageUrls.length}}
+
+
+
+
+
+
+
+ {{item.name}}
+ 已隐藏
+ 已下架
+ 草稿
+
+ 蛋黄: {{item.yolk || '无'}}
+ 规格: {{item.spec || '无'}}
+ 件数: {{item.minOrder}}件
+ 斤重: {{item.grossWeight || ''}}斤
+ 地区: {{item.region || '未设置'}}
+ 创建时间: {{item.formattedCreatedAt}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 加载中...
+
+
+ 点击加载更多下架状态货源
+
+
+
+ 没有更多下架状态货源了
+
+
+
+
+ 暂无下架状态的货源
+
+
+
+
+
+
+
+
+ ×
+
+
+ 创建货源
+
+
+ 商品图片
+
+
+
+
+
+ ×
+
+
+
+ +
+
+
+ 最多上传5张图片
+
+
+ 商品名称
+
+
+ {{newSupply.name || '请选择商品名称'}}
+ ▼
+
+
+
+ 蛋黄
+
+
+ {{newSupply.yolk || '请选择蛋黄类型'}}
+ ▼
+
+
+
+ 规格
+
+
+
+ {{newSupply.spec || '请选择规格'}}
+ ▼
+
+
+
+ 价格
+
+
+ 件数
+
+
+ 斤重
+
+
+
+ 地区
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+ 编辑货源
+
+
+ 商品图片
+
+
+
+
+
+ ×
+
+
+
+ +
+
+
+ 最多上传5张图片
+
+
+ 商品名称
+
+
+ {{editSupply.name || '请选择商品名称'}}
+ ▼
+
+
+ 蛋黄
+
+
+ {{editSupply.yolk || '请选择蛋黄类型'}}
+ ▼
+
+
+
+ 规格
+
+
+
+ {{editSupply.spec || '请选择规格'}}
+ ▼
+
+
+
+
+
+ 价格
+
+
+ 件数
+
+
+ 斤重
+
+
+
+ 地区
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+
+
+ 审核失败原因
+ ×
+
+
+
+
+ {{rejectReason}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 确定
+
+
+
+
+
+ {{item}}
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 确定
+
+
+
+
+
+ {{item}}
+
+
+
+
+
+
+
+
+
+
+ 取消
+ 确定
+
+
+
+
+
+
+
+ ✕
+
+
+
+
+
+
+
+ {{item}}
+
+
+
+
+
+
+
+
+
+ 提示
+
+
+ 您还没有授权登录
+
+
+
+
+
+
+
+
+
+
+
+
+ 授权登录
+
+
+ 请授权获取您的手机号用于登录
+
+
+
+
+
+
+
+
+
+
+
+
+ 完善个人信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/seller/index.wxss b/pages/seller/index.wxss
new file mode 100644
index 0000000..88d76bd
--- /dev/null
+++ b/pages/seller/index.wxss
@@ -0,0 +1,295 @@
+/* pages/seller/index.wxss */
+/* 立体玻璃质感按钮基础样式 */
+.glass-btn {
+ position: relative;
+ overflow: hidden;
+ border: none;
+ padding: 28rpx 40rpx;
+ font-size: 32rpx;
+ font-weight: 600;
+ border-radius: 16rpx;
+ box-shadow:
+ 0 8rpx 24rpx rgba(0, 0, 0, 0.15),
+ 0 0 0 1rpx rgba(255, 255, 255, 0.3) inset,
+ 0 1rpx 0 rgba(255, 255, 255, 0.2) inset;
+ text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2);
+ transition: all 0.3s ease;
+ background: rgba(255, 255, 255, 0.8);
+ backdrop-filter: blur(10rpx);
+ -webkit-backdrop-filter: blur(10rpx);
+ white-space: nowrap;
+ width: auto;
+ min-width: 80%;
+ text-align: center;
+}
+
+/* 按压效果 */
+.glass-btn:active {
+ transform: translateY(2rpx);
+ box-shadow:
+ 0 4rpx 12rpx rgba(0, 0, 0, 0.1),
+ 0 0 0 1rpx rgba(255, 255, 255, 0.2) inset,
+ 0 1rpx 0 rgba(255, 255, 255, 0.1) inset;
+}
+
+/* 主按钮 - 蓝色玻璃效果 */
+.primary-glass-btn {
+ background: rgba(22, 119, 255, 0.7);
+ color: white;
+ box-shadow:
+ 0 8rpx 24rpx rgba(22, 119, 255, 0.3),
+ 0 0 0 1rpx rgba(255, 255, 255, 0.3) inset,
+ 0 1rpx 0 rgba(255, 255, 255, 0.2) inset;
+}
+
+/* 联系客服按钮样式 */
+.customer-service-btn {
+ background: #f0f0f0;
+ color: black;
+ font-size: 30rpx;
+ width: 70rpx;
+ height: 80rpx;
+ line-height: 70rpx;
+ padding: 0;
+ border-radius: 500rpx;
+ border: 1rpx solid #d9d9d9;
+ box-shadow:
+ 0 4rpx 16rpx rgba(0, 0, 0, 0.1),
+ 0 1rpx 0 rgba(255, 255, 255, 0.5) inset;
+ transition: all 0.3s ease;
+ white-space: nowrap;
+ text-align: center;
+}
+
+.customer-service-btn:active {
+ transform: translateY(2rpx);
+ background: #f5f5f5;
+ box-shadow:
+ 0 2rpx 8rpx rgba(0, 0, 0, 0.08),
+ 0 1rpx 0 rgba(255, 255, 255, 0.3) inset;
+}
+
+/* 登录授权弹窗样式 - 专门用于登录相关弹窗 */
+.auth-modal-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.5);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 999;
+}
+
+.auth-modal-container {
+ background-color: white;
+ border-radius: 16rpx;
+ width: 80%;
+ padding: 40rpx;
+}
+
+.auth-modal-title {
+ text-align: center;
+ margin-bottom: 30rpx;
+}
+
+.auth-modal-title text {
+ font-size: 36rpx;
+ font-weight: bold;
+}
+
+.auth-modal-content {
+ text-align: center;
+ margin-bottom: 40rpx;
+ color: #666;
+}
+
+.auth-modal-content text {
+ font-size: 32rpx;
+}
+
+.auth-modal-buttons {
+ text-align: center;
+}
+
+.auth-primary-button {
+ background-color: #1677ff;
+ color: white;
+ width: 100%;
+ border-radius: 8rpx;
+ margin-bottom: 20rpx;
+ border: none;
+}
+
+.auth-cancel-button {
+ background: none;
+ color: #666;
+ border: none;
+}
+
+/* 头像选择样式 */
+.auth-avatar-section {
+ text-align: center;
+ margin-bottom: 40rpx;
+}
+
+.auth-avatar-wrapper {
+ padding: 0;
+ background: none;
+ border: none;
+}
+
+.auth-avatar {
+ width: 160rpx;
+ height: 160rpx;
+ border-radius: 50%;
+}
+
+/* 表单样式 */
+.auth-form-group {
+ margin-bottom: 30rpx;
+}
+
+.auth-form-label {
+ font-size: 28rpx;
+ margin-bottom: 10rpx;
+ display: block;
+}
+
+.auth-form-input {
+ border: 1rpx solid #eee;
+ border-radius: 8rpx;
+ padding: 20rpx;
+ width: 100%;
+ max-width: 100%;
+ box-sizing: border-box;
+ font-size: 28rpx;
+}
+
+.auth-form-actions {
+ text-align: center;
+ margin-top: 40rpx;
+}
+
+.auth-confirm-button {
+ background-color: #07c160;
+ color: white;
+ width: 100%;
+ border-radius: 8rpx;
+ border: none;
+}
+
+/* 加载更多样式 */
+.load-more {
+ text-align: center;
+ padding: 30rpx;
+ color: #666;
+ background-color: #f9f9f9;
+ border-radius: 8rpx;
+ margin: 20rpx 0;
+}
+
+.loading-text {
+ color: #999;
+ font-size: 26rpx;
+}
+
+.load-more-text {
+ color: #1677ff;
+ font-size: 26rpx;
+ padding: 15rpx 30rpx;
+ border: 1rpx solid #1677ff;
+ border-radius: 8rpx;
+ display: inline-block;
+ background-color: white;
+}
+
+.no-more {
+ text-align: center;
+ padding: 30rpx;
+ color: #999;
+ font-size: 26rpx;
+ background-color: #f9f9f9;
+ border-radius: 8rpx;
+ margin: 20rpx 0;
+}
+
+/* 页面滚动锁定样式 */
+.page-scroll-lock {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ overflow: hidden;
+ height: 100vh;
+
+ /* iOS设备特殊锁定机制 */
+ -webkit-overflow-scrolling: auto;
+ touch-action: none;
+ pointer-events: none;
+
+ /* iOS设备硬件加速处理 */
+ transform: translateZ(0);
+ -webkit-transform: translateZ(0);
+}
+
+/* iOS设备子元素交互修复 */
+.page-scroll-lock view,
+.page-scroll-lock text,
+.page-scroll-lock image,
+.page-scroll-lock button,
+.page-scroll-lock input,
+.page-scroll-lock textarea,
+.page-scroll-lock scroll-view,
+.page-scroll-lock swiper,
+.page-scroll-lock navigator,
+.page-scroll-lock picker,
+.page-scroll-lock slider,
+.page-scroll-lock switch {
+ pointer-events: auto;
+}
+
+/* 弹窗输入框防抖动样式 */
+.modal-content .input {
+ -webkit-appearance: none;
+ appearance: none;
+ -webkit-tap-highlight-color: transparent;
+ tap-highlight-color: transparent;
+ outline: none;
+ -webkit-user-select: text;
+ user-select: text;
+ -webkit-touch-callout: none;
+ touch-callout: none;
+}
+
+/* 弹窗容器硬件加速 */
+.modal-content {
+ will-change: transform;
+ -webkit-will-change: transform;
+}
+
+/* 输入框容器稳定性增强 */
+.modal-content input,
+.modal-content textarea {
+ transform: translateZ(0);
+ -webkit-transform: translateZ(0);
+ perspective: 1000px;
+ -webkit-perspective: 1000px;
+}
+
+/* iOS输入框防抖优化 */
+.modal-content .input {
+ -webkit-appearance: none;
+ appearance: none;
+ -webkit-tap-highlight-color: transparent;
+ touch-action: manipulation;
+ -webkit-touch-callout: none;
+ -webkit-user-select: text;
+ user-select: text;
+ -webkit-transform: translateZ(0);
+ transform: translateZ(0);
+ will-change: transform;
+}
\ No newline at end of file
diff --git a/pages/settlement/index.js b/pages/settlement/index.js
new file mode 100644
index 0000000..137250b
--- /dev/null
+++ b/pages/settlement/index.js
@@ -0,0 +1,1164 @@
+// pages/settlement/settlement.js
+Page({
+ data: {
+ // 是否显示引导页
+ showGuidePage: true,
+ // 当前步骤
+ currentStep: 0,
+
+ // 身份选择
+ collaborationid: '', // 合作商身份ID (原selectedIdentity)
+ showIdentityError: false,
+
+ // 基本信息
+ company: '', // 客户公司名称 (原companyName)
+ showCompanyNameError: false,
+ companyNameError: '',
+ province: '',
+ city: '',
+ district: '',
+ detailedaddress: '', // 详细地址 (原detailAddress)
+ showRegionError: false,
+ regionError: '',
+ cooperation: '', // 合作模式 (原selectedCooperation)
+ showCooperationError: false,
+ cooperationError: '',
+
+ // 上传资料
+ businesslicenseurl: null, // 营业执照URL (原businessLicenseFile)
+ proofurl: null, // 动物检疫证明URL (原animalQuarantineFile)
+ idCardFile: null, // 身份证文件 (保持不变)
+ brandurl: null, // 品牌授权链URL (原brandAuthFile)
+
+ // 审核状态
+ partnerstatus: '', // 合作商状态 (原auditStatus),初始为空而不是默认审核中
+ reasonforfailure: '营业执照图片不清晰,无法识别关键信息。请重新上传清晰的LICENSE照片。',
+
+ // 登录弹窗相关
+ showAuthModal: false,
+ loginModalTitle: '请先登录',
+ loginModalContent: '为了您的账户安全,请先完成手机号登录',
+ showLoginButton: true
+ },
+
+ onLoad(options) {
+ console.log('settlement页面加载,options:', options);
+
+ // 检查是否有status参数,如果有则显示审核状态
+ if (options.status) {
+ console.log('检测到status参数:', options.status);
+ // 检查是否有preSubmitData
+ const preSubmitData = wx.getStorageSync('preSubmitData');
+ if (preSubmitData) {
+ console.log('找到preSubmitData,显示审核状态页面');
+ this.setData({
+ showGuidePage: false,
+ currentStep: 3,
+ partnerstatus: options.status
+ });
+ return; // 直接返回,不执行后续逻辑
+ }
+ }
+
+ // 检查是否有保存的入驻进度
+ this.loadSettlementProgress();
+
+ // 如果有保存的进度,直接跳过引导页
+ if (this.data.currentStep > 0) {
+ this.setData({
+ showGuidePage: false
+ });
+ }
+
+ // 检查是否是从首页登录返回的
+ const pendingReturnPath = wx.getStorageSync('pendingReturnPath');
+ if (pendingReturnPath === 'settlement') {
+ console.log('检测到从首页登录返回,清除标记并自动提交申请');
+ // 清除返回路径标记
+ wx.removeStorageSync('pendingReturnPath');
+
+ // 延迟一下确保页面完全加载
+ setTimeout(() => {
+ // 检查是否有保存的表单数据
+ const savedProgress = wx.getStorageSync('settlementProgress');
+ if (savedProgress && savedProgress.formData) {
+ console.log('发现保存的表单数据,自动提交申请');
+ // 恢复表单数据
+ this.setData(savedProgress.formData);
+ // 自动提交申请
+ this.submitApplication();
+ }
+ }, 500);
+ }
+ },
+
+ onUnload() {
+ // 页面卸载时保存进度(除了审核通过状态)
+ if (this.data.partnerstatus !== 'approved') {
+ this.saveSettlementProgress();
+ }
+ },
+
+ // 加载入驻进度
+ loadSettlementProgress() {
+ const settlementData = wx.getStorageSync('settlement_data');
+ if (settlementData) {
+ // 映射旧字段名到新字段名(兼容性处理)
+ const mappedData = {
+ currentStep: settlementData.currentStep,
+ collaborationid: settlementData.collaborationid || settlementData.selectedIdentity,
+ company: settlementData.company || settlementData.companyName,
+ province: settlementData.province,
+ city: settlementData.city,
+ district: settlementData.district,
+ detailedaddress: settlementData.detailedaddress || settlementData.detailAddress,
+ cooperation: settlementData.cooperation || settlementData.selectedCooperation,
+ businesslicenseurl: settlementData.businesslicenseurl || settlementData.businessLicenseFile,
+ proofurl: settlementData.proofurl || settlementData.animalQuarantineFile,
+ idCardFile: settlementData.idCardFile,
+ brandurl: settlementData.brandurl || settlementData.brandAuthFile,
+ agreementChecked: settlementData.agreementChecked,
+ partnerstatus: settlementData.partnerstatus || settlementData.auditStatus
+ };
+
+ this.setData(mappedData);
+ console.log('加载入驻进度:', mappedData);
+ }
+ },
+
+ // 保存入驻进度
+ saveSettlementProgress() {
+ const settlementData = {
+ currentStep: this.data.currentStep,
+ collaborationid: this.data.collaborationid, // 合作商身份ID (原selectedIdentity)
+ company: this.data.company, // 客户公司名称 (原companyName)
+ province: this.data.province,
+ city: this.data.city,
+ district: this.data.district,
+ detailedaddress: this.data.detailedaddress, // 详细地址 (原detailAddress)
+ cooperation: this.data.cooperation, // 合作模式 (原selectedCooperation)
+ businesslicenseurl: this.data.businesslicenseurl, // 营业执照URL (原businessLicenseFile)
+ proofurl: this.data.proofurl, // 动物检疫证明URL (原animalQuarantineFile)
+ idCardFile: this.data.idCardFile,
+ brandurl: this.data.brandurl, // 品牌授权链URL (原brandAuthFile)
+ agreementChecked: this.data.agreementChecked,
+ partnerstatus: this.data.partnerstatus // 合作商状态 (原auditStatus)
+ };
+
+ wx.setStorageSync('settlement_data', settlementData);
+ console.log('保存入驻进度');
+ },
+
+ // 清除入驻进度
+ clearSettlementProgress() {
+ wx.removeStorageSync('settlement_data');
+ console.log('清除入驻进度');
+ },
+
+ // 更新全局入驻状态
+ updateGlobalSettlementStatus(status) {
+ // 可以在这里调用全局状态管理
+ const app = getApp();
+ if (app && app.updateSettlementStatus) {
+ app.updateSettlementStatus(status);
+ }
+
+ // 同时保存到本地存储
+ wx.setStorageSync('settlement_status', status);
+ },
+
+ // 开始入驻流程
+ startSettlement: async function() {
+ console.log('开始入驻流程');
+
+ try {
+ // 检查登录状态
+ const userId = wx.getStorageSync('userId');
+ const userInfo = wx.getStorageSync('userInfo');
+
+ if (!userId || !userInfo) {
+ console.log('用户未登录,显示登录弹窗');
+ this.setData({
+ showAuthModal: true,
+ loginModalTitle: '请先登录',
+ loginModalContent: '为了您的账户安全,请先完成手机号登录',
+ showLoginButton: true
+ });
+ return;
+ }
+
+ // 检查数据库中是否存在入驻信息
+ console.log('用户已登录,检查入驻信息');
+ await this.syncSettlementStatus();
+
+ // 根据入驻状态处理
+ if (this.data.partnerstatus === 'approved' || this.data.partnerstatus === 'underreview') {
+ console.log('用户已入驻或审核中,直接进入相应页面');
+ this.setData({
+ showGuidePage: false,
+ currentStep: 3 // 审核状态页面
+ });
+ } else {
+ console.log('用户未入驻,正常进行入驻流程');
+ this.setData({
+ showGuidePage: false
+ });
+ }
+ } catch (error) {
+ console.error('检查入驻状态时出错:', error);
+ wx.showToast({
+ title: '系统繁忙,请稍后再试',
+ icon: 'none'
+ });
+ }
+ },
+
+ // 下一步
+ nextStep() {
+ switch (this.data.currentStep) {
+ case 0:
+ // 验证身份选择
+ if (!this.data.collaborationid) { // 使用数据库字段名
+ this.setData({ showIdentityError: true });
+ return;
+ }
+ this.setData({
+ currentStep: 1,
+ showIdentityError: false
+ });
+ break;
+
+ case 1:
+ // 验证基本信息
+ let valid = true;
+
+ if (!this.data.company || !this.data.company.trim()) { // 使用数据库字段名,添加空值检查
+ this.setData({ showCompanyNameError: true });
+ valid = false;
+ } else {
+ this.setData({ showCompanyNameError: false });
+ }
+
+ if (!this.data.province || !this.data.city || !this.data.district) {
+ this.setData({ showRegionError: true });
+ valid = false;
+ } else {
+ this.setData({ showRegionError: false });
+ }
+
+ if (!this.data.cooperation) { // 使用数据库字段名
+ this.setData({ showCooperationError: true });
+ valid = false;
+ } else {
+ this.setData({ showCooperationError: false });
+ }
+
+ if (valid) {
+ this.setData({ currentStep: 2 });
+ }
+ break;
+
+ default:
+ break;
+ }
+ },
+
+ // 上一步
+ prevStep() {
+ if (this.data.currentStep > 0) {
+ this.setData({ currentStep: this.data.currentStep - 1 });
+ }
+ },
+
+ // 选择身份
+ selectIdentity(e) {
+ const identity = e.currentTarget.dataset.identity;
+ this.setData({
+ collaborationid: identity, // 使用数据库字段名
+ showIdentityError: false
+ });
+ },
+
+ // 公司名称输入(带实时验证)
+ onCompanyNameInput(e) {
+ const value = e.detail.value.trim();
+ let showError = false;
+ let errorMessage = '';
+
+ if (value.length > 0) {
+ if (value.length < 2) {
+ showError = true;
+ errorMessage = '公司名称至少需要2个字符';
+ } else if (value.length > 50) {
+ showError = true;
+ errorMessage = '公司名称不能超过50个字符';
+ }
+ }
+
+ this.setData({
+ company: value, // 使用数据库字段名
+ showCompanyNameError: showError,
+ companyNameError: errorMessage
+ });
+ },
+
+ // 公司名称获得焦点
+ onCompanyNameFocus(e) {
+ // 清除错误状态,让用户重新输入
+ if (this.data.showCompanyNameError) {
+ this.setData({
+ showCompanyNameError: false,
+ companyNameError: ''
+ });
+ }
+ },
+
+ // 公司名称失去焦点验证
+ onCompanyNameBlur() {
+ if (!this.data.company || !this.data.company.trim()) { // 使用数据库字段名,添加空值检查
+ this.setData({
+ showCompanyNameError: true,
+ companyNameError: '请输入公司名称'
+ });
+ }
+ },
+
+ // 地区选择(带验证)
+ onRegionChange(e) {
+ const value = e.detail.value;
+ const province = value[0] || '';
+ const city = value[1] || '';
+ const district = value[2] || '';
+
+ let showError = false;
+ let errorMessage = '';
+
+ if (!province || !city || !district) {
+ showError = true;
+ errorMessage = '请选择完整的省市区信息';
+ }
+
+ this.setData({
+ province: province,
+ city: city,
+ district: district,
+ showRegionError: showError,
+ regionError: errorMessage
+ });
+ },
+
+ // 详细地址输入
+ onDetailAddressInput(e) {
+ this.setData({ detailedaddress: e.detail.value }); // 使用数据库字段名
+ },
+
+ // 详细地址获得焦点
+ onDetailAddressFocus(e) {
+ // 可以在这里添加焦点处理逻辑,比如滚动到视图等
+ console.log('详细地址输入框获得焦点');
+ },
+
+ // 选择合作模式(带验证)
+ selectCooperation(e) {
+ const value = e.currentTarget.dataset.value;
+
+ this.setData({
+ cooperation: value, // 使用数据库字段名
+ showCooperationError: false,
+ cooperationError: ''
+ });
+ },
+
+ // 上传LICENSE
+ uploadBusinessLicense() {
+ wx.chooseImage({
+ count: 1,
+ sizeType: ['compressed'],
+ sourceType: ['album', 'camera'],
+ success: (res) => {
+ const tempFilePaths = res.tempFilePaths;
+ this.setData({
+ businesslicenseurl: { // 使用数据库字段名
+ path: tempFilePaths[0],
+ name: `营业执照_${new Date().getTime()}.jpg`
+ }
+ });
+ }
+ });
+ },
+
+ // 删除LICENSE
+ deleteBusinessLicense() {
+ this.setData({ businesslicenseurl: null }); // 使用数据库字段名
+ },
+
+ // 上传动物检疫合格证明
+ uploadAnimalQuarantine() {
+ wx.chooseImage({
+ count: 1,
+ sizeType: ['compressed'],
+ sourceType: ['album', 'camera'],
+ success: (res) => {
+ const tempFilePaths = res.tempFilePaths;
+ this.setData({
+ proofurl: { // 使用数据库字段名
+ path: tempFilePaths[0],
+ name: `动物检疫合格证明_${new Date().getTime()}.jpg`
+ }
+ });
+ }
+ });
+ },
+
+ // 删除动物检疫合格证明
+ deleteAnimalQuarantine() {
+ this.setData({ proofurl: null }); // 使用数据库字段名
+ },
+
+ // 上传法人身份证
+ uploadIdCard() {
+ wx.chooseImage({
+ count: 1,
+ sizeType: ['compressed'],
+ sourceType: ['album', 'camera'],
+ success: (res) => {
+ const tempFilePaths = res.tempFilePaths;
+ this.setData({
+ idCardFile: {
+ path: tempFilePaths[0],
+ name: `法人身份证_${new Date().getTime()}.jpg`
+ }
+ });
+ }
+ });
+ },
+
+ // 删除法人身份证
+ deleteIdCard() {
+ this.setData({ idCardFile: null });
+ },
+
+ // 上传品牌授权链文件
+ uploadBrandAuth() {
+ wx.chooseImage({
+ count: 1,
+ sizeType: ['compressed'],
+ sourceType: ['album', 'camera'],
+ success: (res) => {
+ const tempFilePaths = res.tempFilePaths;
+ this.setData({
+ brandurl: { // 使用数据库字段名
+ path: tempFilePaths[0],
+ name: `品牌授权链_${new Date().getTime()}.jpg`
+ }
+ });
+ }
+ });
+ },
+
+ // 删除品牌授权链文件
+ deleteBrandAuth() {
+ this.setData({ brandurl: null }); // 使用数据库字段名
+ },
+
+ // 获取文件类型显示名称
+ getFileTypeDisplayName(fileType) {
+ const typeNames = {
+ 'businessLicense': '营业执照',
+ 'animalQuarantine': '动物检疫合格证明',
+ 'idCard': '法人身份证',
+ 'brandAuth': '品牌授权链文件'
+ };
+ return typeNames[fileType] || '文件';
+ },
+
+ // 上传文件到服务器
+ async uploadFileToServer(filePath, fileType) {
+ try {
+ const API = require('../../utils/api.js');
+ console.log(`开始上传${this.getFileTypeDisplayName(fileType)}文件:`, filePath);
+
+ const result = await API.uploadSettlementFile(filePath, fileType);
+
+ // 修正返回值处理 - API.uploadSettlementFile直接返回data对象
+ if (result && result.fileUrl) {
+ console.log(`${this.getFileTypeDisplayName(fileType)}上传成功:`, result.fileUrl);
+ return result.fileUrl;
+ } else {
+ throw new Error(`${this.getFileTypeDisplayName(fileType)}上传失败`);
+ }
+ } catch (error) {
+ console.error(`${this.getFileTypeDisplayName(fileType)}上传失败:`, error);
+ wx.showToast({
+ title: `${this.getFileTypeDisplayName(fileType)}上传失败`,
+ icon: 'none'
+ });
+ throw error;
+ }
+ },
+
+
+
+ // 提交申请
+ async submitApplication() {
+ // 检查用户是否已登录
+ const openid = wx.getStorageSync('openid');
+ const userId = wx.getStorageSync('userId');
+ console.log('检查用户登录状态,openid:', openid);
+
+ if (!openid) {
+ console.log('用户未登录,调用首页授权登录');
+ this.goToAuthLogin();
+ return;
+ }
+
+ // 先上传所有文件
+ wx.showLoading({
+ title: '正在上传文件...',
+ mask: true
+ });
+
+ const uploadedFiles = {};
+
+ try {
+ // 上传LICENSE
+ if (this.data.businesslicenseurl) { // 使用数据库字段名
+ uploadedFiles.businessLicenseFile = await this.uploadFileToServer(
+ this.data.businesslicenseurl.path,
+ 'businessLicense'
+ );
+ }
+
+ // 上传动物检疫合格证明
+ if (this.data.proofurl) { // 使用数据库字段名
+ uploadedFiles.animalQuarantineFile = await this.uploadFileToServer(
+ this.data.proofurl.path,
+ 'animalQuarantine'
+ );
+ }
+
+ // 上传品牌授权链文件
+ if (this.data.brandurl) { // 使用数据库字段名
+ uploadedFiles.brandAuthFile = await this.uploadFileToServer(
+ this.data.brandurl.path,
+ 'brandAuth'
+ );
+ }
+
+ console.log('所有文件上传完成:', uploadedFiles);
+ // 移除return语句,让代码继续执行到提交数据部分
+ } catch (error) {
+ console.error('文件上传失败:', error);
+ wx.showToast({
+ title: '文件上传失败',
+ icon: 'none'
+ });
+ return; // 修改为return而不是return null
+ } finally {
+ // 确保无论成功失败都会隐藏loading
+ wx.hideLoading();
+ }
+
+ // 准备提交数据(与后端API要求的字段名匹配)
+ // 尝试多种方式获取手机号,确保contactPhone不为空
+ // 1. 先尝试直接获取常见的手机号存储键
+ let contactPhone = wx.getStorageSync('phone') ||
+ wx.getStorageSync('userPhone') ||
+ wx.getStorageSync('mobile') ||
+ '';
+
+ // 2. 如果上述方式没获取到,尝试从userInfo对象中获取
+ if (!contactPhone) {
+ const userInfo = wx.getStorageSync('userInfo');
+ if (userInfo && userInfo.phoneNumber && userInfo.phoneNumber !== '未绑定') {
+ contactPhone = userInfo.phoneNumber;
+ }
+ }
+
+ console.log('最终获取到的手机号:', contactPhone);
+
+ // 根据后端API要求构建submitData对象(使用独立的省市区字段)
+ const submitData = {
+ openid: openid,
+ collaborationid: this.data.collaborationid, // 合作商身份ID
+ company: this.data.company || '', // 客户公司名称
+ province: this.data.province, // 省份
+ city: this.data.city, // 城市
+ district: this.data.district, // 区县
+ detailedaddress: this.data.detailedaddress || '', // 详细地址(即使为空也要传递)
+ cooperation: this.data.cooperation === '货源委托' ? 'wholesale' : this.data.cooperation, // 合作模式映射为后端期望的值
+ phoneNumber: contactPhone, // 后端期望的字段名是phoneNumber
+ businesslicenseurl: uploadedFiles.businessLicenseFile || '', // 营业执照URL
+ proofurl: uploadedFiles.animalQuarantineFile || '', // 动物检疫证明URL
+ brandurl: uploadedFiles.brandAuthFile || '', // 品牌授权链URL
+ userId: userId
+ };
+
+ // 特别记录详细地址字段,确保它被正确提交
+ console.log('详细地址字段值:', submitData.detailedaddress);
+ console.log('详细地址字段类型:', typeof submitData.detailedaddress);
+ console.log('详细地址字段是否存在:', 'detailedaddress' in submitData);
+
+ // 记录省市区字段内容
+ console.log('省市区字段内容(提交数据):', submitData.province, submitData.city, submitData.district);
+
+ // 保存提交数据到本地存储,供首页检查使用
+ wx.setStorageSync('preSubmitData', submitData);
+ console.log('已保存preSubmitData:', submitData);
+
+ // 检查必填字段是否为空
+ console.log('提交数据检查 - contactPhone:', contactPhone);
+ console.log('提交数据检查 - identityType:', this.data.collaborationid);
+ console.log('提交数据检查 - cooperationMode:', this.data.cooperation);
+ console.log('提交数据检查 - cooperationValue:', submitData.cooperation); // 检查映射后的值
+ console.log('提交数据检查 - contactName:', this.data.company);
+ console.log('提交数据检查 - 省市区:', submitData.province, submitData.city, submitData.district);
+ // 检查所有字段是否完整
+ console.log('提交数据完整性检查:', {
+ hasOpenid: !!submitData.openid,
+ hasCollaborationid: !!submitData.collaborationid,
+ hasCompany: !!submitData.company,
+ hasProvince: !!submitData.province,
+ hasCity: !!submitData.city,
+ hasDistrict: !!submitData.district,
+ hasDetailedAddress: !!submitData.detailedaddress,
+ hasCooperation: !!submitData.cooperation,
+ hasPhoneNumber: !!submitData.phoneNumber,
+ hasBusinessLicense: !!submitData.businesslicenseurl,
+ hasProofUrl: !!submitData.proofurl,
+ hasBrandUrl: !!submitData.brandurl
+ });
+
+ // 表单验证 - 检查必填字段
+ if (!openid) {
+ wx.showToast({
+ title: '请先登录',
+ icon: 'none'
+ });
+ return;
+ }
+
+ if (!this.data.collaborationid) {
+ wx.showToast({
+ title: '请选择合作商身份',
+ icon: 'none'
+ });
+ return;
+ }
+
+ if (!this.data.cooperation) {
+ wx.showToast({
+ title: '请选择合作模式',
+ icon: 'none'
+ });
+ return;
+ }
+
+ if (!this.data.company) {
+ wx.showToast({
+ title: '请填写公司名称',
+ icon: 'none'
+ });
+ return;
+ }
+
+ if (!contactPhone) {
+ wx.showToast({
+ title: '请先完成手机号授权',
+ icon: 'none'
+ });
+ // 显示授权弹窗
+ this.setData({
+ showAuthModal: true,
+ loginModalTitle: '请完成手机号授权',
+ loginModalContent: '入驻申请需要您的手机号信息,请完成授权'
+ });
+ return;
+ }
+
+ // 验证省市区字段是否填写完整(用于构建region字段)
+ if (!this.data.province || !this.data.city || !this.data.district) {
+ wx.showToast({
+ title: '请填写完整地址',
+ icon: 'none'
+ });
+ return;
+ }
+
+ // 记录省市区字段内容
+ console.log('省市区字段内容:', this.data.province, this.data.city, this.data.district);
+
+ // 文件上传现在为选填,不再强制要求
+ console.log('文件上传状态:', {
+ businessLicenseFile: !!uploadedFiles.businessLicenseFile,
+ animalQuarantineFile: !!uploadedFiles.animalQuarantineFile,
+ brandAuthFile: !!uploadedFiles.brandAuthFile
+ });
+
+ try {
+ // 调用后端API提交入驻申请
+ // 使用API.BASE_URL构建正确的请求路径
+ const API = require('../../utils/api');
+ console.log('开始提交入驻申请,API地址:', API.BASE_URL + '/api/settlement/submit');
+ console.log('提交的完整数据:', submitData);
+ // 详细检查后端必需的关键字段(使用独立的省市区字段)
+ const requiredFieldsCheck = {
+ openid: { value: submitData.openid, exists: !!submitData.openid },
+ collaborationid: { value: submitData.collaborationid, exists: !!submitData.collaborationid },
+ cooperation: { value: submitData.cooperation, exists: !!submitData.cooperation },
+ company: { value: submitData.company, exists: !!submitData.company },
+ phoneNumber: { value: submitData.phoneNumber, exists: !!submitData.phoneNumber },
+ province: { value: submitData.province, exists: !!submitData.province },
+ city: { value: submitData.city, exists: !!submitData.city },
+ district: { value: submitData.district, exists: !!submitData.district }
+ };
+
+ console.log('后端必需字段详细检查:', requiredFieldsCheck);
+
+ // 检查是否所有必需字段都已填写
+ const allRequiredFieldsExist = Object.values(requiredFieldsCheck).every(field => field.exists);
+ console.log('是否所有后端必需字段都已填写:', allRequiredFieldsExist);
+
+ const result = await new Promise((resolve, reject) => {
+ wx.request({
+ url: API.BASE_URL + '/api/settlement/submit',
+ method: 'POST',
+ data: submitData,
+ success: (res) => {
+ console.log('API请求成功,原始响应:', res);
+ resolve(res.data);
+ },
+ fail: (err) => {
+ console.error('API请求失败:', err);
+ reject(err);
+ }
+ });
+ });
+ console.log('入驻申请提交结果:', result);
+ console.log('请求状态码:', result.code);
+ console.log('请求消息:', result.message);
+
+ if (result && result.success) {
+ // 更新本地状态
+ wx.setStorageSync('settlementStatus', 'underreview');
+ // 保存applicationId到本地存储,供撤回功能使用
+ const appId = result.data?.id || null;
+ if (appId) {
+ wx.setStorageSync('applicationId', appId);
+ }
+
+ this.setData({
+ partnerstatus: 'underreview', // 使用数据库字段名 (原auditStatus)
+ applicationId: appId
+ });
+
+ wx.showToast({
+ title: '提交成功,等待审核',
+ icon: 'none',
+ duration: 2000
+ });
+
+ // 跳转到审核状态页面
+ this.setData({
+ currentStep: 3 // 设置为第4步(审核状态页面)
+ });
+
+ // 清除进度数据,因为已经提交了
+ this.clearSettlementProgress();
+ } else {
+ wx.showToast({
+ title: result.message || '提交失败',
+ icon: 'none'
+ });
+ }
+ } catch (error) {
+ console.error('提交入驻申请失败:', error);
+ wx.showToast({
+ title: '提交失败,请重试',
+ icon: 'none'
+ });
+ }
+ },
+
+ // 跳转到首页进行授权登录
+ async goToAuthLogin() {
+ // 保存当前表单数据
+ this.saveSettlementProgress();
+
+ console.log('用户未登录,在当前页面调用登录方法');
+
+ // 显示登录提示
+ wx.showToast({
+ title: '请先登录',
+ icon: 'none',
+ duration: 1500,
+ complete: () => {
+ // 直接在当前页面调用首页的登录逻辑
+ setTimeout(() => {
+ this.performDirectLogin();
+ }, 1500);
+ }
+ });
+ },
+
+ // 在当前页面直接执行登录逻辑
+ async performDirectLogin() {
+ console.log('显示登录弹窗,让用户主动授权');
+
+ // 显示登录弹窗
+ this.setData({
+ showAuthModal: true
+ });
+ },
+
+ // 关闭登录弹窗
+ closeAuthModal() {
+ this.setData({
+ showAuthModal: false
+ });
+ },
+
+ // 处理手机号授权
+ async onGetPhoneNumber(e) {
+ console.log('用户点击了手机号授权按钮', e.detail);
+
+ // 关闭登录弹窗
+ this.setData({
+ showAuthModal: false
+ });
+
+ if (e.detail.errMsg === 'getPhoneNumber:ok') {
+ // 用户同意授权
+ wx.showLoading({
+ title: '登录中...',
+ mask: true
+ });
+
+ try {
+ // 调用API解密手机号
+ const app = getApp();
+ if (app && app.uploadPhoneNumberData) {
+ const result = await app.uploadPhoneNumberData(e.detail);
+
+ if (result && result.success) {
+ // 保存用户信息到全局和本地存储
+ const userInfo = {
+ nickName: '微信用户',
+ avatarUrl: '/images/default-avatar.png',
+ phoneNumber: result.phoneNumber || '未绑定',
+ gender: 0,
+ country: '',
+ province: '',
+ city: '',
+ language: 'zh_CN'
+ };
+
+ // 保存到全局数据
+ app.globalData.userInfo = userInfo;
+
+ // 保存到本地存储
+ wx.setStorageSync('userInfo', userInfo);
+
+ console.log('用户信息已保存:', userInfo);
+
+ wx.hideLoading();
+ wx.showToast({
+ title: '登录成功',
+ icon: 'success',
+ duration: 1500,
+ complete: () => {
+ // 登录成功后继续提交申请
+ setTimeout(() => {
+ this.submitApplication();
+ }, 1500);
+ }
+ });
+ } else {
+ throw new Error(result.message || '登录失败');
+ }
+ } else {
+ // 备用方案:模拟登录
+ await this.performBackupLogin();
+ }
+ } catch (error) {
+ wx.hideLoading();
+ console.error('手机号授权登录失败:', error);
+ wx.showToast({
+ title: '登录失败,请重试',
+ icon: 'none'
+ });
+ }
+ } else {
+ // 用户拒绝授权
+ wx.showToast({
+ title: '需要手机号授权才能继续',
+ icon: 'none'
+ });
+ }
+ },
+
+ // 备用登录方案
+ async performBackupLogin() {
+ wx.showLoading({
+ title: '登录中...',
+ mask: true
+ });
+
+ try {
+ // 模拟登录流程
+ const mockOpenid = 'settlement_login_' + Date.now();
+ const mockUserId = 'settlement_user_' + Date.now();
+
+ // 存储模拟登录信息
+ wx.setStorageSync('openid', mockOpenid);
+ wx.setStorageSync('userId', mockUserId);
+
+ // 保存用户信息到全局和本地存储
+ const userInfo = {
+ nickName: '微信用户',
+ avatarUrl: '/images/default-avatar.png',
+ phoneNumber: '未绑定',
+ gender: 0,
+ country: '',
+ province: '',
+ city: '',
+ language: 'zh_CN'
+ };
+
+ // 保存到全局数据
+ const app = getApp();
+ if (app) {
+ app.globalData.userInfo = userInfo;
+ }
+
+ // 保存到本地存储
+ wx.setStorageSync('userInfo', userInfo);
+
+ console.log('备用登录用户信息已保存:', userInfo);
+
+ wx.hideLoading();
+ wx.showToast({
+ title: '登录成功',
+ icon: 'success',
+ duration: 1500,
+ complete: () => {
+ // 登录成功后继续提交申请
+ setTimeout(() => {
+ this.submitApplication();
+ }, 1500);
+ }
+ });
+ } catch (error) {
+ wx.hideLoading();
+ console.error('备用登录失败:', error);
+ wx.showToast({
+ title: '登录失败,请重试',
+ icon: 'none'
+ });
+ }
+ },
+
+
+
+ // 撤回备案
+ async withdrawApplication() {
+ wx.showModal({
+ title: '确认撤回',
+ content: '确定要撤回备案申请吗?撤回后可以重新提交。',
+ success: async (res) => {
+ if (res.confirm) {
+ try {
+ // 获取用户的openid
+ const openid = wx.getStorageSync('openid');
+ console.log('准备撤回申请,openid:', openid);
+
+ if (!openid) {
+ wx.showToast({
+ title: '请先登录',
+ icon: 'none'
+ });
+ return;
+ }
+
+ // 调用API撤回申请,不再需要applicationId,只需要用户openid
+ const API = require('../../utils/api.js');
+ const result = await API.withdrawSettlementApplication(openid);
+
+ if (result && result.success) {
+ // 清除本地状态
+ wx.removeStorageSync('preSubmitData');
+ wx.removeStorageSync('applicationId');
+ wx.setStorageSync('hasSubmittedSettlement', false);
+ wx.removeStorageSync('settlementStatus');
+
+ // 重置页面状态
+ this.setData({
+ currentStep: 0,
+ partnerstatus: '', // 使用数据库字段名 (原auditStatus)
+ applicationId: null
+ });
+
+ wx.showToast({
+ title: '已撤回申请',
+ icon: 'success'
+ });
+ } else {
+ wx.showToast({
+ title: result.message || '撤回失败',
+ icon: 'none'
+ });
+ }
+ } catch (error) {
+ console.error('撤回申请失败:', error);
+ wx.showToast({
+ title: '撤回失败,请重试',
+ icon: 'none'
+ });
+ }
+ }
+ }
+ });
+ },
+
+ // 审核中我知道了
+ knowAudit() {
+ // 直接返回首页,不显示提示
+ wx.reLaunch({
+ url: '/pages/index/index'
+ });
+ },
+
+ // 重新提交备案
+ async resubmitApplication() {
+ try {
+ const API = require('../../utils/api.js');
+ const applicationId = wx.getStorageSync('applicationId');
+
+ if (!applicationId) {
+ wx.showToast({
+ title: '未找到申请记录',
+ icon: 'none'
+ });
+ return;
+ }
+
+ wx.showLoading({
+ title: '正在重新提交...',
+ mask: true
+ });
+
+ const result = await API.resubmitSettlementApplication(applicationId);
+
+ wx.hideLoading();
+
+ if (result && result.success) {
+ // 更新本地状态
+ wx.setStorageSync('settlementStatus', 'underreview');
+
+ this.setData({
+ partnerstatus: 'underreview' // 使用数据库字段名 (原auditStatus)
+ });
+
+ wx.showToast({
+ title: '重新提交成功',
+ icon: 'success'
+ });
+ } else {
+ wx.showToast({
+ title: result.message || '重新提交失败',
+ icon: 'none'
+ });
+ }
+ } catch (error) {
+ wx.hideLoading();
+ console.error('重新提交申请失败:', error);
+ wx.showToast({
+ title: '重新提交失败,请重试',
+ icon: 'none'
+ });
+ }
+ },
+
+ // 完成申请
+ completeApplication() {
+ // 更新入驻状态为审核通过
+ this.updateGlobalSettlementStatus('approved');
+
+ wx.showToast({
+ title: '感谢您的提交,我们将尽快与您联系!',
+ icon: 'success'
+ });
+
+ // 延迟返回上一页
+ setTimeout(() => {
+ wx.navigateBack();
+ }, 1500);
+ },
+
+ // 重置申请流程
+ resetApplication() {
+ this.setData({
+ currentStep: 0,
+ collaborationid: '', // 使用数据库字段名 (原selectedIdentity)
+ showIdentityError: false,
+ company: '', // 使用数据库字段名 (原companyName)
+ showCompanyNameError: false,
+ province: '',
+ city: '',
+ district: '',
+ showRegionError: false,
+ detailedaddress: '', // 使用数据库字段名 (原detailAddress)
+ cooperation: '', // 使用数据库字段名 (原selectedCooperation)
+ showCooperationError: false,
+ businesslicenseurl: null, // 使用数据库字段名 (原businessLicenseFile)
+ proofurl: null, // 使用数据库字段名 (原animalQuarantineFile)
+ idCardFile: null,
+ brandurl: null, // 使用数据库字段名 (原brandAuthFile)
+ partnerstatus: 'underreview', // 使用数据库字段名 (原auditStatus)
+ showAuthModal: false,
+ applicationId: null,
+ auditFailedReason: ''
+ });
+
+ // 清除保存的进度
+ this.clearSettlementProgress();
+ },
+
+ // 从服务器同步入驻状态
+ async syncSettlementStatus() {
+ try {
+ const userId = wx.getStorageSync('userId');
+
+ if (!userId) {
+ console.log('用户未登录,跳过状态同步');
+ return;
+ }
+
+ const API = require('../../utils/api.js');
+ const result = await API.getSettlementStatus(userId);
+
+ if (result && result.success && result.data) {
+ const serverData = result.data;
+
+ // 更新本地状态
+ wx.setStorageSync('hasSubmittedSettlement', true);
+ // 只有在有实际状态值时才设置,避免空值时默认为审核中
+ wx.setStorageSync('settlementStatus', serverData.partnerstatus || '');
+
+ if (serverData.id) {
+ wx.setStorageSync('applicationId', serverData.id);
+ }
+
+ // 更新页面状态
+ this.setData({
+ partnerstatus: serverData.partnerstatus || '', // 使用数据库字段名 (原auditStatus),不设置默认值
+ applicationId: serverData.id
+ });
+
+ console.log('已同步服务器入驻状态:', serverData.partnerstatus);
+ }
+ } catch (error) {
+ console.error('同步入驻状态失败:', error);
+ }
+ }
+});
\ No newline at end of file
diff --git a/pages/settlement/index.json b/pages/settlement/index.json
new file mode 100644
index 0000000..19146bf
--- /dev/null
+++ b/pages/settlement/index.json
@@ -0,0 +1,4 @@
+{
+ "usingComponents": {},
+ "navigationBarTitleText": "立即入驻"
+}
\ No newline at end of file
diff --git a/pages/settlement/index.wxml b/pages/settlement/index.wxml
new file mode 100644
index 0000000..16e5bdb
--- /dev/null
+++ b/pages/settlement/index.wxml
@@ -0,0 +1,367 @@
+
+
+
+
+
+
+ 成为供应商
+ 完成入驻后即可发布货源,开展鸡蛋贸易
+
+
+
+
+
+
+
+
+
+ 1
+ 选择身份
+
+
+
+ 2
+ 基本信息
+
+
+
+ 3
+ 上传资料
+
+
+
+ 4
+ 审核状态
+
+
+
+
+
+
+ 请选择您的身份
+
+
+
+ 🐔
+
+
+ 鸡场
+ 养殖场主、生产商身份
+
+
+
+
+ 💰
+
+
+ 贸易商
+ 经销商、批发商身份
+
+
+
+ 请选择身份
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ✓
+
+ {{companyNameError || '请输入公司名称'}}
+
+
+
+
+
+
+
+ {{province || city || district ? province + ' ' + city + ' ' + district : '请选择省市区'}}
+ ▼
+
+
+ {{regionError || '请选择所在地区'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 货源委托
+
+
+
+ 自主定价销售
+
+
+
+ 区域包场合作
+
+
+
+ 其他
+
+
+ {{cooperationError || '请选择合作模式'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{collaborationid === 'chicken' ? '鸡场营业执照(选填)' : '贸易商营业执照(选填)'}}
+
+ +
+ 点击上传营业执照
+ 支持jpg、png格式,大小不超过5M
+
+
+
+ 📄
+ {{businesslicenseurl.name}}
+ 删除
+
+
+
+
+
+
+ 动物检疫合格证明(选填)
+
+ +
+ 点击上传动物检疫合格证明
+ 支持jpg、png格式,大小不超过5M
+
+
+
+ 📄
+ {{proofurl.name}}
+ 删除
+
+
+
+
+
+
+ 法人身份证正反面(选填)
+
+ +
+ 点击上传法人身份证正反面
+ 支持jpg、png格式,大小不超过5M
+
+
+
+ 📄
+ {{idCardFile.name}}
+ 删除
+
+
+
+
+
+ 品牌授权链文件
+
+ +
+ 点击上传品牌授权链文件
+ 支持jpg、png格式,大小不超过5M
+
+
+
+ 📄
+ {{brandurl.name}}
+ 删除
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ⏳
+
+ 审核中
+
+ 你已成功提交小程序备案,请等待审核。
+ 你可以撤回备案
+
+
+
+
+
+
+
+
+ ❌
+
+ 审核失败
+
+ 很抱歉,您的备案申请未通过审核
+
+
+
+ 审核失败原因:
+ {{auditFailedReason}}
+
+
+
+
+
+
+
+
+ ✅
+
+ 审核通过
+
+ 恭喜!您的备案申请已通过审核。
+ 我们将尽快与您联系后续事宜。
+
+
+
+
+
+
+
+ 🤝
+
+ 合作中
+
+ 您已成功成为我们的合作伙伴!
+ 感谢您的信任与支持。
+
+
+
+
+
+
+
+ 📋
+
+ 未合作
+
+ 感谢您的关注,期待未来有机会合作。
+ 如有需要可重新申请。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 📱
+ 为了提供更好的服务,需要获取您的手机号进行身份验证
+
+
+
+
+ 授权后即可完成入驻申请
+
+
+
\ No newline at end of file
diff --git a/pages/settlement/index.wxss b/pages/settlement/index.wxss
new file mode 100644
index 0000000..2eae155
--- /dev/null
+++ b/pages/settlement/index.wxss
@@ -0,0 +1,1697 @@
+/* 优化版页面容器 - 现代化设计 */
+.settlement-page {
+ min-height: 100vh;
+ background: linear-gradient(135deg, #f7f7f7 0%, #e8f5e8 100%);
+ padding: 0;
+ /* 真机优化 */
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+ text-size-adjust: 100%;
+ /* 防止iOS橡皮筋效果 */
+ overscroll-behavior: contain;
+ /* 页面加载动画 */
+ animation: pageFadeIn 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+@keyframes pageFadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(20rpx);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.container {
+ background: transparent;
+ border-radius: 0;
+ box-shadow: none;
+ overflow: hidden;
+ margin: 0;
+ /* 容器动画 */
+ animation: containerSlideIn 0.8s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+@keyframes containerSlideIn {
+ from {
+ opacity: 0;
+ transform: translateX(-30rpx);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+/* 优化版内容区域 - 现代化设计 */
+.content {
+ padding: 32rpx 28rpx;
+ background: transparent;
+ /* 真机优化 */
+ min-height: calc(100vh - 120rpx);
+ box-sizing: border-box;
+ max-width: 100%;
+ overflow: hidden;
+ /* 内容区域动画 */
+ animation: contentFadeIn 1s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+/* 引导页样式 */
+.guide-page {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 80vh;
+ padding: 0 40rpx;
+}
+
+.guide-content {
+ text-align: center;
+ width: 100%;
+}
+
+.guide-title {
+ font-size: 48rpx;
+ font-weight: bold;
+ color: #333;
+ margin-bottom: 20rpx;
+}
+
+.guide-description {
+ font-size: 28rpx;
+ color: #666;
+ margin-bottom: 60rpx;
+ line-height: 40rpx;
+}
+
+.guide-button {
+ width: 100%;
+ height: 96rpx;
+ font-size: 32rpx;
+ border-radius: 48rpx;
+}
+
+@keyframes contentFadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(30rpx);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+/* 真机全局优化 */
+page {
+ /* 防止iOS输入框缩放 */
+ -webkit-text-size-adjust: 100% !important;
+ text-size-adjust: 100% !important;
+ /* 改善触摸体验 */
+ -webkit-tap-highlight-color: transparent;
+ /* 防止橡皮筋效果 */
+ overscroll-behavior: contain;
+ /* 改善滚动性能 */
+ -webkit-overflow-scrolling: touch;
+ /* 防止iOS Safari底部导航栏遮挡 */
+ padding-bottom: constant(safe-area-inset-bottom);
+ padding-bottom: env(safe-area-inset-bottom);
+}
+
+/* iOS特殊优化 */
+@supports (-webkit-touch-callout: none) {
+ .form-input {
+ /* iOS输入框优化 */
+ -webkit-appearance: none;
+ border-radius: 12rpx;
+ /* 防止iOS内阴影 */
+ box-shadow: none !important;
+ /* 改善iOS字体渲染 */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ }
+}
+
+/* Android特殊优化 */
+@supports not (-webkit-touch-callout: none) {
+ .form-input {
+ /* Android输入框优化 */
+ line-height: normal;
+ /* 防止Android默认边框 */
+ border: 2rpx solid #e5e5e5;
+ }
+}
+
+/* 输入框全局优化 */
+input, textarea {
+ /* 防止iOS缩放 */
+ font-size: 30rpx !important;
+ transform-origin: left top;
+ /* 改善输入体验 */
+ -webkit-appearance: none;
+ appearance: none;
+ border-radius: 12rpx;
+ outline: none;
+ /* 防止阴影 */
+ box-shadow: none !important;
+ /* 改善触摸体验 */
+ touch-action: manipulation;
+ /* 光标颜色 */
+ caret-color: #07C160;
+ /* 防止自动放大 */
+ transform: scale(1);
+ /* 改善字体渲染 */
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
+ /* 防止iOS输入框背景变黄 */
+ -webkit-autofill: none;
+ background-color: #fff !important;
+}
+
+/* 按钮全局优化 */
+button {
+ /* 防止iOS缩放 */
+ font-size: 30rpx !important;
+ /* 改善触摸体验 */
+ touch-action: manipulation;
+ -webkit-tap-highlight-color: transparent;
+ /* 防止默认样式 */
+ border: none;
+ outline: none;
+ background: none;
+ padding: 0;
+ margin: 0;
+ /* 防止iOS按钮默认样式 */
+ -webkit-appearance: none;
+ appearance: none;
+ border-radius: 0;
+ /* 改善字体渲染 */
+ font-family: inherit;
+}
+
+/* 选择器全局优化 */
+picker {
+ /* 改善触摸体验 */
+ touch-action: manipulation;
+ -webkit-tap-highlight-color: transparent;
+ /* 防止iOS选择器缩放 */
+ font-size: 30rpx !important;
+}
+
+/* 真机滚动优化 */
+.scroll-view {
+ -webkit-overflow-scrolling: touch;
+ scroll-behavior: smooth;
+}
+
+/* 真机触摸反馈优化 */
+.touchable {
+ touch-action: manipulation;
+ -webkit-tap-highlight-color: transparent;
+ user-select: none;
+ -webkit-user-select: none;
+}
+
+/* 响应式优化 - 针对不同屏幕尺寸 */
+@media (max-width: 375px) {
+ /* 小屏幕设备优化 */
+ .form-input {
+ font-size: 26rpx !important;
+ padding: 20rpx 16rpx;
+ min-height: 72rpx;
+ }
+
+ .form-label {
+ font-size: 26rpx;
+ }
+
+ .cooperation-option {
+ padding: 20rpx 16rpx;
+ min-height: 72rpx;
+ }
+
+ .cooperation-text {
+ font-size: 26rpx;
+ }
+}
+
+@media (min-width: 414px) {
+ /* 大屏幕设备优化 */
+ .form-input {
+ font-size: 28rpx !important;
+ padding: 24rpx 20rpx;
+ min-height: 80rpx;
+ }
+
+ .form-label {
+ font-size: 28rpx;
+ }
+
+ .cooperation-option {
+ padding: 24rpx 20rpx;
+ min-height: 80rpx;
+ }
+
+ .cooperation-text {
+ font-size: 28rpx;
+ }
+}
+
+/* 横屏优化 */
+@media (orientation: landscape) {
+ .settlement-page {
+ min-height: 100vh;
+ }
+
+ .content {
+ padding: 16rpx 18rpx;
+ }
+
+ .form-input {
+ min-height: 64rpx;
+ padding: 18rpx 14rpx;
+ }
+
+ .cooperation-option {
+ min-height: 68rpx;
+ padding: 18rpx 14rpx;
+ }
+}
+
+/* 高分辨率屏幕优化 */
+@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
+ .form-input {
+ border-width: 1rpx;
+ }
+
+ .cooperation-option {
+ border-width: 1rpx;
+ }
+}
+
+/* 暗色模式适配 */
+@media (prefers-color-scheme: dark) {
+ .form-input {
+ background-color: #2c2c2e;
+ color: #fff;
+ border-color: #48484a;
+ }
+
+ .form-input::placeholder {
+ color: #8e8e93;
+ }
+
+ .cooperation-option {
+ background-color: #2c2c2e;
+ border-color: #48484a;
+ color: #fff;
+ }
+
+ .cooperation-option.active {
+ background-color: #1c1c1e;
+ border-color: #07C160;
+ }
+}
+
+/* 优化版步骤指示器 - 现代化设计 */
+.step-indicator {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 60rpx;
+ padding: 40rpx 32rpx;
+ background: linear-gradient(135deg, #ffffff 0%, #f8fffe 100%);
+ border-radius: 20rpx;
+ position: relative;
+ box-shadow: 0 8rpx 32rpx rgba(7, 193, 96, 0.08);
+}
+
+.step {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ color: #bbb;
+ font-size: 24rpx;
+ flex: 1;
+ position: relative;
+ z-index: 2;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.step.active {
+ color: #07C160;
+ transform: translateY(-2rpx);
+}
+
+.step-circle {
+ width: 56rpx;
+ height: 56rpx;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 12rpx;
+ font-size: 26rpx;
+ font-weight: 600;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ border: 3rpx solid #e5e5e5;
+ box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
+ position: relative;
+ overflow: hidden;
+}
+
+.step-circle::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.5) 50%, transparent 70%);
+ transform: translateX(-100%);
+ transition: transform 0.6s;
+}
+
+.step.active .step-circle {
+ background: linear-gradient(135deg, #07C160 0%, #06ae56 100%);
+ color: white;
+ border-color: #07C160;
+ box-shadow: 0 6rpx 20rpx rgba(7, 193, 96, 0.3);
+ transform: scale(1.1);
+}
+
+.step.active .step-circle::before {
+ transform: translateX(100%);
+}
+
+.step-line {
+ position: absolute;
+ top: 28rpx;
+ left: 25%;
+ right: 25%;
+ height: 3rpx;
+ background: linear-gradient(90deg, #e5e5e5 0%, #d0d0d0 100%);
+ z-index: 1;
+ border-radius: 2rpx;
+}
+
+.step-line::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 0;
+ background: linear-gradient(90deg, #07C160 0%, #06ae56 100%);
+ border-radius: 2rpx;
+ transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.step.active ~ .step-line::before {
+ width: 100%;
+}
+
+/* 优化版表单区域 - 现代化设计 */
+.section {
+ margin-bottom: 32rpx;
+ background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%);
+ border-radius: 20rpx;
+ padding: 32rpx 28rpx;
+ box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.06);
+ width: 100%;
+ box-sizing: border-box;
+ overflow: hidden;
+ position: relative;
+}
+
+.section::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 0;
+ background: transparent;
+ border-radius: 20rpx 20rpx 0 0;
+}
+
+.section-title {
+ font-size: 32rpx;
+ font-weight: 700;
+ margin-bottom: 28rpx;
+ color: #1a1a1a;
+ display: flex;
+ align-items: center;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ letter-spacing: 0.5rpx;
+}
+
+.required::after {
+ content: '*';
+ color: #FA5151;
+ margin-left: 6rpx;
+ font-weight: 700;
+}
+
+/* 微信风格的表单项 - 针对真机优化 */
+.form-item {
+ margin-bottom: 28rpx;
+ position: relative;
+ width: 100%;
+ box-sizing: border-box;
+ /* 移除overflow: hidden,避免影响子元素点击事件 */
+ overflow: visible;
+}
+
+.form-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 14rpx;
+ padding-left: 8rpx;
+ width: 100%;
+ box-sizing: border-box;
+ position: relative;
+}
+
+.form-label {
+ font-size: 28rpx;
+ color: #000;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ white-space: nowrap;
+ flex-shrink: 0;
+ max-width: 100%;
+ overflow: visible;
+ /* 改善字体渲染 */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ /* 防止文字被截断 */
+ line-height: 1.2;
+ letter-spacing: 0.5rpx;
+}
+
+.form-label.required::after {
+ content: '*';
+ color: #FA5151;
+ margin-left: 6rpx;
+ font-weight: 700;
+}
+
+.input-wrapper {
+ position: relative;
+ width: 100%;
+ max-width: 100%;
+ box-sizing: border-box;
+}
+
+/* 优化版表单输入框 - 现代化设计 */
+.form-input {
+ width: 100%;
+ max-width: 100%;
+ padding: 24rpx 20rpx;
+ padding-right: 45rpx;
+ border: 2rpx solid rgba(7, 193, 96, 0.15);
+ border-radius: 12rpx;
+ font-size: 28rpx;
+ background: linear-gradient(135deg, #ffffff 0%, #fafafa 100%);
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ box-sizing: border-box;
+ min-height: 80rpx;
+ line-height: 1.4;
+ -webkit-tap-highlight-color: transparent;
+ /* 真机优化 */
+ -webkit-appearance: none;
+ appearance: none;
+ outline: none;
+ /* 防止iOS缩放 */
+ font-size: 28rpx !important;
+ transform-origin: left top;
+ /* 改善触摸体验 */
+ touch-action: manipulation;
+ /* 改善输入体验 */
+ caret-color: #07C160;
+ /* 防止溢出 */
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ /* 改善字体渲染 */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
+ font-weight: 400;
+ letter-spacing: 0.3rpx;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
+ /* 输入框获得焦点动画 */
+ position: relative;
+}
+
+.form-input::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ border-radius: 12rpx;
+ background: linear-gradient(135deg, rgba(7, 193, 96, 0.05) 0%, rgba(7, 193, 96, 0.02) 100%);
+ opacity: 0;
+ transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ z-index: -1;
+}
+
+.form-input:focus {
+ border-color: #07C160;
+ background: linear-gradient(135deg, #ffffff 0%, #f8fff8 100%);
+ box-shadow: 0 4rpx 16rpx rgba(7, 193, 96, 0.15);
+ transform: translateY(-2rpx);
+}
+
+.form-input:focus::before {
+ opacity: 1;
+}
+
+.form-input:active {
+ transform: scale(0.98);
+}
+
+.form-input.error {
+ border-color: #FA5151;
+ background: linear-gradient(135deg, #ffffff 0%, #fff8f8 100%);
+ box-shadow: 0 4rpx 16rpx rgba(250, 81, 81, 0.15);
+}
+
+.form-input::placeholder {
+ color: #999;
+ font-size: 28rpx;
+ font-weight: 400;
+ opacity: 1;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.form-input:focus::placeholder {
+ color: #bbb;
+ opacity: 0.7;
+}
+
+/* placeholder样式优化 */
+.form-input::placeholder {
+ color: #999;
+ font-size: 26rpx;
+ font-weight: 400;
+ opacity: 1;
+ transition: all 0.2s ease;
+}
+
+.form-input-placeholder {
+ color: #999 !important;
+ font-size: 26rpx !important;
+ font-weight: 400 !important;
+ opacity: 1 !important;
+}
+
+.form-input:not(:placeholder-shown) + .input-icon {
+ opacity: 1;
+ transform: scale(1);
+}
+
+.form-input:focus::placeholder {
+ color: #ddd;
+ opacity: 0.7;
+}
+
+/* 输入框激活状态优化 */
+.form-input:not(:placeholder-shown) {
+ border-color: #07C160;
+}
+
+.input-icon {
+ position: absolute;
+ right: 18rpx;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 24rpx;
+ color: #07C160;
+ pointer-events: none;
+ z-index: 2;
+}
+
+.error-message {
+ color: #FA5151;
+ font-size: 26rpx;
+ margin-top: 12rpx;
+ line-height: 1.3;
+ padding: 0;
+ background: transparent;
+ border-radius: 0;
+ font-weight: 400;
+}
+
+/* 优化版地区选择器 - 现代化设计 */
+.region-picker {
+ width: 100%;
+ max-width: 100%;
+ border: 2rpx solid rgba(7, 193, 96, 0.15);
+ border-radius: 12rpx;
+ background: linear-gradient(135deg, #ffffff 0%, #fafafa 100%);
+ font-size: 28rpx;
+ min-height: 80rpx;
+ box-sizing: border-box;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ line-height: 1.4;
+ -webkit-tap-highlight-color: transparent;
+ /* 真机优化 */
+ -webkit-appearance: none;
+ appearance: none;
+ outline: none;
+ touch-action: manipulation;
+ /* 确保picker组件能够正常响应点击事件 */
+ z-index: 1;
+ cursor: pointer;
+ display: block;
+ overflow: visible;
+}
+
+.region-picker .picker-content {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.region-picker .picker-content text {
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ /* 改善字体渲染 */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', Arial, sans-serif;
+ font-weight: 400;
+ letter-spacing: 0.3rpx;
+ font-size: 28rpx;
+}
+
+.picker-content {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ padding: 24rpx 20rpx;
+ box-sizing: border-box;
+}
+
+.picker-arrow {
+ margin-left: 10rpx;
+ font-size: 20rpx;
+ color: #07C160;
+ pointer-events: none;
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.region-picker:focus {
+ border-color: #07C160;
+ background: linear-gradient(135deg, #ffffff 0%, #f8fff8 100%);
+ box-shadow: 0 4rpx 16rpx rgba(7, 193, 96, 0.15);
+ transform: translateY(-2rpx);
+}
+
+.region-picker:focus .picker-arrow {
+ transform: rotate(180deg);
+}
+
+.region-picker:active {
+ /* 移除scale变换,避免点击区域偏移 */
+ background: linear-gradient(135deg, #f8fff8 0%, #ffffff 100%);
+}
+
+.region-picker.placeholder {
+ color: #999;
+ font-size: 28rpx;
+ font-weight: 400;
+}
+
+/* 选中状态优化 */
+.region-picker:not(.placeholder) {
+ border-color: #07C160;
+ color: #000;
+ font-weight: 500;
+}
+
+/* 微信风格的合作模式选择 - 针对真机优化 */
+.cooperation-options {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 20rpx;
+}
+
+.cooperation-option {
+ display: flex;
+ align-items: center;
+ padding: 24rpx 20rpx;
+ border: 2rpx solid #e5e5e5;
+ border-radius: 10rpx;
+ background: #fff;
+ transition: all 0.2s ease;
+ box-sizing: border-box;
+ min-height: 80rpx;
+ position: relative;
+ -webkit-tap-highlight-color: transparent;
+ /* 真机优化 */
+ touch-action: manipulation;
+ cursor: pointer;
+ /* 防止文字选中 */
+ -webkit-user-select: none;
+ user-select: none;
+ /* 改善触摸反馈 */
+ transform: translateZ(0);
+ backface-visibility: hidden;
+ /* 防止溢出 */
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.cooperation-option.active {
+ border-color: #07C160;
+ background: #e8f7ed;
+ box-shadow: 0 2rpx 8rpx rgba(7, 193, 96, 0.15);
+}
+
+.cooperation-option:active {
+ background: #f8f8f8;
+ transform: scale(0.96);
+ transition: all 0.1s ease;
+}
+
+.cooperation-option.active:active {
+ background: #d4ede1;
+ transform: scale(0.96);
+}
+
+.cooperation-icon {
+ width: 36rpx;
+ height: 36rpx;
+ border-radius: 50%;
+ border: 2rpx solid #ddd;
+ margin-right: 20rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.2s ease;
+ position: relative;
+ background: #fff;
+ pointer-events: none;
+ flex-shrink: 0;
+}
+
+.cooperation-option.active .cooperation-icon {
+ border-color: #07C160;
+ background: #07C160;
+ box-shadow: 0 2rpx 6rpx rgba(7, 193, 96, 0.3);
+}
+
+.cooperation-icon::after {
+ content: '✓';
+ color: white;
+ font-size: 22rpx;
+ font-weight: 700;
+ opacity: 0;
+ transform: scale(0.5);
+ transition: all 0.2s ease;
+}
+
+.cooperation-option.active .cooperation-icon::after {
+ opacity: 1;
+ transform: scale(1);
+}
+
+.cooperation-text {
+ flex: 1;
+ font-size: 28rpx;
+ color: #000;
+ font-weight: 400;
+ line-height: 1.3;
+ pointer-events: none;
+}
+
+.cooperation-option.active .cooperation-text {
+ color: #07C160;
+ font-weight: 500;
+}
+
+/* 优化版按钮组 - 现代化设计 */
+.button-group {
+ display: flex;
+ gap: 20rpx;
+ margin-top: 60rpx;
+ position: sticky;
+ bottom: 0;
+ background: linear-gradient(135deg, rgba(247, 247, 247, 0.95) 0%, rgba(232, 245, 232, 0.95) 100%);
+ padding: 32rpx 28rpx;
+ border-top: 1rpx solid rgba(7, 193, 96, 0.1);
+ backdrop-filter: blur(10rpx);
+ border-radius: 24rpx 24rpx 0 0;
+}
+
+.btn {
+ flex: 1;
+ padding: 28rpx 24rpx;
+ border-radius: 16rpx;
+ font-size: 32rpx;
+ font-weight: 600;
+ text-align: center;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ min-height: 88rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ position: relative;
+ overflow: hidden;
+ -webkit-tap-highlight-color: transparent;
+ letter-spacing: 0.5rpx;
+}
+
+.btn::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.2) 50%, transparent 70%);
+ transform: translateX(-100%);
+ transition: transform 0.6s;
+}
+
+.btn:active::before {
+ transform: translateX(100%);
+}
+
+.btn:active {
+ transform: scale(0.96);
+}
+
+.btn-primary {
+ background: linear-gradient(135deg, #07C160 0%, #06ae56 100%);
+ color: white;
+ border: none;
+ box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.3);
+}
+
+.btn-primary:active {
+ background: linear-gradient(135deg, #06ae56 0%, #059d4f 100%);
+ box-shadow: 0 4rpx 16rpx rgba(7, 193, 96, 0.4);
+}
+
+.btn-secondary {
+ background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
+ color: #333;
+ border: 2rpx solid rgba(7, 193, 96, 0.2);
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
+}
+
+.btn-secondary:active {
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
+}
+
+/* 优化版身份选择卡片 - 现代化设计 */
+.identity-options {
+ display: flex;
+ flex-direction: column;
+ gap: 32rpx;
+ margin: 0;
+ padding: 0;
+ /* 卡片容器动画 */
+ animation: cardsSlideIn 1.2s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+@keyframes cardsSlideIn {
+ from {
+ opacity: 0;
+ transform: translateY(40rpx);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.identity-option {
+ display: flex;
+ align-items: center;
+ padding: 40rpx 32rpx;
+ border: 3rpx solid #f0f0f0;
+ border-radius: 24rpx;
+ background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%);
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+ position: relative;
+ box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04);
+ overflow: hidden;
+ cursor: pointer;
+ /* 卡片进入动画 */
+ animation: cardFadeIn 0.6s cubic-bezier(0.4, 0, 0.2, 1) backwards;
+ /* 为不同卡片添加延迟 */
+}
+
+.identity-option:nth-child(1) {
+ animation-delay: 0.1s;
+}
+
+.identity-option:nth-child(2) {
+ animation-delay: 0.2s;
+}
+
+@keyframes cardFadeIn {
+ from {
+ opacity: 0;
+ transform: scale(0.9) translateY(20rpx);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1) translateY(0);
+ }
+}
+
+.identity-option::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(7, 193, 96, 0.05), transparent);
+ transition: left 0.6s;
+}
+
+.identity-option:hover::before {
+ left: 100%;
+}
+
+.identity-option:hover {
+ border-color: rgba(7, 193, 96, 0.3);
+ transform: translateY(-4rpx);
+ box-shadow: 0 12rpx 32rpx rgba(7, 193, 96, 0.15);
+}
+
+.identity-option.selected {
+ border-color: #07C160;
+ background: linear-gradient(135deg, #e8f7ed 0%, #f0faf5 100%);
+ box-shadow: 0 8rpx 32rpx rgba(7, 193, 96, 0.15);
+ transform: translateY(-4rpx);
+ /* 选中状态动画 */
+ animation: cardSelected 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+@keyframes cardSelected {
+ 0% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.05);
+ }
+ 100% {
+ transform: scale(1);
+ }
+}
+
+.identity-option:active {
+ transform: translateY(-2rpx) scale(0.98);
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
+}
+
+.identity-option.selected:active {
+ transform: translateY(-2rpx) scale(0.98);
+ box-shadow: 0 6rpx 24rpx rgba(7, 193, 96, 0.2);
+}
+
+.identity-icon {
+ width: 120rpx;
+ height: 120rpx;
+ background: linear-gradient(135deg, #f7f7f7 0%, #ececec 100%);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 32rpx;
+ color: #666;
+ font-size: 56rpx;
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
+ box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.08);
+ position: relative;
+ overflow: hidden;
+ /* 图标动画 */
+ animation: iconPulse 2s ease-in-out infinite;
+}
+
+@keyframes iconPulse {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.05);
+ }
+}
+
+.identity-icon::before {
+ content: '';
+ position: absolute;
+ top: -50%;
+ left: -50%;
+ width: 200%;
+ height: 200%;
+ background: linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.3) 50%, transparent 70%);
+ transform: rotate(45deg);
+ animation: iconShine 3s ease-in-out infinite;
+}
+
+@keyframes iconShine {
+ 0%, 100% {
+ transform: translateX(-100%) translateY(-100%) rotate(45deg);
+ }
+ 50% {
+ transform: translateX(100%) translateY(100%) rotate(45deg);
+ }
+}
+
+.identity-option:hover .identity-icon {
+ transform: scale(1.1) rotate(5deg);
+ box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.15);
+}
+
+.identity-option.selected .identity-icon {
+ background: linear-gradient(135deg, #07C160 0%, #06ae56 100%);
+ color: white;
+ box-shadow: 0 8rpx 28rpx rgba(7, 193, 96, 0.25);
+ transform: scale(1.1);
+ /* 选中时的特殊动画 */
+ animation: iconSelected 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+@keyframes iconSelected {
+ 0% {
+ transform: scale(1) rotate(0deg);
+ }
+ 50% {
+ transform: scale(1.2) rotate(10deg);
+ }
+ 100% {
+ transform: scale(1.1) rotate(0deg);
+ }
+}
+
+.identity-text {
+ flex: 1;
+ position: relative;
+ z-index: 2;
+ display: flex;
+ flex-direction: column;
+ gap: 8rpx;
+ /* 文本动画 */
+ animation: textFadeIn 0.8s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+@keyframes textFadeIn {
+ from {
+ opacity: 0;
+ transform: translateX(-20rpx);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+.identity-title {
+ font-weight: 700;
+ margin-bottom: 12rpx;
+ font-size: 36rpx;
+ color: #1a1a1a;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ letter-spacing: 0.5rpx;
+ text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.05);
+}
+
+.identity-desc {
+ font-size: 28rpx;
+ color: #888;
+ line-height: 1.5;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ letter-spacing: 0.3rpx;
+ opacity: 0.9;
+}
+
+.identity-option:hover .identity-title {
+ color: #07C160;
+ transform: translateX(4rpx);
+}
+
+.identity-option:hover .identity-desc {
+ color: #555;
+ opacity: 1;
+}
+
+.identity-option.selected .identity-title {
+ color: #07C160;
+ transform: translateX(4rpx);
+}
+
+.identity-option.selected .identity-desc {
+ color: #06ae56;
+ font-weight: 500;
+}
+
+/* 添加选中状态指示器 */
+.identity-option::after {
+ content: '';
+ position: absolute;
+ top: 24rpx;
+ right: 24rpx;
+ width: 32rpx;
+ height: 32rpx;
+ border: 3rpx solid #e0e0e0;
+ border-radius: 50%;
+ background: #fff;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
+}
+
+.identity-option.selected::after {
+ border-color: #07C160;
+ background: #07C160;
+ transform: scale(1.1);
+ box-shadow: 0 4rpx 12rpx rgba(7, 193, 96, 0.3);
+}
+
+.identity-option.selected::before {
+ content: '✓';
+ position: absolute;
+ top: 24rpx;
+ right: 24rpx;
+ width: 32rpx;
+ height: 32rpx;
+ color: white;
+ font-size: 20rpx;
+ font-weight: bold;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 3;
+ opacity: 0;
+ transform: scale(0.5);
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.identity-option.selected::before {
+ opacity: 1;
+ transform: scale(1);
+}
+
+/* 微信风格的上传区域 */
+.upload-area {
+ border: 2rpx dashed #e5e5e5;
+ border-radius: 12rpx;
+ padding: 60rpx 32rpx;
+ text-align: center;
+ background: #fafafa;
+ transition: all 0.2s ease;
+ min-height: 200rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
+
+.upload-area:active {
+ background: #f0f0f0;
+ border-color: #07C160;
+}
+
+.upload-icon {
+ font-size: 48rpx;
+ color: #07C160;
+ margin-bottom: 16rpx;
+}
+
+.upload-text {
+ font-size: 28rpx;
+ color: #000;
+ font-weight: 500;
+ margin-bottom: 4rpx;
+}
+
+.upload-tip {
+ font-size: 24rpx;
+ color: #999;
+ margin-top: 12rpx;
+}
+
+/* 微信风格的已上传文件 */
+.uploaded-file {
+ display: flex;
+ align-items: center;
+ background: #f7f7f7;
+ border-radius: 12rpx;
+ padding: 24rpx;
+ margin-top: 20rpx;
+ transition: all 0.2s ease;
+ border: 1rpx solid #e5e5e5;
+}
+
+.file-icon {
+ color: #07C160;
+ margin-right: 20rpx;
+ font-size: 32rpx;
+}
+
+.file-name {
+ flex: 1;
+ font-size: 28rpx;
+ color: #000;
+ font-weight: 400;
+}
+
+.file-delete {
+ color: #FA5151;
+ font-size: 28rpx;
+ padding: 12rpx;
+}
+
+
+
+/* 微信风格的审核状态 */
+.audit-status {
+ text-align: center;
+ padding: 60rpx 32rpx;
+}
+
+.audit-icon {
+ width: 120rpx;
+ height: 120rpx;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin: 0 auto 32rpx;
+ font-size: 56rpx;
+}
+
+.audit-icon.pending {
+ background-color: #FFF5E6;
+ color: #FF9900;
+}
+
+.audit-icon.failed {
+ background-color: #FFE6E6;
+ color: #FF4D4F;
+}
+
+.audit-icon.success {
+ background-color: #E8F7ED;
+ color: #07C160;
+}
+
+.audit-icon.cooperating {
+ background-color: #E6F7FF;
+ color: #1890FF;
+}
+
+.audit-title {
+ font-size: 36rpx;
+ font-weight: 600;
+ margin-bottom: 24rpx;
+ color: #000;
+}
+
+.audit-desc {
+ font-size: 28rpx;
+ color: #666;
+ margin-bottom: 48rpx;
+ line-height: 1.5;
+}
+
+.audit-reason {
+ background-color: #f7f7f7;
+ border-radius: 12rpx;
+ padding: 24rpx;
+ margin: 32rpx 0;
+ text-align: left;
+ border: 1rpx solid #e5e5e5;
+}
+
+.audit-reason-title {
+ font-weight: 600;
+ margin-bottom: 12rpx;
+ color: #000;
+}
+
+.audit-reason-content {
+ font-size: 26rpx;
+ color: #666;
+ line-height: 1.4;
+}
+
+.btn-audit {
+ margin-top: 32rpx;
+}
+
+
+.protocol-header {
+ padding: 32rpx;
+ text-align: center;
+ font-size: 32rpx;
+ font-weight: 500;
+ border-bottom: 1rpx solid #e5e5e5;
+ position: relative;
+}
+
+.protocol-close {
+ position: absolute;
+ right: 32rpx;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 36rpx;
+ color: #999;
+}
+
+.protocol-body {
+ flex: 1;
+ padding: 32rpx;
+ overflow-y: auto;
+ line-height: 1.5;
+}
+
+.protocol-section {
+ margin-bottom: 32rpx;
+}
+
+.protocol-title {
+ font-weight: 500;
+ margin-bottom: 16rpx;
+ font-size: 28rpx;
+}
+
+.protocol-text {
+ font-size: 26rpx;
+ color: #555;
+ margin-bottom: 8rpx;
+}
+
+.protocol-footer {
+ padding: 24rpx 32rpx;
+ border-top: 1rpx solid #e5e5e5;
+ text-align: center;
+}
+
+.btn-protocol {
+ background-color: #07C160;
+ color: white;
+ border: none;
+ border-radius: 12rpx;
+ padding: 20rpx 40rpx;
+ font-size: 28rpx;
+ width: 100%;
+}
+
+/* 响应式调整 */
+@media (max-width: 375px) {
+ .content {
+ padding: 24rpx 20rpx;
+ }
+
+ .section-title {
+ font-size: 28rpx;
+ margin-bottom: 20rpx;
+ }
+
+ .form-input {
+ padding: 18rpx 14rpx;
+ min-height: 72rpx;
+ font-size: 24rpx !important;
+ }
+
+ .region-picker {
+ padding: 18rpx 14rpx;
+ min-height: 72rpx;
+ font-size: 26rpx;
+ }
+
+ .cooperation-options {
+ grid-template-columns: 1fr;
+ gap: 12rpx;
+ }
+
+ .cooperation-option {
+ padding: 18rpx 14rpx;
+ min-height: 68rpx;
+ }
+
+ .cooperation-text {
+ font-size: 24rpx;
+ }
+
+ .button-group {
+ gap: 12rpx;
+ margin-top: 40rpx;
+ padding: 12rpx 0;
+ }
+
+ .btn {
+ padding: 22rpx 18rpx;
+ min-height: 76rpx;
+ font-size: 28rpx;
+ }
+
+ .form-label {
+ font-size: 24rpx;
+ }
+
+ .error-message {
+ font-size: 20rpx;
+ padding: 4rpx 8rpx;
+ margin-top: 4rpx;
+ }
+}
+
+/* 超小屏幕优化 */
+@media (max-width: 320px) {
+ .content {
+ padding: 20rpx 16rpx;
+ }
+
+ .form-input, .region-picker {
+ padding: 16rpx 12rpx;
+ min-height: 68rpx;
+ font-size: 24rpx;
+ }
+
+ .cooperation-option {
+ padding: 16rpx 12rpx;
+ min-height: 64rpx;
+ }
+
+ .cooperation-text {
+ font-size: 22rpx;
+ }
+
+ .btn {
+ padding: 20rpx 16rpx;
+ min-height: 72rpx;
+ font-size: 26rpx;
+ }
+
+ .form-label {
+ font-size: 24rpx;
+ }
+}
+
+/* 添加页面切换动画 */
+.page {
+ animation: pageSlideIn 0.3s ease-out;
+}
+
+@keyframes pageSlideIn {
+ from {
+ opacity: 0;
+ transform: translateX(20rpx);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+/* 添加加载状态 */
+.loading {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 60rpx;
+}
+
+.loading-spinner {
+ width: 48rpx;
+ height: 48rpx;
+ border: 4rpx solid #f0f0f0;
+ border-top: 4rpx solid #07C160;
+ border-radius: 50%;
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+/* 登录授权弹窗 */
+.auth-modal {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 1002;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.auth-content {
+ background-color: white;
+ border-radius: 20rpx;
+ width: 85%;
+ max-width: 520rpx;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ animation: modalSlideIn 0.3s ease-out;
+}
+
+@keyframes modalSlideIn {
+ from {
+ opacity: 0;
+ transform: translateY(-20rpx) scale(0.95);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+}
+
+.auth-header {
+ padding: 32rpx;
+ text-align: center;
+ font-size: 32rpx;
+ font-weight: 500;
+ border-bottom: 1rpx solid #e5e5e5;
+ position: relative;
+ background: linear-gradient(135deg, #07C160 0%, #06ae56 100%);
+ color: white;
+}
+
+.auth-close {
+ position: absolute;
+ right: 32rpx;
+ top: 50%;
+ transform: translateY(-50%);
+ font-size: 36rpx;
+ color: rgba(255, 255, 255, 0.8);
+ width: 48rpx;
+ height: 48rpx;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0.1);
+ transition: all 0.3s ease;
+}
+
+.auth-close:hover {
+ background: rgba(255, 255, 255, 0.2);
+ color: white;
+}
+
+.auth-body {
+ padding: 48rpx 32rpx;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.auth-icon {
+ font-size: 80rpx;
+ margin-bottom: 24rpx;
+ animation: bounce 2s infinite;
+}
+
+@keyframes bounce {
+ 0%, 20%, 50%, 80%, 100% {
+ transform: translateY(0);
+ }
+ 40% {
+ transform: translateY(-10rpx);
+ }
+ 60% {
+ transform: translateY(-5rpx);
+ }
+}
+
+.auth-text {
+ font-size: 28rpx;
+ color: #666;
+ line-height: 1.5;
+ margin-bottom: 48rpx;
+}
+
+.auth-btn {
+ background: linear-gradient(135deg, #07C160 0%, #06ae56 100%);
+ color: white;
+ border: none;
+ border-radius: 50rpx;
+ padding: 24rpx 48rpx;
+ font-size: 30rpx;
+ font-weight: 500;
+ width: 100%;
+ max-width: 400rpx;
+ box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.3);
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.auth-btn::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
+ transition: left 0.5s ease;
+}
+
+.auth-btn:hover::before {
+ left: 100%;
+}
+
+.auth-btn:active {
+ transform: scale(0.98);
+ box-shadow: 0 4rpx 12rpx rgba(7, 193, 96, 0.3);
+}
+
+.auth-tip {
+ font-size: 24rpx;
+ color: #999;
+ margin-top: 24rpx;
+ line-height: 1.4;
+}
\ No newline at end of file
diff --git a/pages/test-tools/api-test.js b/pages/test-tools/api-test.js
new file mode 100644
index 0000000..5ab8317
--- /dev/null
+++ b/pages/test-tools/api-test.js
@@ -0,0 +1,66 @@
+// pages/test-tools/api-test.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/test-tools/api-test.wxml b/pages/test-tools/api-test.wxml
new file mode 100644
index 0000000..52cc2b5
--- /dev/null
+++ b/pages/test-tools/api-test.wxml
@@ -0,0 +1,2 @@
+
+pages/test-tools/api-test.wxml
\ No newline at end of file
diff --git a/pages/test-tools/clear-storage.js b/pages/test-tools/clear-storage.js
new file mode 100644
index 0000000..8106aaa
--- /dev/null
+++ b/pages/test-tools/clear-storage.js
@@ -0,0 +1,66 @@
+// pages/test-tools/clear-storage.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/test-tools/clear-storage.wxml b/pages/test-tools/clear-storage.wxml
new file mode 100644
index 0000000..f03c1cd
--- /dev/null
+++ b/pages/test-tools/clear-storage.wxml
@@ -0,0 +1,2 @@
+
+pages/test-tools/clear-storage.wxml
\ No newline at end of file
diff --git a/pages/test-tools/connection-test.js b/pages/test-tools/connection-test.js
new file mode 100644
index 0000000..2d1276a
--- /dev/null
+++ b/pages/test-tools/connection-test.js
@@ -0,0 +1,66 @@
+// pages/test-tools/connection-test.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/test-tools/connection-test.wxml b/pages/test-tools/connection-test.wxml
new file mode 100644
index 0000000..f6f0398
--- /dev/null
+++ b/pages/test-tools/connection-test.wxml
@@ -0,0 +1,2 @@
+
+pages/test-tools/connection-test.wxml
\ No newline at end of file
diff --git a/pages/test-tools/fix-connection.js b/pages/test-tools/fix-connection.js
new file mode 100644
index 0000000..e00ffd0
--- /dev/null
+++ b/pages/test-tools/fix-connection.js
@@ -0,0 +1,66 @@
+// pages/test-tools/fix-connection.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/test-tools/fix-connection.wxml b/pages/test-tools/fix-connection.wxml
new file mode 100644
index 0000000..a9e8c39
--- /dev/null
+++ b/pages/test-tools/fix-connection.wxml
@@ -0,0 +1,2 @@
+
+pages/test-tools/fix-connection.wxml
\ No newline at end of file
diff --git a/pages/test-tools/gross-weight-tester.js b/pages/test-tools/gross-weight-tester.js
new file mode 100644
index 0000000..34bee83
--- /dev/null
+++ b/pages/test-tools/gross-weight-tester.js
@@ -0,0 +1,66 @@
+// pages/test-tools/gross-weight-tester.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/test-tools/gross-weight-tester.wxml b/pages/test-tools/gross-weight-tester.wxml
new file mode 100644
index 0000000..be81f4b
--- /dev/null
+++ b/pages/test-tools/gross-weight-tester.wxml
@@ -0,0 +1,2 @@
+
+pages/test-tools/gross-weight-tester.wxml
\ No newline at end of file
diff --git a/pages/test-tools/phone-test.js b/pages/test-tools/phone-test.js
new file mode 100644
index 0000000..d7319c4
--- /dev/null
+++ b/pages/test-tools/phone-test.js
@@ -0,0 +1,66 @@
+// pages/test-tools/phone-test.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/test-tools/phone-test.wxml b/pages/test-tools/phone-test.wxml
new file mode 100644
index 0000000..1e321e5
--- /dev/null
+++ b/pages/test-tools/phone-test.wxml
@@ -0,0 +1,2 @@
+
+pages/test-tools/phone-test.wxml
\ No newline at end of file
diff --git a/pages/test-tools/test-mode-switch.js b/pages/test-tools/test-mode-switch.js
new file mode 100644
index 0000000..9181ee8
--- /dev/null
+++ b/pages/test-tools/test-mode-switch.js
@@ -0,0 +1,66 @@
+// pages/test-tools/test-mode-switch.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/test-tools/test-mode-switch.wxml b/pages/test-tools/test-mode-switch.wxml
new file mode 100644
index 0000000..fc2bb48
--- /dev/null
+++ b/pages/test-tools/test-mode-switch.wxml
@@ -0,0 +1,2 @@
+
+pages/test-tools/test-mode-switch.wxml
\ No newline at end of file
diff --git a/pages/test/undercarriage-test.js b/pages/test/undercarriage-test.js
new file mode 100644
index 0000000..5eefd0a
--- /dev/null
+++ b/pages/test/undercarriage-test.js
@@ -0,0 +1,66 @@
+// pages/test/undercarriage-test.js
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/test/undercarriage-test.wxml b/pages/test/undercarriage-test.wxml
new file mode 100644
index 0000000..a207e69
--- /dev/null
+++ b/pages/test/undercarriage-test.wxml
@@ -0,0 +1,2 @@
+
+pages/test/undercarriage-test.wxml
\ No newline at end of file
diff --git a/project.config.json b/project.config.json
new file mode 100644
index 0000000..3404946
--- /dev/null
+++ b/project.config.json
@@ -0,0 +1,91 @@
+{
+ "setting": {
+ "es6": true,
+ "postcss": true,
+ "minified": true,
+ "uglifyFileName": false,
+ "enhance": true,
+ "sourceMap": false,
+ "packNpmRelationList": [],
+ "babelSetting": {
+ "ignore": [],
+ "disablePlugins": [],
+ "outputPath": ""
+ },
+ "useCompilerPlugins": false,
+ "minifyWXML": true,
+ "requestDomain": [
+ "http://localhost:3000",
+ "http://8.137.125.67:3000",
+ "http://localhost:3001",
+ "https://youniao.icu"
+ ],
+ "compileWorklet": false,
+ "uploadWithSourceMap": true,
+ "packNpmManually": false,
+ "minifyWXSS": true,
+ "localPlugins": false,
+ "disableUseStrict": false,
+ "condition": false,
+ "swc": false,
+ "disableSWC": true
+ },
+ "compileType": "miniprogram",
+ "simulatorPluginLibVersion": {},
+ "packOptions": {
+ "ignore": [
+ {
+ "value": "server-example",
+ "type": "folder"
+ },
+ {
+ "value": "node_modules",
+ "type": "folder"
+ },
+ {
+ "value": ".md",
+ "type": "suffix"
+ },
+ {
+ "value": "test-api-fix.js",
+ "type": "file"
+ },
+ {
+ "value": "test-minimal.js",
+ "type": "file"
+ },
+ {
+ "value": "test-ports.js",
+ "type": "file"
+ },
+ {
+ "value": "test-server.js",
+ "type": "file"
+ },
+ {
+ "value": "verify-fix.js",
+ "type": "file"
+ },
+ {
+ "value": "verify-login.js",
+ "type": "file"
+ },
+ {
+ "value": "check-files.js",
+ "type": "file"
+ },
+ {
+ "value": "full-debug.js",
+ "type": "file"
+ },
+ {
+ "value": "get-openid.js",
+ "type": "file"
+ }
+ ],
+ "include": []
+ },
+ "appid": "wx3da6ea0adf91cf0d",
+ "editorSetting": {},
+ "libVersion": "3.10.3"
+}
\ No newline at end of file
diff --git a/project.private.config.json b/project.private.config.json
new file mode 100644
index 0000000..3c2198f
--- /dev/null
+++ b/project.private.config.json
@@ -0,0 +1,23 @@
+{
+ "libVersion": "3.10.3",
+ "projectname": "miniprogram-x27",
+ "setting": {
+ "urlCheck": false,
+ "coverView": true,
+ "lazyloadPlaceholderEnable": false,
+ "skylineRenderEnable": false,
+ "preloadBackgroundData": false,
+ "autoAudits": false,
+ "showShadowRootInWxmlPanel": true,
+ "compileHotReLoad": true,
+ "useApiHook": true,
+ "useApiHostProcess": true,
+ "useStaticServer": false,
+ "useLanDebug": false,
+ "showES6CompileOption": false,
+ "checkInvalidKey": true,
+ "ignoreDevUnusedFiles": true,
+ "bigPackageSizeSupport": false
+ },
+ "condition": {}
+}
\ No newline at end of file
diff --git a/server-example/.env b/server-example/.env
new file mode 100644
index 0000000..cb1f9b6
--- /dev/null
+++ b/server-example/.env
@@ -0,0 +1,24 @@
+# 微信小程序配置
+WECHAT_APPID=wx3da6ea0adf91cf0d
+WECHAT_APPSECRET=78fd81bce5a2968a8e7c607ae68c4c0b
+WECHAT_TOKEN=your-random-token
+
+# MySQL数据库配置(请根据您的实际环境修改)
+# 如果是首次使用,可能需要先在MySQL中创建wechat_app数据库
+DB_HOST=1.95.162.61
+DB_PORT=3306
+DB_DATABASE=wechat_app
+# 请使用您实际的MySQL用户名
+DB_USER=root
+# 请使用您实际的MySQL密码
+# 如果MySQL的root用户有密码,请在此处填写
+# 如果没有密码,请保留为空字符串(DB_PASSWORD="")
+DB_PASSWORD=schl@2025
+
+# 服务器配置
+PORT=3003
+# 日志配置
+LOG_LEVEL=debug
+NODE_ENV=development
+# 详细日志记录,用于问题排查
+ENABLE_DETAILED_LOGGING=true
\ No newline at end of file
diff --git a/server-example/.env.example.mysql b/server-example/.env.example.mysql
new file mode 100644
index 0000000..5af309a
--- /dev/null
+++ b/server-example/.env.example.mysql
@@ -0,0 +1,101 @@
+# 微信小程序服务器环境变量配置示例(MySQL版本)
+# 将此文件复制为 .env 文件并填写实际值
+
+# ========================================================
+# 微信小程序配置
+# ========================================================
+# 从微信公众平台获取的AppID
+WECHAT_APPID=wx1234567890abcdef
+
+# 从微信公众平台获取的AppSecret(请妥善保管,不要泄露)
+WECHAT_APPSECRET=abcdef1234567890abcdef1234567890
+
+# 微信消息校验Token(可选,用于消息验证)
+WECHAT_TOKEN=your-random-token
+
+# ========================================================
+# MySQL数据库配置
+# ========================================================
+# MySQL主机地址(云数据库地址)
+DB_HOST=your_mysql_host
+
+# MySQL端口(默认3306)
+DB_PORT=3306
+
+# MySQL数据库名(主数据库)
+DB_DATABASE=wechat_app
+
+# MySQL用户名
+DB_USER=your_mysql_username
+
+# MySQL密码
+DB_PASSWORD=your_mysql_password
+
+# userlogin数据库名(如果需要连接)
+DB_DATABASE_USERLOGIN=userlogin
+
+# MySQL连接池配置
+DB_MAX_CONNECTIONS=10
+DB_MIN_CONNECTIONS=0
+DB_CONNECTION_ACQUIRE_TIMEOUT=30000
+DB_CONNECTION_IDLE_TIMEOUT=10000
+
+# ========================================================
+# 服务器配置
+# ========================================================
+# 服务器监听端口
+PORT=3000
+
+# 运行环境(development/production/test)
+NODE_ENV=development
+
+# 日志级别(debug/info/warn/error)
+LOG_LEVEL=info
+
+# 允许的跨域来源(多个来源用逗号分隔)
+CORS_ORIGINS=https://your-miniprogram-domain.com,http://localhost:8080
+
+# ========================================================
+# 安全配置
+# ========================================================
+# JWT密钥(用于API认证,生成随机字符串)
+JWT_SECRET=your-random-jwt-secret
+
+# JWT过期时间(秒)
+JWT_EXPIRES_IN=86400
+
+# 加密密钥(用于敏感数据加密)
+ENCRYPTION_KEY=your-encryption-key-32-bytes-length
+
+# ========================================================
+# 微信接口配置
+# ========================================================
+# 微信API基础URL
+WECHAT_API_BASE_URL=https://api.weixin.qq.com
+
+# 微信登录接口路径
+WECHAT_LOGIN_PATH=/sns/jscode2session
+
+# 微信接口请求超时时间(毫秒)
+WECHAT_API_TIMEOUT=5000
+
+# ========================================================
+# 开发环境配置
+# ========================================================
+# 在开发环境中启用详细错误信息
+DEVELOPMENT_SHOW_ERROR_DETAILS=true
+
+# 是否启用请求日志记录
+ENABLE_REQUEST_LOGGING=true
+
+# ========================================================
+# 生产环境配置
+# ========================================================
+# 是否启用Gzip压缩
+PRODUCTION_ENABLE_GZIP=true
+
+# 是否启用缓存
+PRODUCTION_ENABLE_CACHE=true
+
+# 缓存过期时间(秒)
+PRODUCTION_CACHE_TTL=3600
\ No newline at end of file
diff --git a/server-example/add-department-column.js b/server-example/add-department-column.js
new file mode 100644
index 0000000..518db97
--- /dev/null
+++ b/server-example/add-department-column.js
@@ -0,0 +1,41 @@
+const { Sequelize } = require('sequelize');
+require('dotenv').config();
+
+// 创建数据库连接
+const sequelize = new Sequelize(
+ process.env.DB_DATABASE || 'wechat_app',
+ process.env.DB_USER || 'root',
+ process.env.DB_PASSWORD === undefined ? null : process.env.DB_PASSWORD,
+ {
+ host: process.env.DB_HOST || 'localhost',
+ port: process.env.DB_PORT || 3306,
+ dialect: 'mysql',
+ timezone: '+08:00'
+ }
+);
+
+// 添加department字段到usermanagements表
+async function addDepartmentColumn() {
+ try {
+ // 连接数据库
+ await sequelize.authenticate();
+ console.log('✅ 数据库连接成功');
+
+ // 使用queryInterface添加字段
+ await sequelize.getQueryInterface().addColumn('usermanagements', 'department', {
+ type: Sequelize.STRING(255),
+ defaultValue: null,
+ comment: '部门信息'
+ });
+
+ console.log('✅ 成功添加department字段到usermanagements表');
+ } catch (error) {
+ console.error('❌ 添加字段失败:', error.message);
+ } finally {
+ // 关闭数据库连接
+ await sequelize.close();
+ }
+}
+
+// 执行函数
+addDepartmentColumn();
\ No newline at end of file
diff --git a/server-example/complete-gross-weight-fix.js b/server-example/complete-gross-weight-fix.js
new file mode 100644
index 0000000..a6bc44d
--- /dev/null
+++ b/server-example/complete-gross-weight-fix.js
@@ -0,0 +1,143 @@
+// 毛重字段(grossWeight)处理逻辑完整修复脚本
+// 此脚本用于统一所有API接口对grossWeight字段的处理逻辑
+
+const fs = require('fs');
+const path = require('path');
+
+// 定义配置
+const config = {
+ serverFilePath: path.join(__dirname, 'server-mysql.js'),
+ backupFilePath: path.join(__dirname, 'server-mysql.js.bak.final-fix-' + Date.now()),
+ logFilePath: path.join(__dirname, 'final-fix-gross-weight-log.txt')
+};
+
+// 日志函数
+function log(message) {
+ const timestamp = new Date().toISOString();
+ const logMessage = '[' + timestamp + '] ' + message;
+ console.log(logMessage);
+ try {
+ fs.appendFileSync(config.logFilePath, logMessage + '\n');
+ } catch (e) {
+ console.error('写入日志文件失败:', e.message);
+ }
+}
+
+// 读取文件内容
+function readFile(filePath) {
+ try {
+ return fs.readFileSync(filePath, 'utf8');
+ } catch (error) {
+ log('读取文件失败: ' + error.message);
+ throw error;
+ }
+}
+
+// 写入文件内容
+function writeFile(filePath, content) {
+ try {
+ fs.writeFileSync(filePath, content, 'utf8');
+ log('文件已成功写入: ' + filePath);
+ } catch (error) {
+ log('写入文件失败: ' + error.message);
+ throw error;
+ }
+}
+
+// 创建备份文件
+function createBackup() {
+ try {
+ const content = readFile(config.serverFilePath);
+ writeFile(config.backupFilePath, content);
+ log('已创建备份文件: ' + config.backupFilePath);
+ } catch (error) {
+ log('创建备份文件失败: ' + error.message);
+ throw error;
+ }
+}
+
+// 主函数
+function main() {
+ log('===== 开始执行毛重字段处理逻辑完整修复 =====');
+
+ try {
+ // 创建备份
+ createBackup();
+
+ // 读取文件内容
+ let content = readFile(config.serverFilePath);
+
+ // 修复1: 统一中间件中的毛重处理逻辑,确保所有空值都设为5
+ const searchPatterns = [
+ 'product.grossWeight = 0;',
+ 'product.grossWeight = 0; // 空值设置为0'
+ ];
+
+ let fixesApplied = 0;
+ searchPatterns.forEach(pattern => {
+ if (content.includes(pattern)) {
+ const originalCount = (content.match(new RegExp(pattern, 'g')) || []).length;
+ content = content.replace(new RegExp(pattern, 'g'), 'product.grossWeight = 5; // 空值设置为5');
+ const fixedCount = (content.match(/product\.grossWeight = 5;/g) || []).length - originalCount;
+ fixesApplied += fixedCount;
+ log('修复中间件中的毛重默认值: 替换了' + fixedCount + '处');
+ }
+ });
+
+ if (fixesApplied > 0) {
+ log('修复1完成: 已统一所有中间件中的毛重默认值为5');
+ } else {
+ log('修复1跳过: 所有中间件中的毛重默认值已经是5');
+ }
+
+ // 修复2: 在商品上传接口添加毛重处理逻辑
+ const uploadApiSearch = 'app.post(\'/api/products/upload\', async (req, res) => {';
+ if (content.includes(uploadApiSearch)) {
+ // 查找上传接口的位置
+ const uploadApiStart = content.indexOf(uploadApiSearch);
+ const uploadApiEnd = content.indexOf('});', uploadApiStart) + 3;
+ const uploadApiContent = content.substring(uploadApiStart, uploadApiEnd);
+
+ // 检查是否已经包含毛重处理逻辑
+ if (uploadApiContent.includes('grossWeight') && uploadApiContent.includes('parseFloat')) {
+ log('修复2跳过: 商品上传接口已经包含毛重处理逻辑');
+ } else {
+ // 查找商品数据处理的位置(在try块内)
+ const tryBlockStart = uploadApiContent.indexOf('try {');
+ const tryBlockEnd = uploadApiContent.lastIndexOf('} catch');
+
+ if (tryBlockStart !== -1 && tryBlockEnd !== -1) {
+ // 在try块开始处添加毛重处理逻辑
+ const tryBlockContent = uploadApiContent.substring(tryBlockStart, tryBlockEnd);
+ const weightHandlingCode = `try {\n // 修复毛重字段处理逻辑\n if (req.body && req.body.productData) {\n let processedGrossWeight = 5; // 默认值为5\n if (req.body.productData.grossWeight !== null && req.body.productData.grossWeight !== undefined && req.body.productData.grossWeight !== \'\') {\n const numValue = parseFloat(req.body.productData.grossWeight);\n if (!isNaN(numValue) && isFinite(numValue)) {\n processedGrossWeight = numValue;\n }\n }\n req.body.productData.grossWeight = processedGrossWeight;\n console.log(\'修复后 - 毛重值处理: 原始值=\' + (req.body.productData.grossWeight || \'undefined\') + ', 处理后=\' + processedGrossWeight);\n }`;
+
+ // 替换原代码
+ const fixedUploadApiContent = uploadApiContent.replace(tryBlockContent, weightHandlingCode);
+ content = content.replace(uploadApiContent, fixedUploadApiContent);
+ log('修复2完成: 在商品上传接口添加了毛重处理逻辑');
+ } else {
+ log('修复2失败: 无法在商品上传接口中找到try-catch块');
+ }
+ }
+ } else {
+ log('修复2跳过: 未找到商品上传接口');
+ }
+
+ // 写入修复后的内容
+ writeFile(config.serverFilePath, content);
+
+ log('===== 毛重字段处理逻辑完整修复完成 =====');
+ log('修复内容总结:');
+ log('1. 统一了所有中间件中的毛重默认值为5');
+ log('2. 在商品上传接口中添加了毛重处理逻辑,将空值设为5,有效数字转换为float类型');
+ log('3. 创建了备份文件,以便需要时恢复');
+
+ } catch (error) {
+ log('修复过程中发生错误: ' + error.message);
+ log('===== 毛重字段处理逻辑完整修复失败 =====');
+ process.exit(1);
+ }
+}
+
+// 执行主函数
+main();
\ No newline at end of file
diff --git a/server-example/complete-gross-weight-verification.js b/server-example/complete-gross-weight-verification.js
new file mode 100644
index 0000000..849c58d
--- /dev/null
+++ b/server-example/complete-gross-weight-verification.js
@@ -0,0 +1,123 @@
+const fs = require('fs');
+const path = require('path');
+
+// 读取server-mysql.js文件内容
+function readServerFile() {
+ return fs.readFileSync(path.join(__dirname, 'server-mysql.js'), 'utf8');
+}
+
+// 验证毛重字段处理逻辑
+function verifyGrossWeightHandling() {
+ try {
+ const fileContent = readServerFile();
+
+ // 初始化验证结果
+ const verificationResult = {
+ totalIssues: 0,
+ successPoints: 0,
+ issues: [],
+ successDetails: []
+ };
+
+ // 检查响应中间件中的/products/list接口
+ const listMiddlewarePattern = /data\.products\s*=\s*data\.products\.map\(product\s*=>\s*\{[\s\S]*?product\.grossWeight\s*=\s*([^;]+);/;
+ const listMiddlewareMatch = fileContent.match(listMiddlewarePattern);
+
+ if (listMiddlewareMatch && listMiddlewareMatch[1].includes('0')) {
+ verificationResult.successPoints++;
+ verificationResult.successDetails.push('✓ 响应中间件(/products/list)已正确设置空毛重默认值为0');
+ } else {
+ verificationResult.totalIssues++;
+ verificationResult.issues.push('✗ 响应中间件(/products/list)未正确设置空毛重默认值');
+ }
+
+ // 检查响应中间件中的/data接口
+ const dataMiddlewarePattern = /data\.data\.products\s*=\s*data\.data\.products\.map\(product\s*=>\s*\{[\s\S]*?product\.grossWeight\s*=\s*([^;]+);/;
+ const dataMiddlewareMatch = fileContent.match(dataMiddlewarePattern);
+
+ if (dataMiddlewareMatch && dataMiddlewareMatch[1].includes('0')) {
+ verificationResult.successPoints++;
+ verificationResult.successDetails.push('✓ 响应中间件(/data)已正确设置空毛重默认值为0');
+ } else {
+ verificationResult.totalIssues++;
+ verificationResult.issues.push('✗ 响应中间件(/data)未正确设置空毛重默认值');
+ }
+
+ // 检查商品上传接口
+ const uploadApiPattern = /app\.post\('\/api\/products\/upload',[\s\S]*?let\s+processedGrossWeight\s*=\s*(\d+)/;
+ const uploadApiMatch = fileContent.match(uploadApiPattern);
+
+ if (uploadApiMatch && uploadApiMatch[1] === '0') {
+ verificationResult.successPoints++;
+ verificationResult.successDetails.push('✓ 商品上传接口已正确设置空毛重默认值为0');
+ } else {
+ verificationResult.totalIssues++;
+ verificationResult.issues.push('✗ 商品上传接口未正确设置空毛重默认值');
+ }
+
+ // 检查编辑商品API
+ const editApiPattern = /parsedValue:\s*product\.grossWeight\s*===\s*''\s*\|\|\s*product\.grossWeight\s*===\s*null\s*\|\|\s*product\.grossWeight\s*===\s*undefined\s*\?\s*(\d+)/;
+ const editApiMatch = fileContent.match(editApiPattern);
+
+ if (editApiMatch && editApiMatch[1] === '0') {
+ verificationResult.successPoints++;
+ verificationResult.successDetails.push('✓ 编辑商品API已正确设置空毛重默认值为0');
+ } else {
+ verificationResult.totalIssues++;
+ verificationResult.issues.push('✗ 编辑商品API未正确设置空毛重默认值');
+ }
+
+ // 检查是否还有设置为5的地方
+ const remaining5Pattern = /grossWeight\s*=\s*5/g;
+ const remaining5Matches = fileContent.match(remaining5Pattern);
+
+ if (remaining5Matches && remaining5Matches.length > 0) {
+ verificationResult.totalIssues += remaining5Matches.length;
+ verificationResult.issues.push(`✗ 发现${remaining5Matches.length}处仍将毛重设置为5的地方`);
+ } else {
+ verificationResult.successPoints++;
+ verificationResult.successDetails.push('✓ 未发现仍将毛重设置为5的残留代码');
+ }
+
+ // 检查是否正确实现了空值返回0的逻辑
+ const emptyValueHandlingPattern = /product\.grossWeight\s*===\s*null\s*\|\|\s*product\.grossWeight\s*===\s*undefined\s*\|\|\s*product\.grossWeight\s*===\s*''\s*\?\s*0/g;
+ const emptyValueMatches = fileContent.match(emptyValueHandlingPattern);
+
+ if (emptyValueMatches && emptyValueMatches.length > 0) {
+ verificationResult.successPoints++;
+ verificationResult.successDetails.push(`✓ 发现${emptyValueMatches.length}处正确实现了空值返回0的逻辑`);
+ }
+
+ // 输出验证结果
+ console.log('\n======== 毛重字段处理逻辑全面验证结果 ========');
+ console.log('\n成功项:');
+ verificationResult.successDetails.forEach(detail => console.log(detail));
+
+ console.log('\n问题项:');
+ if (verificationResult.issues.length === 0) {
+ console.log('✓ 未发现任何问题');
+ } else {
+ verificationResult.issues.forEach(issue => console.log(issue));
+ }
+
+ console.log('\n总体评估:');
+ if (verificationResult.totalIssues === 0) {
+ console.log('✅ 验证成功: 所有毛重字段处理逻辑已正确实现');
+ console.log(' 已满足要求: 空值时小程序和数据库均返回0,非空值返回实际值');
+ } else {
+ console.log(`❌ 验证失败: 发现${verificationResult.totalIssues}个问题需要修复`);
+ }
+
+ console.log('==============================================');
+
+ // 设置退出码
+ process.exit(verificationResult.totalIssues > 0 ? 1 : 0);
+
+ } catch (error) {
+ console.error('验证过程中发生错误:', error);
+ process.exit(1);
+ }
+}
+
+// 执行验证
+verifyGrossWeightHandling();
\ No newline at end of file
diff --git a/server-example/create-missing-associations.js b/server-example/create-missing-associations.js
new file mode 100644
index 0000000..7389ec7
--- /dev/null
+++ b/server-example/create-missing-associations.js
@@ -0,0 +1,155 @@
+const { Sequelize } = require('sequelize');
+const fs = require('fs');
+const path = require('path');
+
+// 读取环境变量
+const envPath = path.join(__dirname, '.env');
+if (fs.existsSync(envPath)) {
+ const envContent = fs.readFileSync(envPath, 'utf8');
+ const envVars = envContent.split('\n').filter(line => line.trim() && !line.startsWith('#'));
+ envVars.forEach(line => {
+ const [key, value] = line.split('=').map(part => part.trim());
+ process.env[key] = value;
+ });
+}
+
+// 数据库连接配置
+const sequelize = new Sequelize(
+ process.env.DB_NAME || 'wechat_app',
+ process.env.DB_USER || 'root',
+ process.env.DB_PASSWORD || '',
+ {
+ host: process.env.DB_HOST || 'localhost',
+ port: process.env.DB_PORT || 3306,
+ dialect: 'mysql',
+ logging: false,
+ timezone: '+08:00' // 设置时区为UTC+8
+ }
+);
+
+// 定义模型 - 简化版
+const User = sequelize.define('User', {
+ userId: {
+ type: sequelize.Sequelize.STRING(100),
+ primaryKey: true,
+ allowNull: false
+ },
+ nickName: sequelize.Sequelize.STRING(100),
+ phoneNumber: sequelize.Sequelize.STRING(20)
+}, {
+ tableName: 'users',
+ timestamps: false
+});
+
+const Contact = sequelize.define('Contact', {
+ id: {
+ type: sequelize.Sequelize.INTEGER,
+ autoIncrement: true,
+ primaryKey: true
+ },
+ userId: {
+ type: sequelize.Sequelize.STRING(100),
+ allowNull: false
+ },
+ nickName: sequelize.Sequelize.STRING(100),
+ phoneNumber: sequelize.Sequelize.STRING(20)
+}, {
+ tableName: 'contacts',
+ timestamps: false
+});
+
+const UserManagement = sequelize.define('UserManagement', {
+ id: {
+ type: sequelize.Sequelize.INTEGER,
+ autoIncrement: true,
+ primaryKey: true
+ },
+ userId: {
+ type: sequelize.Sequelize.STRING(100),
+ allowNull: false
+ }
+}, {
+ tableName: 'usermanagements',
+ timestamps: false
+});
+
+// 修复函数
+async function fixMissingAssociations() {
+ try {
+ console.log('========================================');
+ console.log('开始修复用户关联表记录');
+ console.log('========================================');
+
+ // 连接数据库
+ await sequelize.authenticate();
+ console.log('✅ 数据库连接成功');
+
+ // 获取所有用户
+ const users = await User.findAll();
+ console.log(`📊 共找到 ${users.length} 个用户记录`);
+
+ let contactsCreated = 0;
+ let managementsCreated = 0;
+
+ // 为每个用户检查并创建关联记录
+ for (let i = 0; i < users.length; i++) {
+ const user = users[i];
+ console.log(`\n🔄 处理用户 ${i + 1}/${users.length}: ${user.userId}`);
+
+ // 检查并创建联系人记录
+ try {
+ const existingContact = await Contact.findOne({
+ where: { userId: user.userId }
+ });
+
+ if (!existingContact) {
+ await Contact.create({
+ userId: user.userId,
+ nickName: user.nickName || '默认联系人',
+ phoneNumber: user.phoneNumber || ''
+ });
+ console.log('✅ 创建了联系人记录');
+ contactsCreated++;
+ } else {
+ console.log('✅ 联系人记录已存在');
+ }
+ } catch (error) {
+ console.error('❌ 创建联系人记录失败:', error.message);
+ }
+
+ // 检查并创建用户管理记录
+ try {
+ const existingManagement = await UserManagement.findOne({
+ where: { userId: user.userId }
+ });
+
+ if (!existingManagement) {
+ await UserManagement.create({
+ userId: user.userId
+ });
+ console.log('✅ 创建了用户管理记录');
+ managementsCreated++;
+ } else {
+ console.log('✅ 用户管理记录已存在');
+ }
+ } catch (error) {
+ console.error('❌ 创建用户管理记录失败:', error.message);
+ }
+ }
+
+ console.log('\n========================================');
+ console.log('修复完成!');
+ console.log(`📈 共创建了 ${contactsCreated} 条联系人记录`);
+ console.log(`📈 共创建了 ${managementsCreated} 条用户管理记录`);
+ console.log('========================================');
+
+ } catch (error) {
+ console.error('❌ 修复过程中发生错误:', error);
+ } finally {
+ // 关闭数据库连接
+ await sequelize.close();
+ }
+}
+
+// 运行修复
+fixMissingAssociations();
\ No newline at end of file
diff --git a/server-example/database-extension.js b/server-example/database-extension.js
new file mode 100644
index 0000000..3cd70ff
--- /dev/null
+++ b/server-example/database-extension.js
@@ -0,0 +1,356 @@
+// 注意:此文件是MongoDB版本的扩展实现,已被禁用
+// 数据库扩展 - 用于连接userlogin数据库并关联表
+const { Sequelize, DataTypes, Model } = require('sequelize');
+const path = require('path');
+require('dotenv').config({ path: path.resolve(__dirname, '.env') });
+
+// 注意:不再直接导入User模型以避免循环依赖
+// User模型将通过setupAssociations函数的参数传入
+let User = null;
+
+// 创建到userlogin数据库的连接
+const sequelizeUserLogin = new Sequelize(
+ process.env.DB_DATABASE_USERLOGIN || 'userlogin',
+ process.env.DB_USER || 'root',
+ process.env.DB_PASSWORD,
+ {
+ host: process.env.DB_HOST || 'localhost',
+ port: process.env.DB_PORT || 3306,
+ dialect: 'mysql',
+ pool: {
+ max: 10,
+ min: 0,
+ acquire: 30000,
+ idle: 10000
+ },
+ timezone: '+08:00' // 设置时区为UTC+8
+ }
+);
+
+// 测试userlogin数据库连接
+async function testUserLoginDbConnection() {
+ try {
+ await sequelizeUserLogin.authenticate();
+ console.log('userlogin数据库连接成功');
+ } catch (error) {
+ console.error('userlogin数据库连接失败:', error);
+ console.error('请注意:如果不需要使用userlogin数据库,可以忽略此错误');
+ }
+}
+
+// 定义userlogin数据库中的表模型
+
+// contact表模型
+class Contact extends Model { }
+Contact.init({
+ id: {
+ type: DataTypes.INTEGER,
+ autoIncrement: true,
+ primaryKey: true
+ },
+ userId: {
+ type: DataTypes.STRING(100),
+ allowNull: false
+ },
+ name: {
+ type: DataTypes.STRING(100),
+ allowNull: false
+ },
+ phone: {
+ type: DataTypes.STRING(20),
+ allowNull: false
+ },
+ email: {
+ type: DataTypes.STRING(100)
+ },
+ address: {
+ type: DataTypes.TEXT
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ defaultValue: Sequelize.NOW
+ }
+}, {
+ sequelize: sequelizeUserLogin,
+ modelName: 'Contact',
+ tableName: 'contact',
+ timestamps: false
+});
+
+// enterprise表模型
+class Enterprise extends Model { }
+Enterprise.init({
+ id: {
+ type: DataTypes.INTEGER,
+ autoIncrement: true,
+ primaryKey: true
+ },
+ userId: {
+ type: DataTypes.STRING(100),
+ allowNull: false
+ },
+ enterpriseName: {
+ type: DataTypes.STRING(255),
+ allowNull: false
+ },
+ businessLicense: {
+ type: DataTypes.STRING(255)
+ },
+ address: {
+ type: DataTypes.TEXT
+ },
+ contactPerson: {
+ type: DataTypes.STRING(100)
+ },
+ contactPhone: {
+ type: DataTypes.STRING(20)
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ defaultValue: Sequelize.NOW
+ }
+}, {
+ sequelize: sequelizeUserLogin,
+ modelName: 'Enterprise',
+ tableName: 'enterprise',
+ timestamps: false
+});
+
+// managers表模型
+class Manager extends Model { }
+Manager.init({
+ id: {
+ type: DataTypes.INTEGER,
+ autoIncrement: true,
+ primaryKey: true
+ },
+ userId: {
+ type: DataTypes.STRING(100),
+ allowNull: false
+ },
+ managerName: {
+ type: DataTypes.STRING(100),
+ allowNull: false
+ },
+ managerPhone: {
+ type: DataTypes.STRING(20),
+ allowNull: false
+ },
+ role: {
+ type: DataTypes.STRING(50),
+ allowNull: false
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ defaultValue: Sequelize.NOW
+ }
+}, {
+ sequelize: sequelizeUserLogin,
+ modelName: 'Manager',
+ tableName: 'managers',
+ timestamps: false
+});
+
+// publicseademand表模型
+class PublicSeaDemand extends Model { }
+PublicSeaDemand.init({
+ id: {
+ type: DataTypes.INTEGER,
+ autoIncrement: true,
+ primaryKey: true
+ },
+ userId: {
+ type: DataTypes.STRING(100),
+ allowNull: false
+ },
+ demandType: {
+ type: DataTypes.STRING(100),
+ allowNull: false
+ },
+ description: {
+ type: DataTypes.TEXT
+ },
+ status: {
+ type: DataTypes.STRING(50),
+ defaultValue: 'pending'
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ defaultValue: Sequelize.NOW
+ }
+}, {
+ sequelize: sequelizeUserLogin,
+ modelName: 'PublicSeaDemand',
+ tableName: 'publicseademand',
+ timestamps: false
+});
+
+// rootdb表模型
+class RootDb extends Model { }
+RootDb.init({
+ id: {
+ type: DataTypes.INTEGER,
+ autoIncrement: true,
+ primaryKey: true
+ },
+ userId: {
+ type: DataTypes.STRING(100),
+ allowNull: false
+ },
+ dataKey: {
+ type: DataTypes.STRING(100),
+ allowNull: false
+ },
+ dataValue: {
+ type: DataTypes.TEXT
+ },
+ created_at: {
+ type: DataTypes.DATE,
+ defaultValue: Sequelize.NOW
+ }
+}, {
+ sequelize: sequelizeUserLogin,
+ modelName: 'RootDb',
+ tableName: 'rootdb',
+ timestamps: false
+});
+
+// login表模型
+class Login extends Model { }
+Login.init({
+ id: {
+ type: DataTypes.INTEGER,
+ autoIncrement: true,
+ primaryKey: true
+ },
+ userId: {
+ type: DataTypes.STRING(100),
+ allowNull: false
+ },
+ loginTime: {
+ type: DataTypes.DATE,
+ defaultValue: Sequelize.NOW
+ },
+ loginIp: {
+ type: DataTypes.STRING(50)
+ },
+ deviceInfo: {
+ type: DataTypes.TEXT
+ },
+ status: {
+ type: DataTypes.STRING(20),
+ defaultValue: 'success'
+ }
+}, {
+ sequelize: sequelizeUserLogin,
+ modelName: 'Login',
+ tableName: 'login',
+ timestamps: false
+});
+
+// 设置模型关联关系
+function setupAssociations(mainUserModel) {
+ // 确保使用传入的User模型,不再依赖默认的User变量
+ if (!mainUserModel) {
+ console.error('User模型未提供,无法设置关联关系');
+ return;
+ }
+
+ try {
+ // 关联User与Contact(一对多)
+ // 使用唯一的别名userContacts以避免可能的冲突
+ mainUserModel.hasMany(Contact, {
+ foreignKey: 'userId',
+ sourceKey: 'userId',
+ as: 'userContacts'
+ });
+
+ // 反向关联Contact与User
+ Contact.belongsTo(mainUserModel, {
+ foreignKey: 'userId',
+ targetKey: 'userId',
+ as: 'user'
+ });
+
+ // 关联User与Enterprise(一对多)
+ mainUserModel.hasMany(Enterprise, {
+ foreignKey: 'userId',
+ sourceKey: 'userId',
+ as: 'userEnterprises'
+ });
+
+ // 反向关联Enterprise与User
+ Enterprise.belongsTo(mainUserModel, {
+ foreignKey: 'userId',
+ targetKey: 'userId',
+ as: 'user'
+ });
+
+ // 关联User与Manager(一对多)
+ mainUserModel.hasMany(Manager, {
+ foreignKey: 'userId',
+ sourceKey: 'userId',
+ as: 'userManagers'
+ });
+
+ // 反向关联Manager与User
+ Manager.belongsTo(mainUserModel, {
+ foreignKey: 'userId',
+ targetKey: 'userId',
+ as: 'user'
+ });
+
+ // 关联User与PublicSeaDemand(一对多)
+ mainUserModel.hasMany(PublicSeaDemand, {
+ foreignKey: 'userId',
+ sourceKey: 'userId',
+ as: 'userPublicSeaDemands'
+ });
+
+ // 反向关联PublicSeaDemand与User
+ PublicSeaDemand.belongsTo(mainUserModel, {
+ foreignKey: 'userId',
+ targetKey: 'userId',
+ as: 'user'
+ });
+
+ // 关联User与RootDb(一对多)
+ mainUserModel.hasMany(RootDb, {
+ foreignKey: 'userId',
+ sourceKey: 'userId',
+ as: 'userRootDbs'
+ });
+
+ // 反向关联RootDb与User
+ RootDb.belongsTo(mainUserModel, {
+ foreignKey: 'userId',
+ targetKey: 'userId',
+ as: 'user'
+ });
+
+ // 关联User与Login(一对多)
+ mainUserModel.hasMany(Login, {
+ foreignKey: 'userId',
+ sourceKey: 'userId',
+ as: 'userLoginRecords'
+ });
+
+ console.log('已设置wechat_app数据库的User模型与userlogin数据库表的关联关系');
+ } catch (error) {
+ console.error('设置模型关联关系时出错:', error);
+ }
+}
+
+// 导出所有模型和连接
+module.exports = {
+ sequelizeUserLogin,
+ testUserLoginDbConnection,
+ Contact,
+ Enterprise,
+ Manager,
+ PublicSeaDemand,
+ RootDb,
+ Login,
+ setupAssociations,
+ User // 导出User模型(可能是实际的模型或临时模型)
+};
\ No newline at end of file
diff --git a/server-example/direct-db-check.js b/server-example/direct-db-check.js
new file mode 100644
index 0000000..f6ba3d0
--- /dev/null
+++ b/server-example/direct-db-check.js
@@ -0,0 +1,175 @@
+// 直接连接数据库检查productQuantity字段的脚本
+const Sequelize = require('sequelize');
+const mysql = require('mysql2/promise');
+
+// 数据库连接配置
+const sequelize = new Sequelize(
+ 'minishop', // 数据库名
+ 'root', // 用户名
+ 'password', // 密码
+ {
+ host: 'localhost',
+ dialect: 'mysql',
+ pool: {
+ max: 5,
+ min: 0,
+ acquire: 30000,
+ idle: 10000
+ },
+ timezone: '+08:00' // 设置时区为UTC+8
+ }
+);
+
+// 定义购物车模型 - 直接复制自server-mysql.js
+class CartItem extends Sequelize.Model {}
+CartItem.init({
+ id: {
+ type: Sequelize.DataTypes.INTEGER,
+ autoIncrement: true,
+ primaryKey: true
+ },
+ userId: {
+ type: Sequelize.DataTypes.STRING(100),
+ allowNull: false
+ },
+ productId: {
+ type: Sequelize.DataTypes.STRING(100),
+ allowNull: false
+ },
+ productName: {
+ type: Sequelize.DataTypes.STRING(255),
+ allowNull: false
+ },
+ specification: {
+ type: Sequelize.DataTypes.STRING(255)
+ },
+ quantity: {
+ type: Sequelize.DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: 1
+ },
+ productQuantity: {
+ type: Sequelize.DataTypes.INTEGER,
+ allowNull: false,
+ defaultValue: 0
+ },
+ grossWeight: {
+ type: Sequelize.DataTypes.DECIMAL(10, 2)
+ },
+ yolk: {
+ type: Sequelize.DataTypes.STRING(100)
+ },
+ price: {
+ type: Sequelize.DataTypes.DECIMAL(10, 2)
+ },
+ selected: {
+ type: Sequelize.DataTypes.BOOLEAN,
+ defaultValue: true
+ },
+ added_at: {
+ type: Sequelize.DataTypes.DATE,
+ defaultValue: Sequelize.NOW
+ }
+}, {
+ sequelize,
+ modelName: 'CartItem',
+ tableName: 'cart_items',
+ timestamps: false
+});
+
+// 检查数据库结构
+async function checkDatabaseStructure() {
+ console.log('开始直接检查数据库中的productQuantity字段...');
+
+ try {
+ // 检查连接
+ await sequelize.authenticate();
+ console.log('✅ 数据库连接成功');
+
+ // 1. 使用原始查询检查表结构
+ console.log('\n1. 检查cart_items表结构...');
+ const [fields, _] = await sequelize.query('DESCRIBE cart_items');
+
+ // 查找productQuantity字段
+ const productQuantityField = fields.find(field => field.Field === 'productQuantity');
+
+ if (productQuantityField) {
+ console.log('✅ 数据库中存在productQuantity字段:');
+ console.log(` - 类型: ${productQuantityField.Type}`);
+ console.log(` - 是否允许NULL: ${productQuantityField.Null === 'YES' ? '是' : '否'}`);
+ console.log(` - 默认值: ${productQuantityField.Default || '无'}`);
+ } else {
+ console.error('❌ 数据库中不存在productQuantity字段!');
+ console.log('cart_items表中的所有字段:', fields.map(field => field.Field).join(', '));
+
+ // 如果不存在,尝试添加这个字段
+ console.log('\n尝试添加productQuantity字段到cart_items表...');
+ try {
+ await sequelize.query('ALTER TABLE cart_items ADD COLUMN productQuantity INT NOT NULL DEFAULT 0');
+ console.log('✅ 成功添加productQuantity字段');
+ } catch (addError) {
+ console.error('❌ 添加字段失败:', addError.message);
+ }
+ }
+
+ // 2. 检查test_user_id的购物车数据
+ console.log('\n2. 检查测试用户的购物车数据...');
+ const cartItems = await CartItem.findAll({
+ where: {
+ userId: 'test_user_id'
+ },
+ // 明确指定返回所有字段
+ attributes: {
+ exclude: [] // 不排除任何字段
+ }
+ });
+
+ console.log(`找到 ${cartItems.length} 条购物车记录`);
+
+ if (cartItems.length > 0) {
+ // 显示第一条记录的所有字段
+ console.log('\n第一条购物车记录的所有字段:');
+ const firstItem = cartItems[0].toJSON();
+ Object.keys(firstItem).forEach(key => {
+ console.log(` - ${key}: ${firstItem[key]}`);
+ });
+
+ // 特别检查productQuantity字段
+ console.log('\nproductQuantity字段在数据中的状态:');
+ cartItems.forEach((item, index) => {
+ const data = item.toJSON();
+ console.log(` 记录 ${index + 1}: productQuantity = ${data.productQuantity !== undefined ? data.productQuantity : 'undefined'}`);
+ });
+ }
+
+ // 3. 尝试直接插入一条带productQuantity的记录
+ console.log('\n3. 尝试直接插入一条带productQuantity的记录...');
+ const testProductId = 'db_test_' + Date.now();
+ const newItem = await CartItem.create({
+ userId: 'test_user_id',
+ productId: testProductId,
+ productName: '数据库测试商品',
+ specification: '测试规格',
+ quantity: 2,
+ productQuantity: 10,
+ grossWeight: 1000,
+ yolk: '测试蛋黄',
+ price: 50,
+ selected: true,
+ added_at: new Date()
+ });
+
+ console.log('✅ 成功插入记录');
+ console.log('插入的记录详情:', newItem.toJSON());
+
+ } catch (error) {
+ console.error('检查过程中发生错误:', error.message);
+ } finally {
+ // 关闭连接
+ await sequelize.close();
+ console.log('\n数据库连接已关闭');
+ }
+}
+
+// 执行检查
+checkDatabaseStructure();
\ No newline at end of file
diff --git a/server-example/ecosystem.config.js b/server-example/ecosystem.config.js
new file mode 100644
index 0000000..900209d
--- /dev/null
+++ b/server-example/ecosystem.config.js
@@ -0,0 +1,86 @@
+module.exports = {
+ apps: [
+ {
+ // 应用名称
+ name: 'wechat-app',
+ // 要运行的脚本 - 修正为正确的启动脚本
+ script: 'start-server.js',
+ // 运行模式 - 设置为fork模式以避免端口冲突
+ exec_mode: 'fork',
+ // 实例数量
+ instances: 1,
+ // 自动重启
+ autorestart: true,
+ // 监听文件变化(开发环境可设置为true)
+ watch: false,
+ // 内存限制,超过则重启
+ max_memory_restart: '1G',
+ // 环境变量
+ env: {
+ NODE_ENV: 'production',
+ PORT: 3002
+ },
+ env_development: {
+ NODE_ENV: 'development',
+ PORT: 3002
+ },
+ // 日志配置 - 重要:这些配置确保PM2正确捕获和显示所有console.log输出
+ log_date_format: 'YYYY-MM-DD HH:mm:ss.SSS',
+ error_file: './logs/error.log',
+ out_file: './logs/output.log',
+ merge_logs: true,
+ combine_logs: false, // 确保不合并日志
+ log_file_max_size: '10MB',
+ // 启用日志时间戳
+ time: true,
+ // 自动重启策略
+ min_uptime: '60s',
+ max_restarts: 10,
+ restart_delay: 1000,
+ // 环境变量文件加载
+ // PM2会自动加载应用目录下的.env文件
+ // 附加参数
+ args: [],
+ // 启动超时时间
+ kill_timeout: 5000,
+ // 启动前的钩子
+ pre_start: "echo 'Starting wechat-miniprogram-server...'",
+ // 启动后的钩子
+ post_start: "echo 'wechat-miniprogram-server started successfully'",
+ // 错误处理
+ error: './logs/process-error.log',
+ // 合并stdout和stderr
+ combine_logs: false
+ }
+ ],
+ // 简化部署配置,用户可以根据实际情况修改
+ deploy: {
+ production: {
+ user: 'your-username',
+ host: 'your-server-ip',
+ ref: 'origin/master',
+ repo: 'your-git-repository-url',
+ path: '/path/to/your/app',
+ 'post-deploy': 'npm install && pm2 reload ecosystem.config.js --env production'
+ }
+ }
+};
+
+/*
+使用说明:
+1. 基本启动:pm2 start ecosystem.config.js
+2. 开发环境启动:pm2 start ecosystem.config.js --env development
+3. 查看状态:pm2 status
+4. 查看日志:pm2 logs wechat-miniprogram-server
+5. 监控应用:pm2 monit
+6. 停止应用:pm2 stop wechat-miniprogram-server
+7. 重启应用:pm2 restart wechat-miniprogram-server
+8. 删除应用:pm2 delete wechat-miniprogram-server
+9. 设置开机自启:pm2 startup && pm2 save
+
+故障排除提示:
+- 如果应用启动失败,查看日志:pm2 logs wechat-miniprogram-server --lines 100
+- 检查端口占用:lsof -i :3001 或 netstat -ano | findstr :3001
+- 确保.env文件配置正确
+- 确保数据库服务正常运行
+*/
\ No newline at end of file
diff --git a/server-example/find-product-creator.js b/server-example/find-product-creator.js
new file mode 100644
index 0000000..d53e1ea
--- /dev/null
+++ b/server-example/find-product-creator.js
@@ -0,0 +1,61 @@
+// 查询特定名称商品的创建者
+
+const dotenv = require('dotenv');
+const mysql = require('mysql2/promise');
+const path = require('path');
+
+// 加载环境变量
+dotenv.config({ path: path.resolve(__dirname, '.env') });
+
+// 数据库连接配置
+const dbConfig = {
+ host: process.env.DB_HOST || 'localhost',
+ port: process.env.DB_PORT || 3306,
+ user: process.env.DB_USER || 'root',
+ password: process.env.DB_PASSWORD || '',
+ database: process.env.DB_NAME || 'wechat_app',
+ timezone: '+08:00' // 设置时区为UTC+8
+};
+
+async function findProductCreator() {
+ let connection;
+ try {
+ // 连接数据库
+ connection = await mysql.createConnection(dbConfig);
+ console.log('数据库连接成功');
+
+ // 查询名称为88888的商品及其创建者
+ const [products] = await connection.query(`
+ SELECT p.productId, p.productName, p.sellerId, u.userId, u.nickName, u.phoneNumber
+ FROM products p
+ LEFT JOIN users u ON p.sellerId = u.userId
+ WHERE p.productName = '88888'
+ `);
+
+ if (products.length === 0) {
+ console.log('未找到名称为88888的商品');
+ return;
+ }
+
+ console.log(`找到 ${products.length} 个名称为88888的商品:`);
+ products.forEach((product, index) => {
+ console.log(`\n商品 ${index + 1}:`);
+ console.log(` 商品ID: ${product.productId}`);
+ console.log(` 商品名称: ${product.productName}`);
+ console.log(` 创建者ID: ${product.sellerId}`);
+ console.log(` 创建者昵称: ${product.nickName || '未设置'}`);
+ console.log(` 创建者手机号: ${product.phoneNumber || '未设置'}`);
+ });
+
+ } catch (error) {
+ console.error('查询失败:', error.message);
+ } finally {
+ if (connection) {
+ await connection.end();
+ console.log('\n数据库连接已关闭');
+ }
+ }
+}
+
+// 执行查询
+findProductCreator();
\ No newline at end of file
diff --git a/server-example/fixed-server.js b/server-example/fixed-server.js
new file mode 100644
index 0000000..d32a12b
--- /dev/null
+++ b/server-example/fixed-server.js
@@ -0,0 +1,85 @@
+// 简单测试服务器 - 不连接数据库,专注于API接口测试和毛重字段处理
+const express = require('express');
+const bodyParser = require('body-parser');
+const path = require('path');
+
+// 创建Express应用
+const app = express();
+const PORT = 3000;
+
+// 中间件
+app.use(bodyParser.json());
+
+// 请求日志中间件
+app.use((req, res, next) => {
+ const now = new Date();
+ console.log(`[${now.toISOString()}] 收到请求: ${req.method} ${req.url}`);
+ next();
+});
+
+// 简单测试接口
+app.get('/api/test-connection', (req, res) => {
+ res.json({
+ success: true,
+ message: '服务器连接测试成功',
+ timestamp: new Date().toISOString(),
+ serverInfo: { port: PORT }
+ });
+});
+
+// 商品发布接口(简化版,专注于毛重处理)
+app.post('/api/product/publish', (req, res) => {
+ try {
+ const { openid, product } = req.body;
+ console.log('收到商品发布请求:', { openid, product });
+
+ // 验证参数
+ if (!openid || !product) {
+ return res.status(400).json({ success: false, message: '缺少必要参数' });
+ }
+
+ // 重点:毛重字段处理逻辑
+ let grossWeightValue = product.grossWeight;
+ console.log('原始毛重值:', grossWeightValue, '类型:', typeof grossWeightValue);
+
+ // 处理各种情况的毛重值
+ if (grossWeightValue === '' || grossWeightValue === null || grossWeightValue === undefined || (typeof grossWeightValue === 'object' && grossWeightValue === null)) {
+ grossWeightValue = null;
+ console.log('毛重值为空或null,设置为null');
+ } else {
+ // 转换为数字
+ const numValue = Number(grossWeightValue);
+ if (!isNaN(numValue) && isFinite(numValue)) {
+ grossWeightValue = numValue;
+ console.log('毛重值成功转换为数字:', grossWeightValue);
+ } else {
+ grossWeightValue = null;
+ console.log('毛重值不是有效数字,设置为null');
+ }
+ }
+
+ // 返回处理结果
+ return res.json({
+ success: true,
+ message: '商品发布处理成功(模拟)',
+ processedData: {
+ productName: product.productName,
+ price: product.price,
+ quantity: product.quantity,
+ grossWeight: grossWeightValue, // 返回处理后的毛重值
+ grossWeightType: typeof grossWeightValue
+ }
+ });
+
+ } catch (error) {
+ console.error('发布商品失败:', error);
+ res.status(500).json({ success: false, message: '服务器错误', error: error.message });
+ }
+});
+
+// 启动服务器
+app.listen(PORT, () => {
+ console.log(`修复版服务器运行在 http://localhost:${PORT}`);
+ console.log('测试接口: http://localhost:3000/api/test-connection');
+ console.log('商品发布接口: POST http://localhost:3000/api/product/publish');
+});
\ No newline at end of file
diff --git a/server-example/free-port.js b/server-example/free-port.js
new file mode 100644
index 0000000..e01b116
--- /dev/null
+++ b/server-example/free-port.js
@@ -0,0 +1,87 @@
+// 检查并释放被占用的端口
+const { exec } = require('child_process');
+const os = require('os');
+
+// 要检查的端口
+const PORT = 3001;
+
+function killProcessOnPort(port) {
+ console.log(`开始检查端口 ${port} 的占用情况...`);
+
+ if (os.platform() === 'win32') {
+ // Windows系统
+ exec(`netstat -ano | findstr :${port}`, (error, stdout) => {
+ if (error) {
+ console.log(`端口 ${port} 未被占用`);
+ return;
+ }
+
+ const lines = stdout.trim().split('\n');
+ if (lines.length > 0) {
+ // 提取PID
+ const pid = lines[0].trim().split(/\s+/).pop();
+ console.log(`发现进程 ${pid} 占用端口 ${port}`);
+
+ // 杀死进程
+ exec(`taskkill /F /PID ${pid}`, (killError) => {
+ if (killError) {
+ console.error(`杀死进程 ${pid} 失败:`, killError.message);
+ } else {
+ console.log(`成功杀死进程 ${pid},端口 ${port} 已释放`);
+ }
+ });
+ } else {
+ console.log(`端口 ${port} 未被占用`);
+ }
+ });
+ } else {
+ // Linux/Mac系统
+ exec(`lsof -i :${port}`, (error, stdout) => {
+ if (error) {
+ console.log(`端口 ${port} 未被占用`);
+ return;
+ }
+
+ const lines = stdout.trim().split('\n');
+ if (lines.length > 1) {
+ // 提取PID
+ const pid = lines[1].trim().split(/\s+/)[1];
+ console.log(`发现进程 ${pid} 占用端口 ${port}`);
+
+ // 杀死进程
+ exec(`kill -9 ${pid}`, (killError) => {
+ if (killError) {
+ console.error(`杀死进程 ${pid} 失败:`, killError.message);
+ } else {
+ console.log(`成功杀死进程 ${pid},端口 ${port} 已释放`);
+ }
+ });
+ } else {
+ console.log(`端口 ${port} 未被占用`);
+ }
+ });
+ }
+}
+
+// 执行端口检查和释放
+killProcessOnPort(PORT);
+
+// 延迟2秒后再次启动服务器(如果是Windows系统)
+setTimeout(() => {
+ if (os.platform() === 'win32') {
+ console.log('\n正在尝试重新启动服务器...');
+ const serverProcess = exec('node server-mysql.js');
+
+ serverProcess.stdout.on('data', (data) => {
+ console.log(`服务器输出: ${data}`);
+ });
+
+ serverProcess.stderr.on('data', (data) => {
+ console.error(`服务器错误: ${data}`);
+ });
+
+ serverProcess.on('close', (code) => {
+ console.log(`服务器进程退出,代码: ${code}`);
+ });
+ }
+}, 2000);
\ No newline at end of file
diff --git a/server-example/gross-weight-fix-error.json b/server-example/gross-weight-fix-error.json
new file mode 100644
index 0000000..b408862
--- /dev/null
+++ b/server-example/gross-weight-fix-error.json
@@ -0,0 +1,5 @@
+{
+ "timestamp": "2025-10-08T03:56:27.607Z",
+ "error": "Access denied for user 'root'@'218.88.54.38' (using password: YES)",
+ "stack": "Error: Access denied for user 'root'@'218.88.54.38' (using password: YES)\n at Object.createConnectionPromise [as createConnection] (D:\\WeichatAPP\\miniprogram-6\\server-example\\node_modules\\mysql2\\promise.js:19:31)\n at fixGrossWeightValues (D:\\WeichatAPP\\miniprogram-6\\server-example\\fix-gross-weight-values.js:26:30)\n at Object. (D:\\WeichatAPP\\miniprogram-6\\server-example\\fix-gross-weight-values.js:143:1)\n at Module._compile (node:internal/modules/cjs/loader:1688:14)\n at Object..js (node:internal/modules/cjs/loader:1820:10)\n at Module.load (node:internal/modules/cjs/loader:1423:32)\n at Function._load (node:internal/modules/cjs/loader:1246:12)\n at TracingChannel.traceSync (node:diagnostics_channel:322:14)\n at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)\n at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:171:5)"
+}
\ No newline at end of file
diff --git a/server-example/gross-weight-frontend-fix-report.json b/server-example/gross-weight-frontend-fix-report.json
new file mode 100644
index 0000000..b0dc4da
--- /dev/null
+++ b/server-example/gross-weight-frontend-fix-report.json
@@ -0,0 +1,24 @@
+{
+ "timestamp": "2025-10-08T03:57:52.452Z",
+ "modified": true,
+ "changes": [
+ {
+ "name": "商品列表API增强",
+ "applied": true
+ },
+ {
+ "name": "用户商品API增强",
+ "applied": false
+ },
+ {
+ "name": "添加毛重处理中间件",
+ "applied": true
+ }
+ ],
+ "recommendations": [
+ "重启服务器",
+ "检查前端页面使用的字段名",
+ "添加商品发布表单的毛重验证",
+ "检查前端数据处理逻辑"
+ ]
+}
\ No newline at end of file
diff --git a/server-example/gross-weight-log-analyzer.js b/server-example/gross-weight-log-analyzer.js
new file mode 100644
index 0000000..a6c41e7
--- /dev/null
+++ b/server-example/gross-weight-log-analyzer.js
@@ -0,0 +1,135 @@
+const fs = require('fs');
+const path = require('path');
+
+// 日志文件路径
+const logFilePath = path.join(__dirname, 'logs', 'output.log');
+
+// 读取并分析日志文件
+function analyzeGrossWeightLogs() {
+ try {
+ console.log(`正在分析日志文件: ${logFilePath}`);
+ console.log('搜索与grossWeight相关的日志记录...\n');
+
+ // 读取日志文件内容
+ const logContent = fs.readFileSync(logFilePath, 'utf-8');
+ const logLines = logContent.split('\n');
+
+ // 存储找到的毛重相关记录
+ const grossWeightRecords = [];
+ const publishRequestRecords = [];
+
+ // 搜索最近24小时的日志记录
+ const twentyFourHoursAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
+
+ // 遍历日志行
+ for (let i = 0; i < logLines.length; i++) {
+ const line = logLines[i];
+
+ // 检查时间戳是否在最近24小时内
+ const timestampMatch = line.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})/);
+ if (timestampMatch) {
+ const logDate = new Date(timestampMatch[1]);
+ if (logDate < twentyFourHoursAgo) {
+ continue; // 跳过24小时前的日志
+ }
+ }
+
+ // 搜索与grossWeight相关的记录
+ if (line.includes('grossWeight')) {
+ grossWeightRecords.push({
+ line: i + 1,
+ content: line,
+ timestamp: timestampMatch ? timestampMatch[1] : '未知'
+ });
+ }
+
+ // 搜索商品发布请求
+ if (line.includes('/api/product/publish')) {
+ // 收集发布请求的上下文
+ const contextLines = [];
+ // 向前收集5行
+ for (let j = Math.max(0, i - 5); j < Math.min(logLines.length, i + 20); j++) {
+ contextLines.push(logLines[j]);
+ }
+ publishRequestRecords.push({
+ line: i + 1,
+ content: contextLines.join('\n'),
+ timestamp: timestampMatch ? timestampMatch[1] : '未知'
+ });
+ }
+ }
+
+ // 输出分析结果
+ console.log('===== 最近24小时毛重字段处理分析结果 =====\n');
+
+ console.log(`找到 ${grossWeightRecords.length} 条与grossWeight相关的日志记录\n`);
+
+ // 显示最近的10条毛重记录
+ console.log('最近的10条毛重处理记录:');
+ grossWeightRecords.slice(-10).forEach((record, index) => {
+ console.log(`[${record.timestamp}] 第${record.line}行: ${record.content}`);
+ });
+
+ console.log('\n');
+
+ // 显示最近的商品发布请求及其毛重处理
+ console.log(`找到 ${publishRequestRecords.length} 条商品发布请求记录`);
+ if (publishRequestRecords.length > 0) {
+ console.log('\n最近的商品发布请求及毛重处理详情:');
+ const latestPublish = publishRequestRecords[publishRequestRecords.length - 1];
+ console.log(`\n时间: ${latestPublish.timestamp}`);
+ console.log(`起始行号: ${latestPublish.line}`);
+ console.log('详细内容:');
+
+ // 解析请求体中的grossWeight值
+ const requestBodyMatch = latestPublish.content.match(/请求体: \{([\s\S]*?)\}/);
+ if (requestBodyMatch) {
+ console.log(requestBodyMatch[0]);
+
+ // 提取grossWeight值
+ const grossWeightMatch = requestBodyMatch[0].match(/"grossWeight"\s*:\s*(null|\d+(\.\d+)?)/);
+ if (grossWeightMatch) {
+ console.log(`\n请求中的毛重值: ${grossWeightMatch[1]}`);
+ }
+ }
+
+ // 查找毛重处理的相关日志
+ const grossWeightProcessingMatch = latestPublish.content.match(/\[发布商品.*\] 原始毛重值:.*|毛重值.*设置为.*|最终处理的毛重值:.*|grossWeightStored:.*|毛重.*转换为数字/);
+ if (grossWeightProcessingMatch) {
+ console.log('\n毛重处理过程:');
+ grossWeightProcessingMatch.forEach(processingLine => {
+ console.log(processingLine);
+ });
+ }
+ }
+
+ // 生成总结
+ console.log('\n===== 分析总结 =====');
+ if (grossWeightRecords.length === 0) {
+ console.log('在最近24小时内没有找到与grossWeight相关的日志记录。');
+ } else {
+ console.log(`在最近24小时内找到了 ${grossWeightRecords.length} 条与grossWeight相关的日志记录。`);
+
+ // 简单统计
+ const nullGrossWeightCount = grossWeightRecords.filter(r => r.content.includes('grossWeight: null')).length;
+ const zeroGrossWeightCount = grossWeightRecords.filter(r => r.content.includes('grossWeight: 0')).length;
+ const numericGrossWeightCount = grossWeightRecords.filter(r => /grossWeight:\s*\d+\.\d+/.test(r.content)).length;
+
+ console.log(`- 毛重为null的记录数: ${nullGrossWeightCount}`);
+ console.log(`- 毛重为0的记录数: ${zeroGrossWeightCount}`);
+ console.log(`- 毛重为数字的记录数: ${numericGrossWeightCount}`);
+ }
+
+ console.log('\n提示: 如果需要查看更多详细信息,建议直接查看日志文件或使用更专业的日志分析工具。');
+
+ } catch (error) {
+ console.error('分析日志时发生错误:', error.message);
+ console.log('\n建议手动查看日志文件:');
+ console.log(`1. 打开文件: ${logFilePath}`);
+ console.log('2. 搜索关键词: grossWeight');
+ console.log('3. 特别关注: 发布商品请求中的grossWeight值和处理过程');
+ }
+}
+
+// 执行分析
+analyzeGrossWeightLogs();
\ No newline at end of file
diff --git a/server-example/list-users.js b/server-example/list-users.js
new file mode 100644
index 0000000..7a1a054
--- /dev/null
+++ b/server-example/list-users.js
@@ -0,0 +1,67 @@
+require('dotenv').config();
+const mysql = require('mysql2/promise');
+
+// 查询用户信息
+async function listUsers() {
+ let connection = null;
+ try {
+ console.log('连接数据库...');
+ connection = await mysql.createConnection({
+ host: process.env.DB_HOST || 'localhost',
+ user: process.env.DB_USER || 'root',
+ password: process.env.DB_PASSWORD === undefined ? null : process.env.DB_PASSWORD,
+ database: process.env.DB_DATABASE || 'wechat_app',
+ port: process.env.DB_PORT || 3306,
+ timezone: '+08:00' // 设置时区为UTC+8
+ });
+ console.log('数据库连接成功\n');
+
+ // 查询users表结构
+ console.log('=== users表结构 ===');
+ const [columns] = await connection.execute(
+ 'SHOW COLUMNS FROM users'
+ );
+ console.log('字段列表:', columns.map(col => col.Field).join(', '));
+ console.log();
+
+ // 查询前5个用户数据
+ console.log('=== 用户数据 (前5个) ===');
+ const [users] = await connection.execute(
+ 'SELECT * FROM users LIMIT 5'
+ );
+ console.log(`数据库中有 ${users.length} 个用户记录`);
+
+ if (users.length > 0) {
+ users.forEach((user, index) => {
+ console.log(`${index + 1}. 用户数据:`, user);
+ });
+
+ // 查找可能的openid字段
+ const firstUser = users[0];
+ const possibleOpenIdFields = Object.keys(firstUser).filter(key =>
+ key.toLowerCase().includes('openid') || key.toLowerCase().includes('open_id')
+ );
+
+ if (possibleOpenIdFields.length > 0) {
+ console.log('\n=== 可能的openid字段 ===');
+ console.log('找到以下可能的openid字段:', possibleOpenIdFields.join(', '));
+ console.log('请使用其中一个有效的字段更新测试脚本');
+ } else {
+ console.log('\n未找到明显的openid字段,请检查users表结构后手动更新测试脚本');
+ }
+ } else {
+ console.log('\n数据库中没有用户记录');
+ }
+
+ } catch (error) {
+ console.error('查询过程中发生错误:', error);
+ } finally {
+ if (connection) {
+ await connection.end();
+ console.log('\n数据库连接已关闭');
+ }
+ }
+}
+
+// 运行查询
+listUsers();
\ No newline at end of file
diff --git a/server-example/logger.js b/server-example/logger.js
new file mode 100644
index 0000000..b67a2db
--- /dev/null
+++ b/server-example/logger.js
@@ -0,0 +1,86 @@
+// 日志记录模块,用于将控制台输出同时保存到文件
+const fs = require('fs');
+const path = require('path');
+
+// 确保logs目录存在
+const logsDir = path.join(__dirname, 'logs');
+if (!fs.existsSync(logsDir)) {
+ fs.mkdirSync(logsDir);
+}
+
+// 获取当前日期,用于日志文件名
+function getCurrentDate() {
+ const now = new Date();
+ const year = now.getFullYear();
+ const month = String(now.getMonth() + 1).padStart(2, '0');
+ const day = String(now.getDate()).padStart(2, '0');
+ return `${year}-${month}-${day}`;
+}
+
+// 获取带时区的时间戳
+function getFormattedTimestamp() {
+ const now = new Date();
+ const beijingTime = new Date(now.getTime() + 8 * 60 * 60 * 1000);
+ return beijingTime.toISOString().replace('Z', '+08:00');
+}
+
+// 写入日志到文件
+function writeLogToFile(level, message) {
+ const timestamp = getFormattedTimestamp();
+ const logMessage = `[${timestamp}] [${level}] ${message}\n`;
+ const logFilePath = path.join(logsDir, `server-${getCurrentDate()}.log`);
+
+ fs.appendFile(logFilePath, logMessage, (err) => {
+ if (err) {
+ console.error('写入日志文件失败:', err);
+ }
+ });
+}
+
+// 重写console.log,使其同时输出到控制台和文件
+const originalConsoleLog = console.log;
+const originalConsoleError = console.error;
+const originalConsoleWarn = console.warn;
+const originalConsoleInfo = console.info;
+
+console.log = function (...args) {
+ const message = args.map(arg =>
+ typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
+ ).join(' ');
+
+ originalConsoleLog.apply(console, args);
+ writeLogToFile('INFO', message);
+};
+
+console.error = function (...args) {
+ const message = args.map(arg =>
+ typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
+ ).join(' ');
+
+ originalConsoleError.apply(console, args);
+ writeLogToFile('ERROR', message);
+};
+
+console.warn = function (...args) {
+ const message = args.map(arg =>
+ typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
+ ).join(' ');
+
+ originalConsoleWarn.apply(console, args);
+ writeLogToFile('WARN', message);
+};
+
+console.info = function (...args) {
+ const message = args.map(arg =>
+ typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
+ ).join(' ');
+
+ originalConsoleInfo.apply(console, args);
+ writeLogToFile('INFO', message);
+};
+
+module.exports = {
+ logsDir,
+ getFormattedTimestamp,
+ writeLogToFile
+};
\ No newline at end of file
diff --git a/server-example/oss-config.js b/server-example/oss-config.js
new file mode 100644
index 0000000..1f7d8af
--- /dev/null
+++ b/server-example/oss-config.js
@@ -0,0 +1,8 @@
+// 阿里云OSS配置
+module.exports = {
+ region: 'oss-cn-chengdu', // OSS区域,例如 'oss-cn-hangzhou'
+ accessKeyId: 'LTAI5tRT6ReeHUdmqFpmLZi7', // 访问密钥ID
+ accessKeySecret: 'zTnK27IAphwgCDMmyJzMUsHYxGsDBE', // 访问密钥Secret
+ bucket: 'my-supplier-photos', // OSS存储桶名称
+ endpoint: 'oss-cn-chengdu.aliyuncs.com' // 注意:不要在endpoint中包含bucket名称
+};
\ No newline at end of file
diff --git a/server-example/oss-uploader.js b/server-example/oss-uploader.js
new file mode 100644
index 0000000..c4e9db2
--- /dev/null
+++ b/server-example/oss-uploader.js
@@ -0,0 +1,319 @@
+const fs = require('fs');
+const path = require('path');
+const { createHash } = require('crypto');
+const OSSClient = require('ali-oss');
+const ossConfig = require('./oss-config');
+
+// 创建OSS客户端 - ali-oss 6.23.0版本的正确配置
+let client = null;
+
+// 初始化OSS客户端的函数
+function initOSSClient() {
+ try {
+ console.log('初始化OSS客户端配置:', {
+ region: ossConfig.region,
+ accessKeyId: ossConfig.accessKeyId ? '已配置' : '未配置',
+ accessKeySecret: ossConfig.accessKeySecret ? '已配置' : '未配置',
+ bucket: ossConfig.bucket,
+ endpoint: `https://${ossConfig.endpoint}`
+ });
+
+ client = new OSSClient({
+ region: ossConfig.region,
+ accessKeyId: ossConfig.accessKeyId,
+ accessKeySecret: ossConfig.accessKeySecret,
+ bucket: ossConfig.bucket,
+ endpoint: `https://${ossConfig.endpoint}`, // 添加https协议前缀
+ cname: false // 对于标准OSS域名,不需要启用cname模式
+ });
+
+ return client;
+ } catch (error) {
+ console.error('初始化OSS客户端失败:', error);
+ throw error;
+ }
+}
+
+// 延迟初始化,避免应用启动时就连接OSS
+function getOSSClient() {
+ if (!client) {
+ return initOSSClient();
+ }
+ return client;
+}
+
+class OssUploader {
+ /**
+ * 上传文件到OSS
+ * @param {String} filePath - 本地文件路径
+ * @param {String} folder - OSS上的文件夹路径
+ * @param {String} fileType - 文件类型,默认为'image'
+ * @returns {Promise} - 上传后的文件URL
+ */
+ /**
+ * 计算文件的MD5哈希值
+ * @param {String} filePath - 文件路径
+ * @returns {Promise} - MD5哈希值
+ */
+ static async getFileHash(filePath) {
+ return new Promise((resolve, reject) => {
+ const hash = createHash('md5');
+ const stream = fs.createReadStream(filePath);
+
+ stream.on('error', reject);
+ stream.on('data', chunk => hash.update(chunk));
+ stream.on('end', () => resolve(hash.digest('hex')));
+ });
+ }
+
+ /**
+ * 计算缓冲区的MD5哈希值
+ * @param {Buffer} buffer - 数据缓冲区
+ * @returns {String} - MD5哈希值
+ */
+ static getBufferHash(buffer) {
+ return createHash('md5').update(buffer).digest('hex');
+ }
+
+ static async uploadFile(filePath, folder = 'images', fileType = 'image') {
+ try {
+ console.log('【OSS上传】开始上传文件:', filePath, '到目录:', folder);
+
+ // 确保文件存在
+ const fileExists = await fs.promises.access(filePath).then(() => true).catch(() => false);
+ if (!fileExists) {
+ throw new Error(`文件不存在: ${filePath}`);
+ }
+
+ // 获取文件扩展名
+ const extname = path.extname(filePath).toLowerCase();
+ if (!extname) {
+ throw new Error(`无法获取文件扩展名: ${filePath}`);
+ }
+
+ // 基于文件内容计算MD5哈希值,实现文件级去重
+ console.log('【文件去重】开始计算文件哈希值...');
+ const fileHash = await this.getFileHash(filePath);
+ console.log(`【文件去重】文件哈希计算完成: ${fileHash}`);
+
+ // 使用哈希值作为文件名,确保相同内容的文件生成相同的文件名
+ const uniqueFilename = `${fileHash}${extname}`;
+ const ossFilePath = `${folder}/${fileType}/${uniqueFilename}`;
+
+ console.log(`【文件去重】使用基于内容的文件名: ${uniqueFilename}`);
+
+ // 获取OSS客户端,延迟初始化
+ const ossClient = getOSSClient();
+
+ // 测试OSS连接
+ try {
+ await ossClient.list({ max: 1 });
+ console.log('OSS连接测试成功');
+ } catch (connError) {
+ console.error('OSS连接测试失败,尝试重新初始化客户端:', connError.message);
+ // 尝试重新初始化客户端
+ initOSSClient();
+ }
+
+ // 检查OSS客户端配置
+ console.log('【OSS上传】OSS配置检查 - region:', ossClient.options.region, 'bucket:', ossClient.options.bucket);
+
+ // 上传文件,明确设置为公共读权限
+ console.log(`开始上传文件到OSS: ${filePath} -> ${ossFilePath}`);
+ const result = await ossClient.put(ossFilePath, filePath, {
+ headers: {
+ 'x-oss-object-acl': 'public-read' // 确保文件可以公开访问
+ },
+ acl: 'public-read' // 额外设置ACL参数,确保文件公开可读
+ });
+ console.log(`文件上传成功: ${result.url}`);
+ console.log('已设置文件为公共读权限');
+
+ // 返回完整的文件URL
+ return result.url;
+ } catch (error) {
+ console.error('【OSS上传】上传文件失败:', error);
+ console.error('【OSS上传】错误详情:', error.message);
+ console.error('【OSS上传】错误栈:', error.stack);
+ throw error;
+ }
+ }
+
+ /**
+ * 从缓冲区上传文件到OSS
+ * @param {Buffer} buffer - 文件数据缓冲区
+ * @param {String} filename - 文件名
+ * @param {String} folder - OSS上的文件夹路径
+ * @param {String} fileType - 文件类型,默认为'image'
+ * @returns {Promise} - 上传后的文件URL
+ */
+ static async uploadBuffer(buffer, filename, folder = 'images', fileType = 'image') {
+ try {
+ // 获取文件扩展名
+ const extname = path.extname(filename).toLowerCase();
+ if (!extname) {
+ throw new Error(`无法获取文件扩展名: ${filename}`);
+ }
+
+ // 基于文件内容计算MD5哈希值,实现文件级去重
+ console.log('【文件去重】开始计算缓冲区哈希值...');
+ const bufferHash = this.getBufferHash(buffer);
+ console.log(`【文件去重】缓冲区哈希计算完成: ${bufferHash}`);
+
+ // 使用哈希值作为文件名,确保相同内容的文件生成相同的文件名
+ const uniqueFilename = `${bufferHash}${extname}`;
+ const ossFilePath = `${folder}/${fileType}/${uniqueFilename}`;
+
+ console.log(`【文件去重】使用基于内容的文件名: ${uniqueFilename}`);
+
+ // 获取OSS客户端,延迟初始化
+ const ossClient = getOSSClient();
+
+ // 上传缓冲区,明确设置为公共读权限
+ console.log(`开始上传缓冲区到OSS: ${ossFilePath}`);
+ const result = await ossClient.put(ossFilePath, buffer, {
+ headers: {
+ 'x-oss-object-acl': 'public-read' // 确保文件可以公开访问
+ },
+ acl: 'public-read' // 额外设置ACL参数,确保文件公开可读
+ });
+ console.log(`缓冲区上传成功: ${result.url}`);
+ console.log('已设置文件为公共读权限');
+
+ // 返回完整的文件URL
+ return result.url;
+ } catch (error) {
+ console.error('OSS缓冲区上传失败:', error);
+ console.error('OSS缓冲区上传错误详情:', error.message);
+ console.error('OSS缓冲区上传错误栈:', error.stack);
+ throw error;
+ }
+ }
+
+ /**
+ * 批量上传文件到OSS
+ * @param {Array} filePaths - 本地文件路径数组
+ * @param {String} folder - OSS上的文件夹路径
+ * @param {String} fileType - 文件类型,默认为'image'
+ * @returns {Promise>} - 上传后的文件URL数组
+ */
+ static async uploadFiles(filePaths, folder = 'images', fileType = 'image') {
+ try {
+ const uploadPromises = filePaths.map(filePath =>
+ this.uploadFile(filePath, folder, fileType)
+ );
+
+ const urls = await Promise.all(uploadPromises);
+ console.log(`批量上传完成,成功上传${urls.length}个文件`);
+ return urls;
+ } catch (error) {
+ console.error('OSS批量上传失败:', error);
+ throw error;
+ }
+ }
+
+/**
+ * 删除OSS上的文件
+ * @param {String} ossFilePath - OSS上的文件路径
+ * @returns {Promise} - 删除是否成功
+ */
+static async deleteFile(ossFilePath) {
+ try {
+ console.log(`【OSS删除】开始删除OSS文件: ${ossFilePath}`);
+ const ossClient = getOSSClient();
+
+ // 【新增】记录OSS客户端配置信息(隐藏敏感信息)
+ console.log(`【OSS删除】OSS客户端配置 - region: ${ossClient.options.region}, bucket: ${ossClient.options.bucket}`);
+
+ const result = await ossClient.delete(ossFilePath);
+ console.log(`【OSS删除】OSS文件删除成功: ${ossFilePath}`, result);
+ return true;
+ } catch (error) {
+ console.error('【OSS删除】OSS文件删除失败:', ossFilePath, '错误:', error.message);
+ console.error('【OSS删除】错误详情:', error);
+
+ // 【增强日志】详细分析错误类型
+ console.log('【OSS删除】=== 错误详细分析开始 ===');
+ console.log('【OSS删除】错误名称:', error.name);
+ console.log('【OSS删除】错误代码:', error.code);
+ console.log('【OSS删除】HTTP状态码:', error.status);
+ console.log('【OSS删除】请求ID:', error.requestId);
+ console.log('【OSS删除】主机ID:', error.hostId);
+
+ // 【关键检查】判断是否为权限不足错误
+ const isPermissionError =
+ error.code === 'AccessDenied' ||
+ error.status === 403 ||
+ error.message.includes('permission') ||
+ error.message.includes('AccessDenied') ||
+ error.message.includes('do not have write permission');
+
+ if (isPermissionError) {
+ console.error('【OSS删除】❌ 确认是权限不足错误!');
+ console.error('【OSS删除】❌ 当前AccessKey缺少删除文件的权限');
+ console.error('【OSS删除】❌ 请检查RAM策略是否包含 oss:DeleteObject 权限');
+ console.error('【OSS删除】❌ 建议在RAM中授予 AliyunOSSFullAccess 或自定义删除权限');
+ }
+
+ console.log('【OSS删除】=== 错误详细分析结束 ===');
+
+ // 如果文件不存在,也算删除成功
+ if (error.code === 'NoSuchKey' || error.status === 404) {
+ console.log(`【OSS删除】文件不存在,视为删除成功: ${ossFilePath}`);
+ return true;
+ }
+
+ // 【新增】对于权限错误,提供更友好的错误信息
+ if (isPermissionError) {
+ const permissionError = new Error(`OSS删除权限不足: ${error.message}`);
+ permissionError.code = 'OSS_ACCESS_DENIED';
+ permissionError.originalError = error;
+ throw permissionError;
+ }
+
+ throw error;
+ }
+}
+ /**
+ * 获取OSS配置信息
+ * @returns {Object} - OSS配置信息
+ */
+ static getConfig() {
+ return {
+ region: ossConfig.region,
+ bucket: ossConfig.bucket,
+ endpoint: ossConfig.endpoint
+ };
+ }
+
+ /**
+ * 测试OSS连接
+ * @returns {Promise