vite-uni-dev-tool 0.0.17 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -197,6 +197,16 @@ optimizeDeps: {
197
197
 
198
198
  ## 更新日志
199
199
 
200
+ ### 0.0.19
201
+
202
+ - 修复 VirtualListPro 向上滚动
203
+
204
+ ### 0.0.18
205
+
206
+ - Network Send 兼容微信小程序
207
+ - Network Send 去除部分传参格式
208
+ - 部分样式兼容 暗夜模式
209
+
200
210
  ### 0.0.17
201
211
 
202
212
  - v3增加网络请求排序
@@ -164,43 +164,22 @@ export default {
164
164
  }
165
165
  },
166
166
  // 更新可视区域数据
167
- updateVisitableData(direction) {
168
- let tempList = [...this.visitableData];
167
+ updateVisitableData() {
168
+ const tempList = [...this.visitableData];
169
169
  const pageSize = this.pageSize;
170
170
  const current = this.current;
171
171
 
172
- if (direction === 'down') {
173
- // 向下滚动:移除最前面的一页,添加新的一页
174
- tempList.splice(0, pageSize);
175
- const start = pageSize * current;
176
- let end = pageSize * (current + 1);
177
- end = end > this.dataSource.length ? this.dataSource.length : end;
178
- const newData = this.dataSource.slice(start, end);
179
- tempList.push(...newData);
180
- } else {
181
- // 向上滚动:移除最后面的多余数据,添加前面的一页
182
- // 将最末尾的部分进行隐藏
183
- const delCount =
184
- tempList.length - pageSize > 0
185
- ? pageSize
186
- : tempList.length - pageSize;
172
+ // 计算新的起始和结束索引
187
173
 
188
- tempList.splice(pageSize, delCount);
174
+ const currentSub1 = current - 1 < 0 ? 0 : current - 1;
175
+ const currentAdd1 = current + 1;
189
176
 
190
- // 处理上一页内容
191
- let start = pageSize * (current - 1);
177
+ const startIndex = currentSub1 * pageSize;
178
+ const endIndex = Math.min(currentAdd1 * pageSize, data.length);
192
179
 
193
- start = start < 0 ? 0 : start;
180
+ // 更新可见数据
194
181
 
195
- const end = pageSize * current;
196
-
197
- if (end < 0) return;
198
-
199
- const newData = this.dataSource.slice(start, end);
200
- tempList.unshift(...newData);
201
- }
202
-
203
- this.visitableData = tempList;
182
+ this.visitableData = tempList.slice(startIndex, endIndex);
204
183
  },
205
184
  // 更新总高度(累加已加载项的高度)
206
185
  updateCurrentHeight() {
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <view class="app-info-content">
3
- <JsonPretty v-if="showJson" :data="appInfo" />
3
+ <JsonPretty v-if="showJson" :data="appInfo" :theme="theme" />
4
4
  <Empty v-else />
5
5
  </view>
6
6
  </template>
@@ -10,6 +10,7 @@ import JsonPretty from '../JsonPretty/index.vue';
10
10
  import Empty from '../Empty/index.vue';
11
11
  const props = defineProps<{
12
12
  appInfo: Record<string, any>;
13
+ theme?: string;
13
14
  }>();
14
15
 
15
16
  const showJson = computed(() => {
@@ -118,6 +118,7 @@
118
118
  v-if="swiperShow(8)"
119
119
  v-model:storage-list="storageList"
120
120
  v-model="searchStorage"
121
+ :theme="theme"
121
122
  @choose="onStorageChoose"
122
123
  @remove="onStorageRemove"
123
124
  @diff-value="onChangeStorage"
@@ -128,6 +129,7 @@
128
129
  <VuexList
129
130
  v-if="swiperShow(9)"
130
131
  v-model:vuexList="vuexList"
132
+ :theme="theme"
131
133
  @diff-value="onChangeVuex"
132
134
  />
133
135
  </swiper-item>
@@ -135,20 +137,33 @@
135
137
  <PiniaList
136
138
  v-if="swiperShow(10)"
137
139
  v-model:pinia-list="piniaList"
140
+ :theme="theme"
138
141
  @diff-value="onChangePinia"
139
142
  />
140
143
  </swiper-item>
141
144
  <swiper-item>
142
- <WindowInfo v-if="swiperShow(11)" :windowInfo="windowInfo" />
145
+ <WindowInfo
146
+ v-if="swiperShow(11)"
147
+ :windowInfo="windowInfo"
148
+ :theme="theme"
149
+ />
143
150
  </swiper-item>
144
151
  <swiper-item>
145
- <DeviceInfo v-if="swiperShow(12)" :deviceInfo="deviceInfo" />
152
+ <DeviceInfo
153
+ v-if="swiperShow(12)"
154
+ :deviceInfo="deviceInfo"
155
+ :theme="theme"
156
+ />
146
157
  </swiper-item>
147
158
  <swiper-item>
148
- <SystemInfo v-if="swiperShow(13)" :systemInfo="systemInfo" />
159
+ <SystemInfo
160
+ v-if="swiperShow(13)"
161
+ :systemInfo="systemInfo"
162
+ :theme="theme"
163
+ />
149
164
  </swiper-item>
150
165
  <swiper-item>
151
- <AppInfo v-if="swiperShow(14)" :appInfo="appInfo" />
166
+ <AppInfo v-if="swiperShow(14)" :appInfo="appInfo" :theme="theme" />
152
167
  </swiper-item>
153
168
  <swiper-item>
154
169
  <SettingList
@@ -379,7 +394,7 @@ const activeTab = ref(0);
379
394
  const tabScrollLeft = ref(0);
380
395
  const currentConsoleType = ref('all');
381
396
  const currentNetworkType = ref('all');
382
- const currentNetworkSort = ref(1);
397
+ const currentNetworkSort = ref<-1 | 1>(1);
383
398
  const currentUploadType = ref('all');
384
399
  const currentWebSocketType = ref('all');
385
400
 
@@ -1122,7 +1137,7 @@ function onCloseCode() {
1122
1137
  openCode.value = false;
1123
1138
  stack.value = '';
1124
1139
  }
1125
- function onOpenCode(value: string) {
1140
+ function onOpenCode(value?: string) {
1126
1141
  if (!value) return;
1127
1142
 
1128
1143
  stack.value = value;
@@ -1216,7 +1231,7 @@ function onOpenCode(value: string) {
1216
1231
  --dev-tool-active-bg-color: #f0f0f0;
1217
1232
  --dev-tool-time-line-color: #9254de;
1218
1233
  }
1219
- .dev-tool-window-dart {
1234
+ .dev-tool-window-dark {
1220
1235
  --dev-tool-bg-color: rgba(0, 0, 0, 0.8);
1221
1236
  --dev-tool-bg2-color: rgba(43, 43, 43, 0.8);
1222
1237
  --dev-tool-bg3-color: rgba(43, 43, 43, 0.999);
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <view class="device-info-content">
3
- <JsonPretty :data="deviceInfo" v-if="showJson" />
3
+ <JsonPretty :data="deviceInfo" v-if="showJson" :theme="theme" />
4
4
  <Empty v-else />
5
5
  </view>
6
6
  </template>
@@ -10,6 +10,7 @@ import Empty from '../Empty/index.vue';
10
10
  import JsonPretty from '../JsonPretty/index.vue';
11
11
  const props = defineProps<{
12
12
  deviceInfo: Record<string, any>;
13
+ theme?: string;
13
14
  }>();
14
15
 
15
16
  const showJson = computed(() => {
@@ -95,6 +95,7 @@ function onSelect(item: { label: string; value: any }) {
95
95
  align-items: center;
96
96
  padding: 0 8px;
97
97
  width: 100%;
98
+ min-width: 100px;
98
99
  height: 24px;
99
100
 
100
101
  border-radius: 4px;
@@ -472,5 +472,7 @@ onUnmounted(() => {
472
472
 
473
473
  .dark {
474
474
  /* 深色主题样式 */
475
+ --json-pretty-color-nil: #bfcbd9;
476
+ --json-pretty-color-undefined: var(--json-pretty-color-nil);
475
477
  }
476
478
  </style>
@@ -154,6 +154,7 @@ function onClose() {
154
154
  position: fixed;
155
155
  width: 100vw;
156
156
  height: 100%;
157
+ z-index: 5;
157
158
  /* z-index: 1001; */
158
159
  top: 0;
159
160
  left: 0;
@@ -142,7 +142,7 @@ const isUseDevSource = computed(() => {
142
142
 
143
143
  .network-stock {
144
144
  text-align: right;
145
- word-wrap: break-all;
145
+ word-wrap: break-word;
146
146
  }
147
147
  .network-stock-link {
148
148
  text-decoration: underline;
@@ -1,6 +1,14 @@
1
1
  <template>
2
2
  <view class="network-send" :style="{ zIndex: zIndex }">
3
3
  <view class="network-send-form">
4
+ <view class="network-send-control">
5
+ <DevToolTitle>超时时间</DevToolTitle>
6
+ </view>
7
+ <input
8
+ class="network-input"
9
+ :value="state.timeout"
10
+ @input="onChangeState($event, 'timeout')"
11
+ />
4
12
  <view class="network-send-control">
5
13
  <DevToolTitle>请求方式</DevToolTitle>
6
14
  <CircularButton style="margin-left: auto" text="×" @click="onClose" />
@@ -8,7 +16,7 @@
8
16
  <radio-group class="radio-group" @change="onChangeRequestMethod">
9
17
  <label
10
18
  class="radio-group-item"
11
- v-for="(item, index) in requestMethods"
19
+ v-for="item in requestMethods"
12
20
  :key="item.value"
13
21
  >
14
22
  <radio
@@ -21,17 +29,6 @@
21
29
  <view>{{ item.name }}</view>
22
30
  </label>
23
31
  </radio-group>
24
- <DevToolTitle>请求地址</DevToolTitle>
25
- <input
26
- placeholder="请输入请求地址"
27
- placeholderStyle="font-size: 12px"
28
- class="network-input"
29
- v-model="state.url"
30
- />
31
- <view class="form-error-message">
32
- {{ hasUrl ? '' : '请输入请求地址' }}
33
- </view>
34
-
35
32
  <view class="network-send-control">
36
33
  <DevToolTitle>请求头</DevToolTitle>
37
34
  <CircularButton
@@ -42,7 +39,10 @@
42
39
  </view>
43
40
 
44
41
  <view class="network-header-list">
45
- <template v-if="headerList.length > 0">
42
+ <checkbox-group
43
+ v-if="headerList.length > 0"
44
+ @change="onChangeHeaderChecked"
45
+ >
46
46
  <view
47
47
  class="network-header-item"
48
48
  v-for="(item, index) in headerList"
@@ -50,16 +50,18 @@
50
50
  >
51
51
  <checkbox :checked="item.checked" />
52
52
  <input
53
- v-model="item.key"
54
53
  class="network-input"
55
54
  placeholder="请输入请求头名称"
56
55
  placeholderStyle="font-size: 12px"
56
+ :value="item.key"
57
+ @input="onChangeHeader($event, 'key', index)"
57
58
  />
58
59
  <input
59
- v-model="item.value"
60
60
  class="network-input"
61
61
  placeholder="请输入请求头值"
62
62
  placeholderStyle="font-size: 12px"
63
+ :value="item.value"
64
+ @input="onChangeHeader($event, 'value', index)"
63
65
  />
64
66
  <CircularButton
65
67
  style="margin-left: 6px"
@@ -67,10 +69,21 @@
67
69
  @click="onDeleteHeader(item)"
68
70
  />
69
71
  </view>
70
- </template>
72
+ </checkbox-group>
71
73
 
72
74
  <view class="network-empty" v-else> 暂无请求头 </view>
73
75
  </view>
76
+ <DevToolTitle>请求地址</DevToolTitle>
77
+ <textarea
78
+ placeholder="请输入请求地址"
79
+ placeholderStyle="font-size: 12px"
80
+ class="network-textarea"
81
+ :value="state.url"
82
+ @input="onChangeUrl"
83
+ />
84
+ <view class="form-error-message">
85
+ {{ hasUrl ? '' : '请输入请求地址' }}
86
+ </view>
74
87
 
75
88
  <view class="network-send-control">
76
89
  <DevToolTitle>请求参数(query)</DevToolTitle>
@@ -92,16 +105,18 @@
92
105
  >
93
106
  <checkbox :checked="item.checked" :value="item.id" />
94
107
  <input
95
- v-model="item.key"
96
108
  class="network-input"
97
109
  placeholder="请输入参数名称"
98
110
  placeholderStyle="font-size: 12px"
111
+ :value="item.key"
112
+ @input="onChangeQuery($event, 'key', index)"
99
113
  />
100
114
  <input
101
- v-model="item.value"
102
115
  class="network-input"
103
116
  placeholder="请输入参数值"
104
117
  placeholderStyle="font-size: 12px"
118
+ :value="item.value"
119
+ @input="onChangeQuery($event, 'value', index)"
105
120
  />
106
121
  <CircularButton
107
122
  text="一"
@@ -114,83 +129,18 @@
114
129
  <view class="network-empty" v-else> 暂无请求参数 </view>
115
130
  </view>
116
131
 
117
- <template v-if="state.method === 'POST' || state.method === 'PUT'">
132
+ <template v-if="!noBodyRequestMethods.includes(state.method)">
118
133
  <view class="network-send-control">
119
134
  <DevToolTitle>请求体(body)</DevToolTitle>
120
- <CircularButton
121
- v-if="
122
- state.bodyType == 'form-data' ||
123
- state.bodyType == 'x-www-form-urlencoded'
124
- "
125
- style="margin-left: auto"
126
- text="+"
127
- @click="onAddBody"
128
- />
129
- </view>
130
-
131
- <radio-group class="radio-group" @change="onChangeBodyType">
132
- <label
133
- class="radio-group-item"
134
- v-for="(item, index) in bodyTypes"
135
- :key="item.value"
136
- >
137
- <radio
138
- size
139
- style="transform: scale(0.8)"
140
- :value="item.value"
141
- :checked="item.value === state.bodyType"
142
- />
143
-
144
- <view>{{ item.name }}</view>
145
- </label>
146
- </radio-group>
147
-
148
- <view
149
- class="network-body-data"
150
- v-if="
151
- state.bodyType == 'form-data' ||
152
- state.bodyType == 'x-www-form-urlencoded'
153
- "
154
- >
155
- <template v-if="bodyList.length > 0">
156
- <checkbox-group
157
- class="network-body-data-item"
158
- v-for="(item, index) in bodyList"
159
- :key="item.id"
160
- @change="onChangeBodyChecked"
161
- >
162
- <checkbox v-model="item.checked" />
163
- <input
164
- v-model="item.key"
165
- class="network-input"
166
- placeholder="请输入参数名称"
167
- placeholderStyle="font-size: 12px"
168
- />
169
- <input
170
- v-model="item.value"
171
- class="network-input"
172
- placeholder="请输入参数值"
173
- placeholderStyle="font-size: 12px"
174
- />
175
- <CircularButton
176
- text="一"
177
- style="margin-left: 6px"
178
- @click="onDeleteBody(item)"
179
- />
180
- </checkbox-group>
181
- </template>
182
-
183
- <view class="network-empty" v-else> 暂无请求参数 </view>
184
135
  </view>
185
136
 
186
137
  <textarea
187
- v-else-if="state.bodyType == 'Raw text'"
188
- v-model="state.bodyText"
189
138
  placeholder="请输入请求体"
190
- class="network-body-textarea"
139
+ class="network-textarea"
191
140
  placeholderStyle="font-size: 12px"
141
+ :value="state.bodyText"
142
+ @input="onChangeState($event, 'bodyText')"
192
143
  />
193
- <view class="network-empty" v-else> 暂无请求参数 </view>
194
144
  </template>
195
145
 
196
146
  <view class="network-send-buttons">
@@ -211,12 +161,11 @@
211
161
  </template>
212
162
  <script lang="ts" setup>
213
163
  import { ref, reactive, onMounted } from 'vue';
214
-
215
164
  import CircularButton from '../CircularButton/index.vue';
216
165
  import DevToolTitle from '../DevToolTitle/index.vue';
217
166
  import NetworkDetail from './NetworkDetail.vue';
218
167
  import type { DevTool } from '../../type';
219
- import { isObject, isString } from '../../utils';
168
+
220
169
  const props = defineProps<{ network: DevTool.NetworkItem; zIndex?: number }>();
221
170
 
222
171
  const emit = defineEmits<{ (e: 'close'): void }>();
@@ -231,25 +180,18 @@ const requestMethods = [
231
180
  { name: 'HEAD', value: 'HEAD' },
232
181
  ];
233
182
 
234
- const bodyTypes = [
235
- { name: 'none', value: 'none' },
236
- { name: 'form-data', value: 'form-data' },
237
- { name: 'x-www-form-urlencoded', value: 'x-www-form-urlencoded' },
238
- { name: 'Raw text', value: 'Raw text' },
239
- ];
240
-
241
183
  const hasUrl = ref(true);
242
184
 
243
185
  const state = reactive<{
244
186
  method: any;
245
- bodyType: any;
246
187
  url: string;
247
188
  bodyText: string;
189
+ timeout: number;
248
190
  }>({
249
191
  method: 'GET',
250
- bodyType: 'none',
251
- url: '192.168.0.1:8080/a?a=123',
192
+ url: 'http://192.168.0.1:8080/a?a=123',
252
193
  bodyText: '',
194
+ timeout: 60 * 1000,
253
195
  });
254
196
 
255
197
  const defaultHeader = [
@@ -274,34 +216,28 @@ const defaultHeader = [
274
216
  {
275
217
  id: 4,
276
218
  key: 'Content-Type',
277
- value: 'application/x-www-form-urlencoded',
219
+ value: 'application/json; charset=utf-8',
278
220
  checked: true,
279
221
  },
280
222
  ];
281
223
 
282
- const headerList = reactive([...defaultHeader]);
283
-
284
- const defaultQuery = [
285
- {
286
- id: 1,
287
- key: 'name',
288
- value: '',
289
- checked: false,
290
- },
291
- ];
224
+ type PB = {
225
+ id: number;
226
+ key: string;
227
+ value: string;
228
+ checked: boolean;
229
+ };
292
230
 
293
- const queryList = reactive([...defaultQuery]);
231
+ const headerList = reactive([...defaultHeader]);
294
232
 
295
- const defaultBody = [
233
+ const queryList = reactive<PB[]>([
296
234
  {
297
235
  id: 1,
298
- key: 'name',
299
- value: '',
300
- checked: false,
236
+ key: 'a',
237
+ value: '123',
238
+ checked: true,
301
239
  },
302
- ];
303
-
304
- const bodyList = reactive([...defaultBody]);
240
+ ]);
305
241
 
306
242
  const isFinished = ref(false);
307
243
 
@@ -325,6 +261,41 @@ const network = reactive<DevTool.NetworkItem>({
325
261
  payload: undefined,
326
262
  });
327
263
 
264
+ const noBodyRequestMethods = ['GET', 'HEAD', 'PATCH', 'OPTIONS'];
265
+
266
+ function onChangeState(e: any, key: keyof typeof state) {
267
+ state[key] = e.detail.value as never;
268
+ }
269
+
270
+ function parseUrlToList(url: string) {
271
+ if (url.includes('?')) {
272
+ const query = url.split('?')[1];
273
+ const queryObject = urlParamsToObject(query);
274
+ const list = objectToArray(queryObject);
275
+
276
+ return list;
277
+ }
278
+ return [];
279
+ }
280
+
281
+ function parseListToUrl(list: PB[]) {
282
+ const baseUrl = state.url.split('?')[0] || '';
283
+ if (list.length === 0) {
284
+ return baseUrl;
285
+ } else {
286
+ return (
287
+ baseUrl + '?' + arrayToUrlParams(queryList?.filter((q) => q.checked))
288
+ );
289
+ }
290
+ }
291
+
292
+ function onChangeUrl(e: any) {
293
+ const url = e.detail.value;
294
+ state.url = url;
295
+ const list = parseUrlToList(url);
296
+ queryList.splice(0, queryList.length, ...list);
297
+ }
298
+
328
299
  function onDetail() {
329
300
  showDetail.value = true;
330
301
  }
@@ -337,12 +308,10 @@ function onReset() {
337
308
  isFinished.value = false;
338
309
  hasUrl.value = true;
339
310
  state.method = 'GET';
340
- state.bodyType = 'none';
341
311
  state.url = '';
342
312
  state.bodyText = '';
343
313
  headerList.splice(0, headerList.length, ...defaultHeader);
344
- queryList.splice(0, queryList.length, ...defaultQuery);
345
- bodyList.splice(0, bodyList.length);
314
+ queryList.splice(0, queryList.length);
346
315
  }
347
316
 
348
317
  function onClose() {
@@ -362,51 +331,43 @@ function onSend() {
362
331
  hasUrl.value = true;
363
332
 
364
333
  const header = arrayToObject(headerList);
365
- const query = arrayToObject(queryList);
366
-
367
- const body = arrayToObject(bodyList);
368
- const formData = new FormData();
334
+ const query = arrayToUrlParams(queryList);
369
335
 
370
336
  const requestOptions: UniNamespace.RequestOptions = {
371
337
  url: state.url,
372
338
  method: state.method,
373
- timeout: 60 * 1000,
339
+ timeout: state.timeout,
374
340
  header,
375
341
  };
376
342
 
377
- console.log('state: ', state);
343
+ if (noBodyRequestMethods.includes(state.method)) {
344
+ // 不支持携带 body 参数
345
+ requestOptions.data = {};
346
+ state.url = parseListToUrl(queryList);
347
+ } else {
348
+ // 支持 url 中携带参数
378
349
 
379
- if (state.bodyType === 'form-data') {
380
- for (const key in body) {
381
- formData.append(key, body[key]);
350
+ if (state.url.includes('?')) {
351
+ requestOptions.url = state.url + '&' + query;
352
+ } else {
353
+ requestOptions.url = state.url + '?' + query;
382
354
  }
383
- requestOptions.data = formData;
384
- } else if (state.bodyType === 'x-www-form-urlencoded') {
385
- const urlencoded = objectToUrlParams(body);
386
- requestOptions.data = urlencoded;
387
- } else if (state.bodyType === 'Raw text') {
388
- try {
389
- const bodyJson = JSON.parse(state.bodyText);
390
- requestOptions.data = bodyJson;
391
- } catch (error) {
392
- uni.showToast({
393
- title: '请求体请输入正确的JSON格式',
394
- icon: 'none',
395
- });
396
- return;
355
+
356
+ // 支持携带 body 参数
357
+ if (state.bodyText?.trim()) {
358
+ try {
359
+ const bodyJson = JSON.parse(state.bodyText);
360
+ requestOptions.data = bodyJson;
361
+ } catch (error) {
362
+ uni.showToast({
363
+ title: '请求体请输入正确的JSON格式',
364
+ icon: 'none',
365
+ });
366
+ return;
367
+ }
397
368
  }
398
- } else {
399
- console.log('------------state: ', state);
400
- const urlQuery = urlParamsToObject(state.url.split('?')?.[1] ?? '');
401
- console.log('urlQuery: ', urlQuery);
402
- requestOptions.data = {
403
- ...query,
404
- ...urlQuery,
405
- };
406
369
  }
407
370
 
408
- console.log('requestOptions: ', requestOptions);
409
-
410
371
  isFinished.value = false;
411
372
 
412
373
  uni.showLoading({
@@ -465,56 +426,6 @@ function onSend() {
465
426
  function onChangeRequestMethod(e: any) {
466
427
  const method = e.detail.value;
467
428
  state.method = method;
468
-
469
- if (method === 'POST' || method === 'PUT') {
470
- bodyList.splice(0, bodyList.length);
471
- state.bodyType = 'none';
472
- }
473
- }
474
-
475
- function onChangeBodyType(e: any) {
476
- const bodyType = e.detail.value;
477
- state.bodyType = bodyType;
478
- const ctIndex = headerList.findIndex((h) =>
479
- ['Content-Type', 'Content-type', 'content-Type', 'content-type'].includes(
480
- h.key,
481
- ),
482
- );
483
-
484
- if (bodyType === 'form-data' || bodyType === 'x-www-form-urlencoded') {
485
- if (ctIndex === -1) {
486
- headerList.push({
487
- id: Date.now(),
488
- key: 'Content-Type',
489
- value: 'application/x-www-form-urlencoded',
490
- checked: true,
491
- });
492
- } else {
493
- headerList[ctIndex].checked = true;
494
- headerList[ctIndex].value = 'application/x-www-form-urlencoded';
495
- }
496
- } else {
497
- bodyList.splice(0, bodyList.length);
498
-
499
- if (ctIndex === -1) {
500
- headerList.push({
501
- id: Date.now(),
502
- key: 'Content-Type',
503
- value: 'application/json;charset:utf-8;',
504
- checked: true,
505
- });
506
- } else {
507
- headerList[ctIndex].checked = true;
508
- headerList[ctIndex].value = 'application/json;charset:utf-8;';
509
- }
510
- }
511
- }
512
-
513
- function onChangeBodyChecked(e: any) {
514
- const list = e.detail?.value ?? [];
515
- bodyList.forEach((h) => {
516
- list?.includes(h.id) ? (h.checked = true) : (h.checked = false);
517
- });
518
429
  }
519
430
 
520
431
  function onDeleteHeader(item: any) {
@@ -532,6 +443,17 @@ function onAddHeader() {
532
443
  });
533
444
  }
534
445
 
446
+ function onChangeHeaderChecked(e: any) {
447
+ const list = e.detail?.value ?? [];
448
+ headerList.forEach((q) => {
449
+ q.checked = list?.includes(q.id);
450
+ });
451
+ }
452
+
453
+ function onChangeHeader(e: any, key: 'key' | 'value', index: number) {
454
+ headerList[index][key] = e.detail.value;
455
+ }
456
+
535
457
  function onDeleteQuery(item: any) {
536
458
  const index = queryList.findIndex((i) => i.id === item.id);
537
459
  queryList.splice(index, 1);
@@ -548,23 +470,16 @@ function onAddQuery() {
548
470
  function onChangeQueryChecked(e: any) {
549
471
  const list = e.detail?.value ?? [];
550
472
  queryList.forEach((q) => {
551
- list?.includes(q.id) ? (q.checked = true) : (q.checked = false);
473
+ q.checked = list?.includes(q.id);
552
474
  });
553
- }
554
475
 
555
- function onDeleteBody(item: any) {
556
- const index = bodyList.findIndex((i) => i.id === item.id);
557
- bodyList.splice(index, 1);
476
+ state.url = parseListToUrl(queryList);
558
477
  }
559
478
 
560
- function onAddBody() {
561
- const id = Date.now();
562
- bodyList.push({
563
- id,
564
- key: '',
565
- value: '',
566
- checked: false,
567
- });
479
+ function onChangeQuery(e: any, key: 'key' | 'value', index: number) {
480
+ queryList[index][key] = e.detail.value;
481
+
482
+ state.url = parseListToUrl(queryList);
568
483
  }
569
484
 
570
485
  function arrayToObject(arr: any[]) {
@@ -591,14 +506,25 @@ function objectToUrlParams(obj: any) {
591
506
  .join('&');
592
507
  }
593
508
 
594
- function formDataToObject(data: Record<string, any>) {
595
- const obj: Record<string, any> = {};
596
- for (const key in data) {
597
- if (data.hasOwnProperty(key)) {
598
- obj[key] = data[key];
509
+ function arrayToUrlParams(arr: any[]) {
510
+ return arr
511
+ .map((item) => `${item.key}=${encodeURIComponent(item.value)}`)
512
+ ?.join('&');
513
+ }
514
+
515
+ function unionArrayByKey<T>(arr1: T[], arr2: T[], key: keyof T): T[] {
516
+ const map = new Map();
517
+ arr1.forEach((item) => {
518
+ map.set(item?.[key], item);
519
+ });
520
+ arr2.forEach((item) => {
521
+ if (map.has(item?.[key])) {
522
+ map.set(item?.[key], { ...map.get(item?.[key]), ...item });
523
+ } else {
524
+ map.set(item?.[key], item);
599
525
  }
600
- }
601
- return obj;
526
+ });
527
+ return Array.from(map.values());
602
528
  }
603
529
 
604
530
  function urlParamsToObject(urlParams: string) {
@@ -635,74 +561,30 @@ function handleResendNetwork() {
635
561
 
636
562
  headerList.splice(0, headerList.length, ...requestHeaders);
637
563
 
638
- // 查找 Content-Type 头部
639
- const contentType = requestHeaders.find((h) =>
640
- ['Content-Type', 'content-type', 'Content-type', 'content-Type'].includes(
641
- h.key,
642
- ),
643
- )?.value;
644
-
645
564
  queryList.splice(0, queryList.length);
646
565
 
647
- // 参数在 query 中
648
- if (props.network.url.includes('?')) {
649
- queryList.splice(
650
- 0,
651
- queryList.length,
652
- ...objectToArray(
566
+ // 解析参数
567
+ if (noBodyRequestMethods.includes(state.method)) {
568
+ // 参数在 query 中
569
+ if (props.network.url.includes('?')) {
570
+ const urlParams = objectToArray(
653
571
  urlParamsToObject(props.network.url.split('?')?.[1] ?? ''),
654
- ),
655
- );
656
- }
657
-
658
- // 根据 Content-Type 设置请求体类型和内容
659
- if (contentType?.includes('application/json')) {
660
- if (state.method === 'GET' || state.method === 'DELETE') {
661
- state.bodyType = 'none';
662
-
663
- // 参数在 payload 中
664
- if (props.network.payload) {
665
- queryList.splice(
666
- queryList.length,
667
- 0,
668
- ...objectToArray(urlParamsToObject(props.network.payload)),
669
- );
670
- }
671
- } else {
672
- state.bodyType = 'Raw text';
673
- try {
674
- state.bodyText = isString(props.network.payload)
675
- ? props.network.payload
676
- : JSON.stringify(props.network.payload);
677
- } catch (error) {
678
- console.error('Failed to parse payload as JSON:', error);
572
+ );
573
+ const payloadParams = objectToArray(props.network.payload);
679
574
 
680
- state.bodyText = '请求体非JSON格式';
575
+ const list = unionArrayByKey(urlParams, payloadParams, 'key');
681
576
 
682
- uni.showToast({
683
- title: '请求体JSON格式错误',
684
- icon: 'none',
685
- });
686
- }
687
- }
688
- } else if (contentType?.includes('application/x-www-form-urlencoded')) {
689
- if (isString(props.network.payload)) {
690
- state.bodyType = 'x-www-form-urlencoded';
691
- const payloadObject = urlParamsToObject(props.network.payload);
692
- bodyList.splice(0, bodyList.length, ...objectToArray(payloadObject));
693
- } else {
694
- state.bodyType = 'form-data';
695
- // 对于非字符串负载,尝试转换为对象形式
696
- const payloadObject = props.network.payload
697
- ? isObject(props.network.payload)
698
- ? props.network.payload
699
- : formDataToObject(props.network.payload)
700
- : {};
701
- bodyList.splice(0, bodyList.length, ...objectToArray(payloadObject));
577
+ queryList.splice(0, queryList.length, ...list);
702
578
  }
703
579
  } else {
704
- // 默认为无请求体 无法解析请求体
705
- state.bodyType = 'none';
580
+ // 参数在 query 中
581
+ if (props.network.url.includes('?')) {
582
+ const urlParams = objectToArray(
583
+ urlParamsToObject(props.network.url.split('?')?.[1] ?? ''),
584
+ );
585
+ queryList.splice(0, queryList.length, ...urlParams);
586
+ }
587
+ state.bodyText = JSON.stringify(props.network.payload);
706
588
  }
707
589
  }
708
590
 
@@ -759,7 +641,7 @@ onMounted(() => {
759
641
  font-size: 12px;
760
642
  border: 1px solid var(--dev-tool-border-color);
761
643
  }
762
- .network-body-textarea {
644
+ .network-textarea {
763
645
  padding: 6px;
764
646
  width: 100%;
765
647
  box-sizing: border-box;
@@ -89,7 +89,7 @@ const emit = defineEmits<{
89
89
  (e: 'choose', type: string): void;
90
90
  (e: 'update:modelValue', value: string): void;
91
91
  (e: 'search', value: string): void;
92
- (e: 'sort', sort: -1 | 0 | 1): void;
92
+ (e: 'sort', sort: -1 | 1): void;
93
93
  (e: 'openCode', value?: string): void;
94
94
  }>();
95
95
  const networkFilterItems = [
@@ -1,10 +1,11 @@
1
1
  <template>
2
2
  <view class="pinia-content">
3
3
  <JsonPretty
4
- :data="piniaList"
5
- showLength
6
4
  editable
5
+ showLength
7
6
  v-if="showJson"
7
+ :data="piniaList"
8
+ :theme="theme"
8
9
  @update:data="onUpdateData"
9
10
  @nodeClick="onNodeClick"
10
11
  />
@@ -17,9 +18,9 @@ import JsonPretty from '../JsonPretty/index.vue';
17
18
  import Empty from '../Empty/index.vue';
18
19
  import { getValueByPath } from '../../utils';
19
20
 
20
-
21
21
  const props = defineProps<{
22
22
  piniaList: Record<string, any>;
23
+ theme?: string;
23
24
  }>();
24
25
  const emit = defineEmits<{
25
26
  (e: 'update:piniaList', data: Record<string, any>): void;
@@ -46,7 +47,7 @@ function onUpdateData(data: Record<string, any>) {
46
47
 
47
48
  emit('update:piniaList', data);
48
49
  emit('diffValue', {
49
- [keys]: newData
50
+ [keys]: newData,
50
51
  });
51
52
  } catch (error) {
52
53
  console.log('error: ', error);
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <view class="setting-content">
3
3
  <view class="setting-item">
4
- <DevToolTitle>DevTool(v0.0.16-vue3)</DevToolTitle>
4
+ <DevToolTitle>DevTool(v0.0.19-vue3)</DevToolTitle>
5
5
  <view class="setting-item-content">
6
6
  <view class="setting-row">
7
7
  <view>显示调试按钮:</view>
@@ -65,9 +65,9 @@
65
65
  <view
66
66
  class="setting-item-theme setting-theme-dark"
67
67
  :class="{
68
- 'setting-theme-active': theme === 'dart',
68
+ 'setting-theme-active': theme === 'dark',
69
69
  }"
70
- @click="emit('changeTheme', 'dart')"
70
+ @click="emit('changeTheme', 'dark')"
71
71
  ></view>
72
72
  </view>
73
73
  </view>
@@ -38,6 +38,7 @@
38
38
  }"
39
39
  showLength
40
40
  editable
41
+ :theme="theme"
41
42
  @update:data="onUpdateData($event, item)"
42
43
  />
43
44
  </view>
@@ -55,6 +56,7 @@ import type { DevTool } from '../../type';
55
56
  const props = defineProps<{
56
57
  storageList: DevTool.StorageItem[];
57
58
  modelValue: string;
59
+ theme?: string;
58
60
  }>();
59
61
 
60
62
  const emit = defineEmits<{
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <view class="system-content">
3
- <JsonPretty :data="systemInfo" showLength v-if="showJson" />
3
+ <JsonPretty showLength :theme="theme" :data="systemInfo" v-if="showJson" />
4
4
  <Empty v-else />
5
5
  </view>
6
6
  </template>
@@ -10,6 +10,7 @@ import JsonPretty from '../JsonPretty/index.vue';
10
10
  import Empty from '../Empty/index.vue';
11
11
  const props = defineProps<{
12
12
  systemInfo: Record<string, any>;
13
+ theme?: string;
13
14
  }>();
14
15
  const showJson = computed(() => {
15
16
  try {
@@ -76,7 +76,7 @@ const state = reactive<{
76
76
  scrollTop: number;
77
77
  }>({
78
78
  height: 0,
79
- current: 1,
79
+ current: 0,
80
80
  visitableData: [],
81
81
  currentHeight: 0,
82
82
  scrollTop: 0,
@@ -118,51 +118,20 @@ watch(
118
118
  );
119
119
 
120
120
  /** 向上滚动和向下滚动 */
121
- function updateVisitableData(direction: 'up' | 'down') {
122
- let tempList = [...state.visitableData];
121
+ function updateVisitableData() {
122
+ const { pageSize, data } = props;
123
+ const { current } = state;
123
124
 
124
- if (direction === 'down') {
125
- // 将最前面的内容进行隐藏
126
- tempList.splice(0, props.pageSize);
125
+ // 计算新的起始和结束索引
127
126
 
128
- // 处理下一页内容
129
- const start = props.pageSize * state.current;
130
- let end = props.pageSize * (state.current + 1);
127
+ const currentSub1 = current - 1 < 0 ? 0 : current - 1;
128
+ const currentAdd1 = current + 1;
131
129
 
132
- if (start >= props.data.length) {
133
- return;
134
- }
130
+ const startIndex = currentSub1 * pageSize;
131
+ const endIndex = Math.min(currentAdd1 * pageSize, data.length);
135
132
 
136
- if (end > props.data.length) {
137
- end = props.data.length;
138
- }
139
-
140
- const newData = props.data.slice(start, end);
141
-
142
- tempList.push(...newData);
143
- } else {
144
- // 将最末尾的部分进行隐藏
145
- const delCount =
146
- tempList.length - props.pageSize > 0
147
- ? props.pageSize
148
- : tempList.length - props.pageSize;
149
-
150
- tempList.splice(props.pageSize, delCount);
151
-
152
- // 处理上一页内容
153
- let start = props.pageSize * (state.current - 1);
154
-
155
- const end = props.pageSize * state.current;
156
-
157
- if (end < 0) return;
158
-
159
- if (start < 0) {
160
- start = 0;
161
- }
162
- const newData = props.data.slice(start, end);
163
- tempList.unshift(...newData);
164
- }
165
- state.visitableData = tempList;
133
+ // 更新可见数据
134
+ state.visitableData = data.slice(startIndex, endIndex);
166
135
  }
167
136
 
168
137
  /** 计算合并的高度 */
@@ -179,7 +148,7 @@ function onScrollToLower() {
179
148
  if ((state.current + 1) * props.pageSize < props.data.length) {
180
149
  state.current++;
181
150
 
182
- updateVisitableData('down');
151
+ updateVisitableData();
183
152
 
184
153
  updateCurrentHeight();
185
154
  }
@@ -194,7 +163,7 @@ function onScroll(e: { detail: { scrollTop: number } }) {
194
163
  ) {
195
164
  state.current--;
196
165
 
197
- updateVisitableData('up');
166
+ updateVisitableData();
198
167
 
199
168
  updateCurrentHeight();
200
169
  }
@@ -213,7 +182,7 @@ function onBackTop() {
213
182
  nextTick(() => {
214
183
  state.current = 1;
215
184
  state.currentHeight = 0;
216
- updateVisitableData('up');
185
+ updateVisitableData();
217
186
 
218
187
  toView.value = '';
219
188
  });
@@ -1,10 +1,11 @@
1
1
  <template>
2
2
  <view class="vuex-content">
3
3
  <JsonPretty
4
- :data="vuexList"
5
- showLength
6
4
  editable
5
+ showLength
7
6
  v-if="showJson"
7
+ :data="vuexList"
8
+ :theme="theme"
8
9
  @update:data="onUpdateData"
9
10
  @nodeClick="onNodeClick"
10
11
  />
@@ -17,6 +18,7 @@ import JsonPretty from '../JsonPretty/index.vue';
17
18
  import Empty from '../Empty/index.vue';
18
19
  const props = defineProps<{
19
20
  vuexList: Record<string, any>;
21
+ theme?: string;
20
22
  }>();
21
23
  const emit = defineEmits<{
22
24
  (e: 'update:vuexList', data: Record<string, any>): void;
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <view class="window-info-content">
3
- <JsonPretty v-if="showJson" :data="windowInfo" />
3
+ <JsonPretty v-if="showJson" :data="windowInfo" :theme="theme" />
4
4
  <Empty v-else />
5
5
  </view>
6
6
  </template>
@@ -11,6 +11,7 @@ import JsonPretty from '../JsonPretty/index.vue';
11
11
  import Empty from '../Empty/index.vue';
12
12
  const props = defineProps<{
13
13
  windowInfo: Record<string, any>;
14
+ theme?: string;
14
15
  }>();
15
16
 
16
17
  const showJson = computed(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-uni-dev-tool",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "description": "vite-uni-dev-tool, debug, uni-app, 一处编写,到处调试",
5
5
  "keywords": [
6
6
  "vite",