Browse Source

更新打包

lex 1 year ago
parent
commit
1b3007d195

File diff suppressed because it is too large
+ 0 - 0
dist/assets/polyfills-legacy.c60f005e.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/teacher-legacy.eca69152.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/teacher.f2fc65eb.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/video-class-detail-legacy.066fa317.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/video-class-detail-legacy.206abf49.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/video-class-detail.7198ccc5.js


File diff suppressed because it is too large
+ 0 - 0
dist/assets/video-class-detail.b058a031.js


+ 1 - 1
dist/index.html

@@ -51,7 +51,7 @@
   
   <!-- <script type="module" src="/src/teacher/main.ts"></script> -->
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
-  <script nomodule id="vite-legacy-polyfill" src="./assets/polyfills-legacy.a8efd1b2.js"></script>
+  <script nomodule id="vite-legacy-polyfill" src="./assets/polyfills-legacy.c60f005e.js"></script>
   <script nomodule id="vite-legacy-entry" data-src="./assets/index-legacy.48fa787d.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 

+ 3 - 3
dist/teacher.html

@@ -36,7 +36,7 @@
   <meta name="msapplication-tap-highlight" content="no" />
   <title>酷乐秀</title>
   <script src="./flexible.js" charset="UTF-8"></script>
-  <script type="module" crossorigin src="./assets/teacher.4e6c7765.js"></script>
+  <script type="module" crossorigin src="./assets/teacher.f2fc65eb.js"></script>
   <link rel="modulepreload" href="./assets/index.b4531198.js">
   <link rel="modulepreload" href="./assets/routes-common.da70ca0a.js">
   <link rel="stylesheet" href="./assets/index.90dd4d0d.css">
@@ -48,8 +48,8 @@
   <div id="app"></div>
   
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
-  <script nomodule id="vite-legacy-polyfill" src="./assets/polyfills-legacy.a8efd1b2.js"></script>
-  <script nomodule id="vite-legacy-entry" data-src="./assets/teacher-legacy.d4da4474.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
+  <script nomodule id="vite-legacy-polyfill" src="./assets/polyfills-legacy.c60f005e.js"></script>
+  <script nomodule id="vite-legacy-entry" data-src="./assets/teacher-legacy.eca69152.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 
 </html>

+ 1 - 1
dist/tenant.html

@@ -50,7 +50,7 @@
   
   <!-- <script type="module" src="/src/teacher/main.ts"></script> -->
   <script nomodule>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
-  <script nomodule id="vite-legacy-polyfill" src="./assets/polyfills-legacy.a8efd1b2.js"></script>
+  <script nomodule id="vite-legacy-polyfill" src="./assets/polyfills-legacy.c60f005e.js"></script>
   <script nomodule id="vite-legacy-entry" data-src="./assets/tenant-legacy.102d87f3.js">System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))</script>
 </body>
 

+ 373 - 372
src/teacher/video-class/video-class-detail.tsx

@@ -1,372 +1,373 @@
-import CourseVideoItem from '@/business-components/course-video-item'
-import SectionDetail from '@/business-components/section-detail'
-import ColHeader from '@/components/col-header'
-import ColVideo from '@/components/col-video'
-import request from '@/helpers/request'
-import {
-  Cell,
-  Icon,
-  Rate,
-  Tab,
-  Tabs,
-  Image,
-  Button,
-  Sticky,
-  Field,
-  List,
-  Toast
-} from 'vant'
-import { defineComponent } from 'vue'
-import styles from './video-class-detail.module.less'
-import { state } from '@/state'
-
-import iconStudent from '@common/images/icon_student.png'
-import dayjs from 'dayjs'
-import ColResult from '@/components/col-result'
-
-export default defineComponent({
-  name: 'VideoClassDetail',
-  data() {
-    const query = this.$route.query
-    return {
-      groupId: query.groupId,
-      classId: query.classId,
-      tabIndex: 1,
-      title: '',
-      lessonPrice: 0,
-      useRelationType: '',
-      alreadyBuy: false,
-      currentClassIndex: 1,
-      detailList: [],
-      posterUrl: '',
-      srcUrl: '',
-      message: '',
-      navHeight: 0 as any,
-      reload: false,
-      videoContent: '',
-      list: [],
-      dataShow: true, // 判断是否有数据
-      loading: false,
-      finished: false,
-      params: {
-        page: 1,
-        rows: 20
-      },
-      freeRate: 0, // 试看百分比
-      trySee: false, // 是否试看
-      videoHeight: '212px'
-    }
-  },
-  computed: {
-    users() {
-      return state.user.data
-    },
-    offsetTop() {
-      const navHeight: number = this.navHeight
-      const top = Number(navHeight) + 44
-      return top + 'px'
-    }
-  },
-  async mounted() {
-    this.navHeight = sessionStorage.getItem('navHeight') || 0
-    try {
-      const res = await request.get(
-        '/api-teacher/videoLessonGroup/selectVideoLesson',
-        {
-          params: {
-            groupId: this.groupId
-          }
-        }
-      )
-      const result = res.data || {}
-      this.title = result.lessonGroup.lessonName
-      this.useRelationType = result.lessonGroup.relationType
-      this.lessonPrice = result.lessonGroup.lessonPrice
-      this.alreadyBuy = result.alreadyBuy
-      this.detailList = result.detailList || []
-
-      if (state.user.data?.userId !== result.lessonGroup.teacherId) {
-        this.trySee = !result.alreadyBuy
-      }
-
-      this.detailList.forEach((item: any, index: number) => {
-        if (item.id === Number(this.classId)) {
-          this.posterUrl = item.coverUrl
-          this.srcUrl = item.videoUrl
-          this.title = item.videoTitle
-          this.currentClassIndex = index + 1
-          this.videoContent = item.videoContent
-        }
-      })
-
-      const config = await request.get(
-        '/api-student/sysConfig/queryByParamNameList',
-        {
-          params: {
-            paramNames: 'video_lesson_free_rate'
-          }
-        }
-      )
-      this.freeRate = config.data[0]?.paramValue || 0
-
-      this.getList()
-    } catch {}
-  },
-  methods: {
-    onSearch() {
-      this.params.page = 1
-      this.list = []
-      this.dataShow = true // 判断是否有数据
-      this.loading = false
-      this.finished = false
-      this.getList()
-    },
-    async getList() {
-      try {
-        const params = this.params
-        const res = await request.post('/api-student/videoLesson/page', {
-          data: {
-            ...params,
-            videoId: this.classId
-          }
-        })
-        this.loading = false
-        const result = res.data || {}
-        console.log(result)
-        // 处理重复请求数据
-        if (this.list.length > 0 && result.pageNo === 1) {
-          return
-        }
-        this.list = this.list.concat(result.rows || [])
-        this.finished = result.pageNo >= result.totalPage
-        this.params.page = result.pageNo + 1
-        this.dataShow = this.list.length > 0
-      } catch {
-        this.dataShow = false
-        this.finished = true
-      }
-    },
-    onPlay(item: any) {
-      // 判断是否点击的是当前播放的视频
-      if (item.id === Number(this.classId)) {
-        return
-      }
-      this.reload = true
-      this.posterUrl = item.imgUrl
-      this.srcUrl = item.videoUrl
-      this.title = item.title
-      this.currentClassIndex = item.index
-      this.videoContent = item.content
-      this.classId = item.id
-      this.onSearch()
-      setTimeout(() => {
-        this.reload = false
-      }, 0)
-    },
-    async onSubmit() {
-      try {
-        await request.post('/api-teacher/videoLesson/evaluate', {
-          data: {
-            isTeacher: 1,
-            videoId: this.classId,
-            content: this.message,
-            studentId: state.user.data.userId
-          }
-        })
-        Toast('评论成功')
-        this.message = ''
-        setTimeout(() => {
-          this.onSearch()
-        }, 1000)
-      } catch {}
-    }
-  },
-  render() {
-    return (
-      <div class={styles['video-class-detail']}>
-        {/* <ColHeader
-          v-slots={{
-            default: () => (
-              <ColVideo
-                src={this.srcUrl}
-                poster={this.posterUrl}
-                freeRate={Number(this.freeRate)}
-                trySee={this.trySee}
-                height={this.videoHeight}
-              />
-            )
-          }}
-        /> */}
-        <ColVideo
-          src={this.srcUrl}
-          poster={this.posterUrl}
-          freeTitleStatus={this.lessonPrice > 0 ? true : false}
-          freeRate={Number(this.freeRate)}
-          trySee={this.trySee}
-          height={this.videoHeight}
-        />
-        <Cell
-          border={false}
-          class={styles.cell}
-          title={this.title}
-          titleClass={styles.titleInfo}
-          v-slots={{
-            icon: () => (
-              <Icon
-                name="video"
-                size={18}
-                color="var(--van-primary)"
-                style={{ display: 'flex', alignItems: 'center' }}
-              />
-            ),
-            value: () => (
-              <div class={styles.label}>
-                <span>{this.currentClassIndex}</span>/{this.detailList.length}
-                课时
-              </div>
-            )
-          }}
-        ></Cell>
-        <div class={styles.videoDesc}>{this.videoContent}</div>
-
-        <Tabs
-          v-model:active={this.tabIndex}
-          class={styles.infoField}
-          color="var(--van-primary)"
-          lineWidth={20}
-          sticky
-          lazyRender
-          offsetTop={this.offsetTop}
-        >
-          <Tab title="目录" name={1}>
-            <div style={{ height: 'calc(100vh - 320px)', overflowY: 'auto' }}>
-              <SectionDetail title="课程列表" icon="courseList">
-                {this.detailList.map((item: any, index: number) => {
-                  const musicAlbumInfos = item.musicAlbumInfos || []
-                  const temp = musicAlbumInfos.map((info: any) => {
-                    return {
-                      relationMusicAlbum: info.relationType,
-                      musicAlbumName: info.name,
-                      musicAlbumId: info.musicAlbumId,
-                      status: info.status,
-                      useRelationType: this.useRelationType
-                    }
-                  })
-                  return (
-                    <CourseVideoItem
-                      musicAlbumInfos={temp}
-                      playId={Number(this.classId)}
-                      detail={{
-                        id: item.id,
-                        title: item.videoTitle,
-                        content: item.videoContent,
-                        imgUrl: item.coverUrl,
-                        videoUrl: item.videoUrl,
-                        index: index + 1
-                      }}
-                      onPlay={this.onPlay}
-                      onMusicAlbumDetail={(item: any) => {
-                        if (!this.alreadyBuy && !item.status) {
-                          Toast('数据正在更新,请稍后再试')
-                          return
-                        }
-                        if (item.relationMusicAlbum === 'MUSIC') {
-                          this.$router.push({
-                            path: '/music-detail',
-                            query: {
-                              id: item.musicAlbumId
-                            }
-                          })
-                        } else if (item.relationMusicAlbum === 'ALBUM') {
-                          this.$router.push({
-                            path: '/music-album-detail/' + item.musicAlbumId
-                          })
-                        }
-                      }}
-                    />
-                  )
-                })}
-              </SectionDetail>
-            </div>
-          </Tab>
-          <Tab title="讨论" name={3}>
-            <div
-              style={{
-                overflowY: 'auto',
-                marginBottom:
-                  'calc(var(--van-cell-vertical-padding) * 2 + var( --van-cell-line-height))'
-              }}
-            >
-              {this.dataShow ? (
-                <List
-                  v-model:loading={this.loading}
-                  finished={this.finished}
-                  finishedText=" "
-                  immediateCheck={false}
-                  onLoad={this.getList}
-                >
-                  {this.list.map((item: any) => (
-                    <Cell
-                      class={[
-                        styles['message-list'],
-                        item.isTeacher === 1 && styles['message-active']
-                      ]}
-                      valueClass={styles['message-time']}
-                      v-slots={{
-                        icon: () => (
-                          <Image
-                            class={styles.userLogo}
-                            src={item.avatar || iconStudent}
-                            fit="cover"
-                          />
-                        ),
-                        title: () => (
-                          <div class={styles.title}>
-                            <div class={styles['message-name']}>
-                              {item.userName}
-                            </div>
-                            <div class={styles['message-time']}>
-                              {dayjs(item.evaluateTime).format(
-                                'YYYY年MM月DD日'
-                              )}
-                            </div>
-                          </div>
-                        ),
-                        label: () => (
-                          <div class={styles.label}>{item.content}</div>
-                        )
-                      }}
-                    />
-                  ))}
-                </List>
-              ) : (
-                <ColResult btnStatus={false} tips="暂无讨论" />
-              )}
-            </div>
-
-            <div class={[styles.messageContainer]}>
-              <Field
-                placeholder="快来讨论吧~"
-                v-model={this.message}
-                v-slots={{
-                  button: () => (
-                    <Button
-                      type="primary"
-                      disabled={!this.message}
-                      style={{ padding: '0 20px' }}
-                      size="small"
-                      round
-                      onClick={this.onSubmit}
-                    >
-                      发布
-                    </Button>
-                  )
-                }}
-              />
-            </div>
-          </Tab>
-        </Tabs>
-      </div>
-    )
-  }
-})
+import CourseVideoItem from '@/business-components/course-video-item'
+import SectionDetail from '@/business-components/section-detail'
+import ColHeader from '@/components/col-header'
+import ColVideo from '@/components/col-video'
+import request from '@/helpers/request'
+import {
+  Cell,
+  Icon,
+  Rate,
+  Tab,
+  Tabs,
+  Image,
+  Button,
+  Sticky,
+  Field,
+  List,
+  Toast
+} from 'vant'
+import { defineComponent } from 'vue'
+import styles from './video-class-detail.module.less'
+import { state } from '@/state'
+
+import iconStudent from '@common/images/icon_student.png'
+import dayjs from 'dayjs'
+import ColResult from '@/components/col-result'
+
+export default defineComponent({
+  name: 'VideoClassDetail',
+  data() {
+    const query = this.$route.query
+    return {
+      groupId: query.groupId,
+      classId: query.classId,
+      tabIndex: 1,
+      title: '',
+      lessonPrice: 0,
+      useRelationType: '',
+      alreadyBuy: false,
+      currentClassIndex: 1,
+      detailList: [],
+      posterUrl: '',
+      srcUrl: '',
+      message: '',
+      navHeight: 0 as any,
+      reload: false,
+      videoContent: '',
+      list: [],
+      dataShow: true, // 判断是否有数据
+      loading: false,
+      finished: false,
+      params: {
+        page: 1,
+        rows: 20
+      },
+      freeRate: 0, // 试看百分比
+      trySee: false, // 是否试看
+      videoHeight: '212px'
+    }
+  },
+  computed: {
+    users() {
+      return state.user.data
+    },
+    offsetTop() {
+      const navHeight: number = this.navHeight
+      const top = Number(navHeight) + 44
+      return top + 'px'
+    }
+  },
+  async mounted() {
+    this.navHeight = sessionStorage.getItem('navHeight') || 0
+    try {
+      const res = await request.get(
+        '/api-teacher/videoLessonGroup/selectVideoLesson',
+        {
+          params: {
+            groupId: this.groupId
+          }
+        }
+      )
+      const result = res.data || {}
+      this.title = result.lessonGroup.lessonName
+      this.useRelationType = result.lessonGroup.relationType
+      this.lessonPrice = result.lessonGroup.lessonPrice
+      this.alreadyBuy = result.alreadyBuy
+      this.detailList = result.detailList || []
+
+      if (state.user.data?.userId !== result.lessonGroup.teacherId) {
+        this.trySee = !result.alreadyBuy
+      }
+
+      this.detailList.forEach((item: any, index: number) => {
+        if (item.id === Number(this.classId)) {
+          this.posterUrl = item.coverUrl
+          this.srcUrl = item.videoUrl
+          this.title = item.videoTitle
+          this.currentClassIndex = index + 1
+          this.videoContent = item.videoContent
+        }
+      })
+
+      const config = await request.get(
+        '/api-student/sysConfig/queryByParamNameList',
+        {
+          params: {
+            paramNames: 'video_lesson_free_rate'
+          }
+        }
+      )
+      this.freeRate = config.data[0]?.paramValue || 0
+
+      this.getList()
+    } catch {}
+  },
+  methods: {
+    onSearch() {
+      this.params.page = 1
+      this.list = []
+      this.dataShow = true // 判断是否有数据
+      this.loading = false
+      this.finished = false
+      this.getList()
+    },
+    async getList() {
+      try {
+        const params = this.params
+        const res = await request.post('/api-student/videoLesson/page', {
+          data: {
+            ...params,
+            videoId: this.classId
+          }
+        })
+        this.loading = false
+        const result = res.data || {}
+        console.log(result)
+        // 处理重复请求数据
+        if (this.list.length > 0 && result.pageNo === 1) {
+          return
+        }
+        this.list = this.list.concat(result.rows || [])
+        this.finished = result.pageNo >= result.totalPage
+        this.params.page = result.pageNo + 1
+        this.dataShow = this.list.length > 0
+      } catch {
+        this.dataShow = false
+        this.finished = true
+      }
+    },
+    onPlay(item: any) {
+      // 判断是否点击的是当前播放的视频
+      if (item.id === Number(this.classId)) {
+        return
+      }
+      this.reload = true
+      this.posterUrl = item.imgUrl
+      this.srcUrl = item.videoUrl
+      this.title = item.title
+      this.currentClassIndex = item.index
+      this.videoContent = item.content
+      this.classId = item.id
+      this.onSearch()
+      setTimeout(() => {
+        this.reload = false
+      }, 0)
+    },
+    async onSubmit() {
+      try {
+        await request.post('/api-teacher/videoLesson/evaluate', {
+          data: {
+            isTeacher: 1,
+            videoId: this.classId,
+            content: this.message,
+            studentId: state.user.data.userId
+          }
+        })
+        Toast('评论成功')
+        this.message = ''
+        setTimeout(() => {
+          this.onSearch()
+        }, 1000)
+      } catch {}
+    }
+  },
+  render() {
+    return (
+      <div class={styles['video-class-detail']}>
+        {/* <ColHeader
+          v-slots={{
+            default: () => (
+              <ColVideo
+                src={this.srcUrl}
+                poster={this.posterUrl}
+                freeRate={Number(this.freeRate)}
+                trySee={this.trySee}
+                height={this.videoHeight}
+              />
+            )
+          }}
+        /> */}
+        <ColHeader />
+        <ColVideo
+          src={this.srcUrl}
+          poster={this.posterUrl}
+          freeTitleStatus={this.lessonPrice > 0 ? true : false}
+          freeRate={Number(this.freeRate)}
+          trySee={this.trySee}
+          height={this.videoHeight}
+        />
+        <Cell
+          border={false}
+          class={styles.cell}
+          title={this.title}
+          titleClass={styles.titleInfo}
+          v-slots={{
+            icon: () => (
+              <Icon
+                name="video"
+                size={18}
+                color="var(--van-primary)"
+                style={{ display: 'flex', alignItems: 'center' }}
+              />
+            ),
+            value: () => (
+              <div class={styles.label}>
+                <span>{this.currentClassIndex}</span>/{this.detailList.length}
+                课时
+              </div>
+            )
+          }}
+        ></Cell>
+        <div class={styles.videoDesc}>{this.videoContent}</div>
+
+        <Tabs
+          v-model:active={this.tabIndex}
+          class={styles.infoField}
+          color="var(--van-primary)"
+          lineWidth={20}
+          sticky
+          lazyRender
+          offsetTop={this.offsetTop}
+        >
+          <Tab title="目录" name={1}>
+            <div style={{ height: 'calc(100vh - 320px)', overflowY: 'auto' }}>
+              <SectionDetail title="课程列表" icon="courseList">
+                {this.detailList.map((item: any, index: number) => {
+                  const musicAlbumInfos = item.musicAlbumInfos || []
+                  const temp = musicAlbumInfos.map((info: any) => {
+                    return {
+                      relationMusicAlbum: info.relationType,
+                      musicAlbumName: info.name,
+                      musicAlbumId: info.musicAlbumId,
+                      status: info.status,
+                      useRelationType: this.useRelationType
+                    }
+                  })
+                  return (
+                    <CourseVideoItem
+                      musicAlbumInfos={temp}
+                      playId={Number(this.classId)}
+                      detail={{
+                        id: item.id,
+                        title: item.videoTitle,
+                        content: item.videoContent,
+                        imgUrl: item.coverUrl,
+                        videoUrl: item.videoUrl,
+                        index: index + 1
+                      }}
+                      onPlay={this.onPlay}
+                      onMusicAlbumDetail={(item: any) => {
+                        if (!this.alreadyBuy && !item.status) {
+                          Toast('数据正在更新,请稍后再试')
+                          return
+                        }
+                        if (item.relationMusicAlbum === 'MUSIC') {
+                          this.$router.push({
+                            path: '/music-detail',
+                            query: {
+                              id: item.musicAlbumId
+                            }
+                          })
+                        } else if (item.relationMusicAlbum === 'ALBUM') {
+                          this.$router.push({
+                            path: '/music-album-detail/' + item.musicAlbumId
+                          })
+                        }
+                      }}
+                    />
+                  )
+                })}
+              </SectionDetail>
+            </div>
+          </Tab>
+          <Tab title="讨论" name={3}>
+            <div
+              style={{
+                overflowY: 'auto',
+                marginBottom:
+                  'calc(var(--van-cell-vertical-padding) * 2 + var( --van-cell-line-height))'
+              }}
+            >
+              {this.dataShow ? (
+                <List
+                  v-model:loading={this.loading}
+                  finished={this.finished}
+                  finishedText=" "
+                  immediateCheck={false}
+                  onLoad={this.getList}
+                >
+                  {this.list.map((item: any) => (
+                    <Cell
+                      class={[
+                        styles['message-list'],
+                        item.isTeacher === 1 && styles['message-active']
+                      ]}
+                      valueClass={styles['message-time']}
+                      v-slots={{
+                        icon: () => (
+                          <Image
+                            class={styles.userLogo}
+                            src={item.avatar || iconStudent}
+                            fit="cover"
+                          />
+                        ),
+                        title: () => (
+                          <div class={styles.title}>
+                            <div class={styles['message-name']}>
+                              {item.userName}
+                            </div>
+                            <div class={styles['message-time']}>
+                              {dayjs(item.evaluateTime).format(
+                                'YYYY年MM月DD日'
+                              )}
+                            </div>
+                          </div>
+                        ),
+                        label: () => (
+                          <div class={styles.label}>{item.content}</div>
+                        )
+                      }}
+                    />
+                  ))}
+                </List>
+              ) : (
+                <ColResult btnStatus={false} tips="暂无讨论" />
+              )}
+            </div>
+
+            <div class={[styles.messageContainer]}>
+              <Field
+                placeholder="快来讨论吧~"
+                v-model={this.message}
+                v-slots={{
+                  button: () => (
+                    <Button
+                      type="primary"
+                      disabled={!this.message}
+                      style={{ padding: '0 20px' }}
+                      size="small"
+                      round
+                      onClick={this.onSubmit}
+                    >
+                      发布
+                    </Button>
+                  )
+                }}
+              />
+            </div>
+          </Tab>
+        </Tabs>
+      </div>
+    )
+  }
+})

Some files were not shown because too many files changed in this diff